We’ve run into an issue in our Delphi FMX app. We use TRONetSuperHTTPChannel to connect to a Remoting SDK SuperHTTP server endpoint as part of our login process.
On Android, iOS and macOS the ShHello request fails for one of our endpoints: we get an HTML “Request Rejected” response from a Web Application Firewall. On Windows the same request succeeds.
The issue seems to be that TRONetSuperHTTPChannel.DispatchHTTPRequest never sets a Content-Type on the post. On Android/iOS/macOS the platform HTTP stack then defaults to application/x-www-form-urlencoded, which the WAF rejects for the binary SuperHTTP body. Windows (WinHTTP) sends no Content-Type in that case, and the WAF allows that to go through.
As temporary workaround I’ve subclassed TRONetSuperHTTPChannel and have my own version of DispatchHTTPRequest and it works but would be nice if this could be fixed.
Thank you for your response. So application/octet-streamis accepted, but the SetHeaders call doesnt work. What worked for me is to set it like this: l_request.SetHeaderValue(id_ContentType, id_ContentType_application_octetstream);
But that is actually also not the only thing I see now.
There’s also this
procedure TROBaseSuperHTTPChannel.DispatchHTTPRequest(aWaitingThread: Boolean; aRequest: TStream; out aResponse: TStream);
begin
{$IFDEF LOG}
if not aWaitingThread then
Log('===== DispatchHTTPRequest (' + TargetUrl + ')')
else
Log('===== DispatchHTTPRequest[WAITING] (' + TargetUrl + ')');
{$ENDIF}
if fAllowGzipEncoding and not aWaitingThread then begin
if (aemGZIP in fServerAcceptEncodingModes) and
fCanUseContentEncoding and not IsEncryptionUsed and
(aRequest.Size >= fMinSizeForGzipEncoding) then begin
DoEncodeStream(aRequest);
SetHeaders(aWaitingThread, id_ContentEncoding, id_gzip);
end
else begin
SetHeaders(aWaitingThread, id_ContentEncoding, '');
end;
end
else begin
SetHeaders(aWaitingThread, id_ContentEncoding, '');
end;
end;
The 2 SetHeaders(aWaitingThread, id_ContentEncoding, ''); calls are also contributing to the issue. In my subclass I’m skipping those. So skipping these 2 + the l_request.SetHeaderValue thing from before made it work for me.
Yeah this seems to be the case for the encoding issue: SetHeaders(aWaitingThread, id_ContentEncoding, '');
As for the content type I dont understand why, but SetHeaders(aWaitingThread, id_ContentType, id_ContentType_application_octetstream); does not work. I used Fiddler to verify, content type doesnt show up in the request headers if we use the SetHeaders call but does with l_request.SetHeaderValue.
procedure TROBaseSuperHTTPChannel.DispatchHTTPRequest(aWaitingThread: Boolean; aRequest: TStream; out aResponse: TStream);
begin
SetHeaders(aWaitingThread, id_ContentType, id_ContentType_application_octetstream); // <<< added
procedure TRONetSuperHTTPChannel.SetHeaders(aWaitingThread: Boolean; const aName, aValue: string);
var
l_client: THTTPClient;
begin
if aWaitingThread then
l_client := ClientWait
else
l_client := ClientRequest;
if l_client.CustomHeaders[aName] <> aValue then
l_client.CustomHeaders[aName] := aValue;
end;