oakrom oakrom - 7 days ago 5
HTTP Question

How to connect DataSnap client to DataSnap server via proxy server?

The problem is this:

I decided to make a messenger/chat (VCL application) with callback on DataSnap technology (IDE Delphi XE6), has created a simple DataSnap server (tcp / ip + http) without the database, and thick client.

All works fine if the whole thing run on a local network (tcp / ip) or via the Internet (http).Problems arise when run over HTTP and the client machine has a HTTP proxy server, the client application can not connect to my DataSnap server application. Client application gets error "

10061 connection refused
"
or "
Expected datasnap context in request http://[YourServerIP]:[YourPort]/datasnap/tunnel
"
.

I tried to enter IP and port of the proxy server to params of component
TSQLConnection.Driver
params
DSProxyHost
and
DSProxyPort
, turned off my firewall and antivirus software, checked allows traffic to the proxy ip + port, but the problem has not disappeared.

After few days searches, without results, i decided listening requests from client application and response of my DataSnap Server application in
HTTPTrace
procedure of
DSHTTPService1
component, also with software HTTPDebugerPro, and i noticed interesting thing:


  • when client app connecting to ds server app without proxy server, in request ds server app receive
    URI
    with this text "
    /datasnap/tunnel
    "
    and all works fine ds server response "
    200, OK
    "
    .

  • when client app connecting to ds server app with proxy, in request ds server app receive
    URI
    with text "
    http://[YourServerIP]:[YourPort]/datasnap/tunnel
    "
    and raised exception with response error "
    404, Expected datasnap context in request http://YourServerIP:YourPort/datasnap/tunnel
    "
    .



Has anyone knows solution about this problem? How to connect DataSnap client to DataSnap server via proxy server? I searched solution for this problem several days, I shoveled the Internet but have not yet found a solution.

Answer

Thanks for all who try help to resolve this problem.

After several days of research on this problem, I found the solution, in my opinion is not a good solution, but it solves the problem.

So, Debugger is the best friend of a programmer, when processing request debugger has led me to Unit Datasnap.DSHTTP, to procedure TDSRESTServer.DoCommand(AContext: TDSHTTPContext; ARequestInfo: TDSHTTPRequest; AResponseInfo: TDSHTTPResponse).

In this procedure, there is a request processing and generating "Expected datasnap context in request" error if request URI is incorrect like my:

http://[YourServerIP]:[YourPort]/datasnap/tunnel

Following piece of code from the Unit Datasnap.DSHTTP in which you can modify one line and resolve the problem. In my case i cut part of URI http://[YourServerIP]:[YourPort] from request string and all works fine.

const
INVALID_DATASNAP_CONTEXT = 'Expected datasnap context in request% s'; // Do not localize

procedure TDSRESTServer.DoCommandOtherContext (AContext: TDSHTTPContext; ARequestInfo: TDSHTTPRequest; AResponseInfo: TDSHTTPResponse; const ARequest: string);
begin
  AResponseInfo.ResponseNo: = 404; {Datasnap not found}
  AResponseInfo.ResponseText: = Format (INVALID_DATASNAP_CONTEXT, [ARequest]);
  AResponseInfo.CloseConnection: = true;
end;

procedure TDSRESTServer.DoCommand (AContext: TDSHTTPContext; ARequestInfo: TDSHTTPRequest; AResponseInfo: TDSHTTPResponse);
var  
  Request: string; 
  NextRequest: string; 
  NextContext: string; 
  RestCtxt: string;
  StartDispatch: Boolean;
begin
  // HTTPDispatch object if necessary
  StartDispatch: = not TDSHTTPApplication.Instance.Dispatching;
  if StartDispatch then
    TDSHTTPApplication.Instance.StartDispatch (AContext, ARequestInfo, AResponseInfo);
  try
{$ IFNDEF POSIX}
    if CoInitFlags = -1 then
      CoInitializeEx (nil, COINIT_MULTITHREADED)
    else
      CoInitializeEx (nil, CoInitFlags);
{$ ENDIF}
    try
     // Check for context, if not found send the appropriate error message     
     Request: = ARequestInfo.URI;  //IT IS THIS LINE!!! you can write some code here to cut the not desired text from request string
     if Consume (FDSContext, Request, NextRequest) then
     begin
       Request: = NextRequest;
       if Consume (FRESTContext, Request, NextRequest) then
       begin
         // Datasnap / rest
         DoDSRESTCommand (ARequestInfo, AResponseInfo, NextRequest);
       end
       else if ConsumeOtherContext (Request, NextContext, NextRequest) then
       begin
         DoDSOtherCommand (AContext, ARequestInfo, AResponseInfo, NextContext, NextRequest, FDSServerName <> EmptyStr);
       end
       else
       begin
         RestCtxt: = Trim (FRESTContext);
         if RestCtxt = EmptyStr then
           RestCtxt: = SProtocolRestEmpty;
         AResponseInfo.ResponseNo: = 501; {Rest or other service not found in URI}
         AResponseInfo.ContentText: = Format (SProtocolNotSupported, [Request, RestCtxt]);
         AResponseInfo.CloseConnection: = true;
       end;
     end
     else
     begin
       // This may dispatch .js files for example
       DoCommandOtherContext (AContext, ARequestInfo, AResponseInfo, Request);
     end;
     if Assigned (Self.FTrace) then
     begin
       FTrace (Self, AContext, ARequestInfo, AResponseInfo);
     end;
    finally

      ClearInvocationMetadata ();
{$ IFNDEF POSIX}
      CoUnInitialize;
{$ ENDIF}
    end;
  finally
    if StartDispatch then
    TDSHTTPApplication.Instance.EndDispatch;
  end;
end;

i think in my case URI in request generated by Proxy server, which stand on client machine.

In my opinion this is not mistake as such, may be it is bug or imperfection of Datasnap.DSHTTP.TDSRESTServer.DoCommand procedure, what do you think about it?