CORS No data

Delphi 11.1
Remobjects SDK 1533

I am changing my webservice so I can access it from a website.
This is al new to me…

Because I get no results in the browser I tried the RestDebugger.
When I execute a Get, https://consolit.nl:8099/api/ListCompanies
I get no data back

When I set SendCrossOrginHeader to False, I do get data

What am I missing here?

Hi,

try to play with OnSendCrossOriginHeaderEx event of IndyHTTPServer.
in this event you can specify some additional headers.

Note: it requires SendCrossOriginHeader = true

Hi,

Ok, I got some mixed results.

I have some Virtual machines to try different versions.

Delphi 10.4.1
Remobjects 1481

procedure TServerDataModule.ROServerSendCrossOriginHeader( var AllowedOrigin: string);
begin

AllowedOrigin:=’*’;

end;

Runs fine in my website. I got results!
No errors

Delphi 11
Remobjects 1521

Webbrowser gives cores error.

Has been blocked by CORS policy: No ‘Access-Control-Allow-Origin’ header is present on the requested resource.
with I confirmed with RestDebugger from Delphi, No “”Access-Control-Allow-Origin=*” in header.
But with data witch I can see in the RestDebugger.

Delphi 11.1
Remobjects 1533

Webbrowser gives NO cores error, but no data is returned.

I confirmed this with the RestDebugger.
Header correct, No bytes returned.

Hi,

Can you create a simple testcase that reproduces this issue, pls?
You can drop email to support@ for keeping privacy.

I send a Mail

Logged as bugs://D19242.

bugs://D19242 was closed as fixed.

Hi,

pls update uROBaseHTTPServer.pas as

procedure TROBaseHTTPServer.ProcessRequest(const aTransport: IROHTTPTransportEx;
..
  DoCORSSupport(aTransport, aResponse);  //<<<< "if" clause was removed

Hi,

There still something strange going on.

I will try to explain.
I am using TMS Webcore by the way.
When I use
WebRESTClient1.HttpsGet(BaseURL + ‘ListCompanies’);
Everything works as expected

When I use
WebHttpRequest1.URL:=BaseURL + ‘ListCompanies’;
WebHttpRequest1.Execute(
I get the CORS error.

Even more strange that after this error there is no longer
Access-Control-Allow-Origin in the header in any call.

I confirmed this with RestDebugger.
Recap
WebRESTClient1.HttpsGet(BaseURL + ‘ListCompanies’);
WebRESTClient1.HttpsGet(BaseURL + ‘ListCompanies’);
WebRESTClient1.HttpsGet(BaseURL + ‘ListCompanies’);
Works
WebHttpRequest1.Execute
CORS error
WebRESTClient1.HttpsGet(BaseURL + ‘ListCompanies’);
CORS error
RestDebugger
Access-Control-Allow-Origin is missing

By debugging the webservice I see that the method used by WebHttpRequest1 = OPTIONS

function TROCustomHTTPServer.DoCORSSupport(const aRequest: IInterface; const aResponse: IROHTTPResponse): Boolean;

aResponse.Headers[id_AccessControlAllowOrigin] := l_corsStruct.AllowedOrigin;
if SameText(l_Request.Method, id_Method_Options) then begin //l_Request.Method = “OPTIONS”
→ if l_Request.Headers[id_AccessControlRequestMethod] <> ‘’ then aResponse.Headers[id_AccessControlAllowMethods] := l_corsStruct.AllowedMethods;
if l_Request.Headers[id_AccessControlRequestHeaders] <> ‘’ then aResponse.Headers[id_AccessControlAllowHeaders] := l_corsStruct.AllowedHeaders; aResponse.Headers[id_AccessControlMaxAge] := IntToStr(l_corsStruct.MaxAge);
end;
Result := True;
end;
end;
finally
l_Request := nil;
end;
end;

when the other call WebHttpRequest1 is used the Method = “GET”

Hope this makes sense to you

Hi,

I can’t reproduce failure with OPTIONS:

C:\>curl -verbose -X OPTIONS "http://localhost:8099/api/ListCompanies"   -H "accept: application/json"
*   Trying ::1:8099...
*   Trying 127.0.0.1:8099...
* Connected to localhost (127.0.0.1) port 8099 (#0)
> OPTIONS /api/ListCompanies HTTP/1.1
> Host: localhost:8099
> User-Agent: curl/7.72.0
> Referer: rbose
> accept: application/json
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 501 Not Implemented
< Connection: close
< Content-Type: text/html; charset=ISO-8859-1
< Content-Length: 0
< Date: Fri, 25 Mar 2022 11:06:11 GMT
< Accept-Encoding: gzip, identity
< Access-Control-Allow-Origin: *
< Access-Control-Max-Age: 86400
<
* Closing connection 0

C:\>curl -verbose -X GET "http://localhost:8099/api/ListCompanies"   -H "accept: application/json"
Note: Unnecessary use of -X or --request, GET is already inferred.
*   Trying ::1:8099...
*   Trying 127.0.0.1:8099...
* Connected to localhost (127.0.0.1) port 8099 (#0)
> GET /api/ListCompanies HTTP/1.1
> Host: localhost:8099
> User-Agent: curl/7.72.0
> Referer: rbose
> accept: application/json
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Connection: close
< Content-Type: application/json; charset=utf-8
< Content-Length: 29
< Date: Fri, 25 Mar 2022 11:06:11 GMT
< Accept-Encoding: gzip, identity
< Access-Control-Allow-Origin: *
<
[{"naam":"Test","werkm":999}]* Closing connection 0

Note: I’ve used plain http:// because it has some issues with certificates

Hi,

I’ve updated code so ROD server will return 204 No content for OPTIONS requests

Hi,

I do not understand.
Where can I find this code?

I trying to find out what the exactly do.
This is what the send in de header when I do a get with basic authorization.
This call fails.

Host: consolit.nl:8099
Connection: keep-alive
Accept: /
Access-Control-Request-Method: GET
Access-Control-Request-Headers: authorization
Origin: http://localhost:8000
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.84 Safari/537.36
Sec-Fetch-Mode: cors
Sec-Fetch-Site: cross-site
Sec-Fetch-Dest: empty
Referer: http://localhost:8000/
Accept-Encoding: gzip, deflate, br
Accept-Language: nl-NL,nl;q=0.9,en-US;q=0.8,en;q=0.7

This is in the header with a basic get, no authorization
This call is succesfull.

Host: consolit.nl:8099
Connection: keep-alive
sec-ch-ua: " Not A;Brand";v=“99”, “Chromium”;v=“99”, “Google Chrome”;v=“99”
sec-ch-ua-mobile: ?0
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.84 Safari/537.36
sec-ch-ua-platform: “Windows”
Accept: /
Origin: http://localhost:8000
Sec-Fetch-Site: cross-site
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: http://localhost:8000/
Accept-Encoding: gzip, deflate, br
Accept-Language: nl-NL,nl;q=0.9,en-US;q=0.8,en;q=0.7

What can I do more?

Hi,

we are going to release a new version of Remoting SDK this week.

Have you enabled server.RequireHTTPAuthentication ?
You can check password with server.OnHTTPAuthentication event.
Also you can specify realm at server.HTTPAuthenticationRealm

Hi,

I do the same call https://consolit.nl:8099/api/ListCompanies
But now with, basic authorization.
Yes, I enabled 'RequireHTTPAuthentication"on the server.
Yes, I implemented OnHTTPAuthentication
I deed not specify a realm.

When the request is send from the client.

The server sents a 401 back.

This is the header of the client request.

Host: consolit.nl:8099
Connection: keep-alive
Accept: /
Access-Control-Request-Method: GET
Access-Control-Request-Headers: authorization
Origin: http://localhost:8000
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.84 Safari/537.36
Sec-Fetch-Mode: cors
Sec-Fetch-Site: cross-site
Sec-Fetch-Dest: empty
Referer: http://localhost:8000/
Accept-Encoding: gzip, deflate, br
Accept-Language: nl-NL,nl;q=0.9,en-US;q=0.8,en;q=0.7

The browser shows a CORS error.

Hi,

as for me, it works as expected:

C:\>curl --insecure -verbose -X GET "https://localhost:8099/api/ListCompanies"   -H "accept: application/json" -H "Authorization: Basic YTph="
Note: Unnecessary use of -X or --request, GET is already inferred.
*   Trying ::1:8099...
*   Trying 127.0.0.1:8099...
* Connected to localhost (127.0.0.1) port 8099 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (IN), TLS handshake, Server finished (14):
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
* TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (OUT), TLS handshake, Finished (20):
* TLSv1.2 (IN), TLS handshake, Finished (20):
* SSL connection using TLSv1.2 / AES256-GCM-SHA384
* ALPN, server did not agree to a protocol
* Server certificate:
*  subject: CN=*.consolit.nl
*  start date: Oct 20 00:00:00 2021 GMT
*  expire date: Nov 20 23:59:59 2022 GMT
*  issuer: C=GB; ST=Greater Manchester; L=Salford; ...
*  SSL certificate verify result: unable to get local issuer certificate (20), continuing anyway.
> GET /api/ListCompanies HTTP/1.1
> Host: localhost:8099
> User-Agent: curl/7.72.0
> Referer: rbose
> accept: application/json
> Authorization: Basic YTph=
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Connection: close
< Content-Type: application/json; charset=utf-8
< Content-Length: 29
< Date: Mon, 28 Mar 2022 12:33:57 GMT
< WWW-Authenticate: Basic realm=""
< Accept-Encoding: gzip, identity
< Access-Control-Allow-Origin: *
<
[{"naam":"Test","werkm":999}]* Closing connection 0
* TLSv1.2 (OUT), TLS alert, close notify (256):

Hi,

That “OPTIONS” method is still sent in above example.
Because of your comment that in the new version of Remobejects you will sent a 204 back I tried this hack.
Surprise, surprise it makes everything works!

Is this basically your solution as well?

procedure TROBaseHTTPServer.ProcessRequest(const aTransport: IROHTTPTransportEx;
  const aRequestStream: TStream; out aResponseStream: TROBinaryMemoryStream;
  const aResponse: IROHTTPResponse);
....

  l_Request: IROHTTPRequest;
begin
  if Assigned(aRequestStream) then aRequestStream.Position := 0;

  aResponseStream := nil;
  l_acceptModes := HTTP_DetectAcceptEncoding(aTransport.Headers[id_AcceptEncoding]);

  if Supports(aTransport, IROHTTPRequest, l_Request) then
  begin
    if l_Request.Method = 'OPTIONS' then
    begin
      aResponse.Code := HTTP_204_code;
      aResponse.Status:= HTTP_204_status;
      aResponse.ContentType := id_ContentType_text_html;
      aResponse.Headers[id_AcceptEncoding] := HTTP_SupportedEncoding;
      DoCORSSupport(aTransport, aResponse);
      WriteUTF8Error(HTTP_204_status);
      Exit;
    end;
  end;

Hi,

in general, it does something similar to my code

Hi,

I installed 1535, but the same error occurs.
That is because of if RequireHTTPAuthentication etc
It never gets to your “OPTIONS” in that scenario.
I copied your code and placed it before “if RequireHTTPAuthentication”
Now it works again.

OPTIONS - HTTP | MDN (mozilla.org)

procedure TROBaseHTTPServer.ProcessRequest(const aTransport: IROHTTPTransportEx;
  const aRequestStream: TStream; out aResponseStream: TROBinaryMemoryStream;
  const aResponse: IROHTTPResponse);
...
begin
  if Assigned(aRequestStream) then aRequestStream.Position := 0;
 
  aResponseStream := nil;
  l_acceptModes := HTTP_DetectAcceptEncoding(aTransport.Headers[id_AcceptEncoding]);


  if Supports(aTransport, IROHTTPRequest, l_httpRequest) then try
    if l_httpRequest.Method = id_Method_Options then begin
      aResponse.Code := HTTP_204_code;
      aResponse.Status := HTTP_204_status;
      aResponse.ContentType := id_ContentType_text_html;
      aResponse.Headers[id_AcceptEncoding] := HTTP_SupportedEncoding;
      DoCORSSupport(aTransport, aResponse);
      Exit;
    end;
  finally
    l_httpRequest := nil;
  end;

  if ([aemGZIP, aemIdentity,aemAsterisk] * l_acceptModes = []) and
     ([aemUnknown, aemCompress, aemDeflate] * l_acceptModes <> []) then begin
    aResponse.Code := HTTP_406_code;
    aResponse.Status:= HTTP_406_status;
    WriteUTF8Error(HTTP_406_status);
    Exit;
  end;
  if RequireHTTPAuthentication then begin
    aResponse.Headers[id_WWWAuthenticate] := Format('Basic realm="%s"', [Self.fHTTPAuthenticationRealm]);

Hi,

if authorization is specified, everything is ok:

C:\>curl --insecure -verbose -X OPTIONS "https://localhost:8099/api/ListCompanies"   -H "accept: application/json" -H "Authorization: Basic YTph="
*   Trying ::1:8099...
*   Trying 127.0.0.1:8099...
* Connected to localhost (127.0.0.1) port 8099 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (IN), TLS handshake, Server finished (14):
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
* TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (OUT), TLS handshake, Finished (20):
* TLSv1.2 (IN), TLS handshake, Finished (20):
* SSL connection using TLSv1.2 / AES256-GCM-SHA384
* ALPN, server did not agree to a protocol
* Server certificate:
*  subject: CN=*.consolit.nl
*  start date: Oct 20 00:00:00 2021 GMT
*  expire date: Nov 20 23:59:59 2022 GMT
*  issuer: C=GB; ST=Greater Manchester; L=Salford; ....
*  SSL certificate verify result: unable to get local issuer certificate (20), continuing anyway.
> OPTIONS /api/ListCompanies HTTP/1.1
> Host: localhost:8099
> User-Agent: curl/7.72.0
> Referer: rbose
> accept: application/json
> Authorization: Basic YTph=
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 204 No Content
< Connection: close
< Content-Type: text/html; charset=ISO-8859-1
< Content-Length: 0
< Date: Wed, 30 Mar 2022 09:39:45 GMT
< WWW-Authenticate: Basic realm=""
< Accept-Encoding: gzip, identity
< Access-Control-Allow-Origin: *
< Access-Control-Max-Age: 86400
<
* Closing connection 0
* TLSv1.2 (OUT), TLS alert, close notify (256):