RTC Forums

Subscription => Support => Topic started by: Kas on July 22, 2018, 10:56:19 AM



Title: TRtcMessengerServer enhancement request/suggestion.
Post by: Kas on July 22, 2018, 10:56:19 AM
I would love TRtcMessengerServer to support long request data .

TRtcMessgengerServer can add nice features to a TCP server-client application without the hassle of utilizing additional ports specially if this application is not written in Delphi, that application is already using port 443, what i did is after checking if the request is POST or GET i passed the requests/data to DLL that have this TRtcMessengerServer and it worked like magic, i can so lot of things remotely and even from a web browser, but the limit of 32000 bytes prevent me from adding more features or unleash its power like adding full web server to access log files from a browser or browsing big folders ( in case of Portal File Transfer ) or even use the portal RDP.

So would you please consider to enhance this powerful components ( server and client )? or show us how to do it ?


ps: Examples folder lack a sample for those components like the others, you always did it the right way, so it will be nice to see how it should be done .


Title: Re: TRtcMessengerServer enhancement request/suggestion.
Post by: D.Tkalcec (RTC) on July 22, 2018, 01:39:47 PM
Even though "TRtcMessageClient" and "TRtcMessageServer" components use a 32KB buffer to read from the input stream, the number of bytes you can send and receive in a single request or response when using these components is NOT limited by the size of that buffer. The only thing the buffer size affects, is the number of times the "OnDataReceived" event will be triggered for requests and responses until the entire request or response content body was read. Since this is also the case when working with HTTP/s components (multiple "OnDataReceived" events will be triggered for requests and responses containing a larger content body), I fail to see the problem.


Title: Re: TRtcMessengerServer enhancement request/suggestion.
Post by: Kas on July 22, 2018, 05:32:24 PM
Then there is few things i am doing wrong , i don't have OnDataReceived in TRtcMessengerServer .

What i was doing something can be tested with this :

I dropped TRtcMessgerServer on a module and added TRtcPortalGateway , assigned the server in that Gateway , now on other server part (C++ TCP media relay server) ,i am receiving packets , then i am checking if those packets are HTTP then searching them for #13#10#13#10 after that i parse the content-length and make sure the received data is a complete http request ( header and content ) , after that i it using as aStream in ProcessData(aRequest, aReply: TStream) then sending the result stream aReply back if the size >0 , this works fine ! and the control can browse the remote files on the host and send and receive files, and i can browse folders it works and download files if those files are small relatively, and fail if the folder contains thousands files or files are big , same happen with show remove desktop , view desktop from the control will not work ( while desktop to host with small window around 100 pixel will work fine )

Should i drop this aReply stream and use RtcMsgServerDataOut instead ? How to access the raw response from Sender:TRtcConnection inside this event?


Title: Re: TRtcMessengerServer enhancement request/suggestion.
Post by: D.Tkalcec (RTC) on July 22, 2018, 07:54:42 PM
TRtcMessageClient and TRtcMessageServer components were designed to be linked together for direct communication, or be used with 3rd-party transports designed for these components - like NexusDB transport plugins, which are included as a 3rd-party package, but require NexusDB components to compile. If you are trying to implement your own custom transport, you can check how TRtcMessageClient and TRtcMessageServer components work together when linked directly, or take a closer look at NexusDB plugins, but ... explaining how to correctly implement a custom transport for the TRtcMessageClient or the TRtcMessageServer component is beyond the scope of this Forum.


Title: Re: TRtcMessengerServer enhancement request/suggestion.
Post by: Kas on July 22, 2018, 09:45:38 PM
Thank you Danijel for answering and please forgive my English, may be i didn't clear about what i am asking for.

I am not asking for custom protocol but asking to enhance the portability and usability of RtcMessengerServer and RtcMessengerClient for that i posted in suggestion and features :

1_ I saw the NexusDB plugin and i managed to handle this limitation where i should pass one message and only one ( one full request with content ) to ProcessData , while i imagine you are planning to support HTTP2 where HTTP pipelining is needed , so adding such mechanism to feed ProcessData with bulk requests in those messenger components will be easier, where one can stream requests as whole or parts and those components will buffer and respond accordingly.

2_ Callback: in a case where gateway had received a request and a response should be sent to multiple connected client, it will be nice to have specific event triggered with Sender:RtcConnection for each connection intended to receive with the response content as raw .

3_ I still can't find the reason for why sometimes in my example using the portal i can send files bigger like 256k successfully and sometimes it fails at 33k, and my question is not about , and i gave an example where it fail to deliver on big request or responses , i am not sure yet ,
   A) if it is RtcPortal bug , then i know you stand about it .
   B) if it is a TRtcMessengerServer bug , then you have it .
   C) if it is by design , then please consider this a suggestion to enhance or modify , as i know you calling it messenger from a simple message .

The point is and was to use RTC with different application not the ones developed by Delphi or FreePascal.

Thank you Danijel again, wasting your time is not my intention.


Title: Re: TRtcMessengerServer enhancement request/suggestion.
Post by: Kas on July 22, 2018, 11:22:40 PM
Here is a simple way to see the limit with request :
New VCL project with RtcMessengerServer with the default TRtcPortalGateway copied from the portal gateway and a RtcTcpServer

Code:
procedure TForm6.RtcTcpServer1ClientConnect(Sender: TRtcConnection);
begin
  Sender.Info.asObj['con']:=RtcMessageServer1.GetConnection;
end;

procedure TForm6.RtcTcpServer1ClientDisconnect(Sender: TRtcConnection);
begin
  RtcMessageServer1.PutConnection(Sender.Info.asObj['con']);
  Sender.Info.asObj['con']:=nil;
end;

procedure TForm6.RtcTcpServer1DataReceived(Sender: TRtcConnection);
var
  B:RtcByteArray;
  aReq,aAns:TMemoryStream;
begin
  aReq:=TMemoryStream.Create;
  aAns:=TMemoryStream.Create;
  try
    B:=Sender.ReadEx;
    aReq.WriteBuffer(B[0],Length(B));
    aReq.Position:=0;
    TRtcMessageServer(Sender.Info.asObj['con']).ProcessData(aReq,aAns);
    if aAns.Size>0 then
    begin
      aAns.Position:=0;
      SetLength(B,aAns.Size);
      aAns.ReadBuffer(B[0],aAns.Size);
      Sender.WriteEx(B);
    end else
    begin
      /// this will be reached when the request is bigger than 32k
    end;
  finally
    aReq.Free;
    aAns.Free;
  end;
end;

The above will code will allow portal clients connect and browse folders and send files as long the files are small relatively and folder with not with so many files (few thousands) , in short this will fail ( no exception here but the aResponse stream is empty ) when a request content is bigger 32k, and this will break one response for one request.
and that what i meant for enhancing or removing the limitation.


Title: Re: TRtcMessengerServer enhancement request/suggestion.
Post by: D.Tkalcec (RTC) on July 23, 2018, 03:25:50 PM
As the name implies, TRtcMessageClient and TRtcMessageServer components are message-based client and server components. They were designed to process messages in a blocking way. A complete request is required to produce a complete response.

If you look at NexusDB transport plugins, you will see that their Server- and Client-side plugins ONLY use the "rtcTransports.pas" unit. The ONLY thing interesting in that unit is the "IRTCMessageReceiver" interface, which ONLY has one method: "ProcessMessage", as you can see below (copy/paste from the "rtcTransports.pas" unit) ...
 
type
  { @abstract(Transport Plugin interface)
    This interface should be *IMPLEMENTED* when writing a "receiver" transport plugin,
    which can be linked to TRtcMessageClient in place of the TRtcMessageServer component. }
  IRTCMessageReceiver = interface
    ['{C9E3606F-ED08-43F4-AF97-F55A3EC8F14B}']
    { ProcessMessage need to be called *only* once per request, with a complete request data
      waiting in the "aRequest" stream and an empty "aReply" stream to receive the response.
      Request processing is done in a "blocking mode", which means that the caller will
      have the complete response filled in the "aReply" stream, before the call returns. }
    procedure ProcessMessage(aRequest, aReply: TStream);
  end;

This is NOT a coincidence. This is BY DESIGN, to shield 3rd-party transport details from RTC component details and vice-versa, while allowing RTC components to communicate with each other through 3rd-party communication channels.

In other words, components linked to a TRtcMessageClient can communicate with components linked to TRtcMessageServer directly, or through a compatible pair of Client- and Server-transport plugins, without having to worry about the actual transport being used. At the same time, the transport plugin should NOT concern itself with the actual data being transported, nor should it make any assumptions about the data format used in requests and responses, but should handle each request and response as an opaque binary stream.


Title: Re: TRtcMessengerServer enhancement request/suggestion.
Post by: Kas on July 23, 2018, 09:06:49 PM
Thank you Danijel very much , that is helpful.

I couldn't find how to attach a file to this post so i will paste the code it may help someone, i just couldn't figure out how to disconnect RtcTcpServer and RtcMessengerServer ??:
Code:
type
  TForm6 = class(TForm)
    RtcMessageServer1: TRtcMessageServer;
    RtcTcpServer1: TRtcTcpServer;
    Gateway: TRtcPortalGateway;
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure FormCreate(Sender: TObject);
    procedure RtcTcpServer1Connect(Sender: TRtcConnection);
    procedure RtcTcpServer1DataReceived(Sender: TRtcConnection);
    procedure RtcTcpServer1Disconnect(Sender: TRtcConnection);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form6: TForm6;

implementation

{$R *.dfm}

procedure TForm6.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  RtcMessageServer1.StopListen;
  RtcTcpServer1.StopListen;
  RtcTcpServer1.Disconnect;
end;

procedure TForm6.FormCreate(Sender: TObject);
begin
  RtcTcpServer1.Listen;
end;

procedure TForm6.RtcTcpServer1Connect(Sender: TRtcConnection);
begin
  Sender.Info.asObj['con'] := RtcMessageServer1.GetConnection;
  Sender.Info.asObj['req'] := TMemoryStream.Create;
  Sender.Info.asObj['res'] := TMemoryStream.Create;
  Sender.Info.asInteger['reqsize'] := 0;
end;

procedure TForm6.RtcTcpServer1DataReceived(Sender: TRtcConnection);
const
  CONTENT_LEN = 'CONTENT-LENGTH:';
  CRLF = #13#10;

  function GetRequestSize(buf: RtcByteArray): Integer;
  var
    st, ss: RtcString;
    p, ct: Integer;
  begin
    Result := 0;
    p := PosEx(CRLF + CRLF, buf);
    if p > -1 then
    begin
      st:=Upper_Case(RtcBytesZeroToString(buf,0,p + 3));
      ct := PosEx(CONTENT_LEN, st);
      if ct > 0 then
        ss := RtcBytesZeroToString(buf, ct + Length(CONTENT_LEN), PosEx(#13#10,
          st, ct) - (ct + Length(CONTENT_LEN)) - 1)
      else
        Exit;
      Result := Str2IntDef(ss, 0) + Length(st);
    end;
  end;

var
  buf: RtcByteArray;
  aReq, aAns: TMemoryStream;
  rs: Integer;
begin
  aReq := TMemoryStream(Sender.Info.asObj['req']);
  aAns := TMemoryStream(Sender.Info.asObj['res']);
  buf := Sender.ReadEx;
  aReq.WriteBuffer(buf[0], Length(buf));

  rs := Sender.Info.asInteger['reqsize'];
  if rs = 0 then
  begin
    rs := GetRequestSize(buf);
    if rs = 0 then
    begin
      Sender.Disconnect;
      Exit;
    end;
    Sender.Info.asInteger['reqsize'] := rs;
  end;

  if rs <> aReq.Size then
  begin
    if rs < aReq.Size then
      Sender.Disconnect;
    Exit;
  end;

  aReq.Position := 0;
  TRtcMessageServer(Sender.Info.asObj['con']).ProcessData(aReq, aAns);
  if aAns.Size > 0 then
  begin
    aAns.Position := 0;
    SetLength(buf, aAns.Size);
    aAns.ReadBuffer(buf[0], aAns.Size);
    Sender.WriteEx(buf);
    aAns.Clear;
    aReq.Clear;
    Sender.Info.asInteger['reqsize'] := 0;
  end
  else
  begin
    Sender.Disconnect;
    Exit;
  end;

end;

procedure TForm6.RtcTcpServer1Disconnect(Sender: TRtcConnection);
begin
  RtcMessageServer1.PutConnection(Sender.Info.asObj['con']);
  Sender.Info.asObj['con'] := nil;
  TMemoryStream(Sender.Info.asObj['req']).Free;
  Sender.Info.asObj['req'] := nil;
  TMemoryStream(Sender.Info.asObj['res']).Free;
  Sender.Info.asObj['res'] := nil;
end;

end.

RtcTcpServer is must be multithreaded, i uninstalled Delphi IDE and EurekaLog and reinstalled them and the problem with big request seems to be resolved !


Title: Re: TRtcMessengerServer enhancement request/suggestion.
Post by: D.Tkalcec (RTC) on July 23, 2018, 09:09:20 PM
Thanks for your complete example Project. I'm sure someone will benefit from it.

Anyway ... while you were working on this, I've released an update for the RTC SDK (v9.26), which might fix the problem with your previous (much simpler) example, because it should now be possible to use the "ProcessData" method to handle request content as it arrives, rather than storing it in a temporary buffer until the complete request content is here (as you did in your more complex example now), but ... please keep in mind that this is NOT how the components were meant to be used, so you might stumble over some other problems along the way, like - for example - memory issues when using an in-memory stream to accept the response (as you did in both of your examples) if you try to use this approach to download a large file, since the entire contents of the file would then be loaded into the memory stream before being sent out.

PS. I've moved this topic to the "Support" section now.


Title: Re: TRtcMessengerServer enhancement request/suggestion.
Post by: Kas on July 23, 2018, 09:33:59 PM
I was writing questions , and it is great support and understanding from you.

Thank you very much now it is working fine,  webserver and RtcPortal or the more important RtcRemoteFunction can be injected in any internet application easily, even adding web browser functionality, but i have few questions :
1_ i understand the consequences of using the memory like this but how to free the blocking thread ? (cancel/exit ProcessData )
2_ in my code above i couldn't figure out the right way to close and terminate , would you explain how to do it.
3_ If for some reason the thread that is blocking on ProcessData got terminated externally ( because it is not mine to start with ) how to recover ? if that is possible.


Title: Re: TRtcMessengerServer enhancement request/suggestion.
Post by: D.Tkalcec (RTC) on July 23, 2018, 10:00:38 PM
Sorry, but I don’t have answers to your latst questions. As said, you are using the components in a way in which they were NOT meant to be used, so there are no mechanisms in place to handle the extreme cases you have mentioned.


Title: Re: TRtcMessengerServer enhancement request/suggestion.
Post by: Kas on July 23, 2018, 11:20:15 PM
Third question that was worst case scenario, when things goes south, first two questions is what concern me more as i can't find working cancel or abort method.


Title: Re: TRtcMessengerServer enhancement request/suggestion.
Post by: D.Tkalcec (RTC) on July 24, 2018, 08:54:07 AM
Frankly, I think that you would be much better off by using the TRtcHttpServer component to host a fully asynchronous HTTP Server, which is designed for that purpose, instead of fiddling with the TRtcMessageServer and looking for workarounds to handle potential issues which could arise because of its blocking nature.

When your Client and your Server are running on the same machine (or in the same process), you can bind the Server to the ‘localhost’ address (assign it to the ‘ServerAddr’ property on the TRtcHttpServer component) to make it inaccessible from any other machine.

Also, by using ‘localhost’ as your destination address on the Client, you won’t be generating network traffic (all traffic to and from the ‘localhost’ address is handled internally by the socket API). You only need an available TCP/IP listening port, but with 64K port numbers to choose from, this shouldn’t be a problem.


Title: Re: TRtcMessengerServer enhancement request/suggestion.
Post by: Kas on July 24, 2018, 09:15:44 AM
I agree with you, but still it is neat Swiss Army Knife to have in the toolbox!
I need this for two application one written in Unity and the other is media server both are using TLS connection and strictly firewalled and the only way to achieve my goal fast and easy ( i am too lazy to waste time in that Unity ) without asking to change firewall settings, now i can support web browser without minimum modification in both servers, about the blocking i can make my own thread to block on ProcessData and release the caller thus i have non-blocking with simple one callback.


Title: Re: TRtcMessengerServer enhancement request/suggestion.
Post by: Kas on July 25, 2018, 03:54:49 PM
I found time to dig deeper and resolve the closing problem, i couldn't find a way other than this ugly hack.

I added WakeUpAllDelayedCall to rtcSrvModule and called this on termination, it worked fine and no more exceptions or delays, ProcessData exited as it should be, is there a way wake up specific calls based on the owner component itself ( RtcServerModule or RtcMessegerServer)

Code:
procedure WakeUpAllDelayedCall;
  var
    ob:TObject;
    i:RtcIntPtr;
  begin
  CS.Acquire;
  try
    if assigned(List) then
      begin
        i:=List.search_min(ob);
      while assigned(ob) do
        begin
          if ob is TRtcDelayedCall then
          TRtcDelayedCall(ob).WakeUp;
          i:=List.search_g(i, ob);
        end;
      end;
  finally
    CS.Release;
    end;
end;

Would you please add such last approach as solution for extreme cases ? ( it is ugly and wrong but might prevent freezing or crashing )

ps: RtcMessengerServer should check in ProcessData and ProcessMessage for isListening to simulate server behavior better.


Title: Re: TRtcMessengerServer enhancement request/suggestion.
Post by: Kas on July 25, 2018, 04:23:22 PM
This will work too if i kept a list GetConnection and called them with :

Code:
procedure WakeUpByConnection(conn:TRtcConnection);
  var
    ob:TObject;
    i:RtcIntPtr;
  begin
  CS.Acquire;
  try
    if assigned(List) then
      begin
        i:=List.search_min(ob);
        while assigned(ob) do
          begin
            if (ob is TRtcDelayedCall)then
            if  TRtcDelayedCall(ob).Conn=conn then
              TRtcDelayedCall(ob).WakeUp;
            i:=List.search_g(i, ob);
          end;
      end;
  finally
    CS.Release;
    end;
end;


Title: Re: TRtcMessengerServer enhancement request/suggestion.
Post by: D.Tkalcec (RTC) on July 25, 2018, 04:36:10 PM
Since (A) all delayed call objects are kept in a single global list and (B) the only reason to force a wake-up call on all delayed call objects would be to make sure that blocked threads waiting for a wake-up call get "unblocked" before the application terminates, I think that adding a global "WakeUpAllDelayedCalls" procedure is the simplest solution to this problem, so ... I'm going to add it to the "rtcSrvModule.pas" unit in the next RTC SDK update.


Title: Re: TRtcMessengerServer enhancement request/suggestion.
Post by: Kas on July 25, 2018, 04:56:15 PM
Thank you Danijel, that is great.

But may adding (B) will be helpful too !

if TRtcMessengerServer kept a list of only delayed connections and be used like this


Code:
 
procedure TRtcMessageServer.ProcessData(aRequest, aReply: TStream);
  begin
  EnterEvent;
  try
    FConList.Add(Con);
    TMyProvider(Con).ExecuteRequest(aRequest, aReply);
    FConList.Remove(Con);
  finally
    LeaveEvent;
    end;
  end;

Then TRtcMessageServer can wake only the blocked calls, calling (B)  from TRtcMessengerServer Disconnect and Destroy will resolve all the specific problem that comes with TRtcMessengerServer simulations.
and (A) is helpful in all.

Thank you again ,i see you already updated the version, while i still writing a post !, and that is awesome.


Title: Re: TRtcMessengerServer enhancement request/suggestion.
Post by: D.Tkalcec (RTC) on July 25, 2018, 05:02:00 PM
Even though delayed call objects need a reference to the Connection object from which they were initiated, Connection components (like TRtcMessageServer) do NOT have any knowledge about Delayed Calls. Delayed Call objects are implemented at a higher level and used ONLY by the "TRtcServerModule" component.

Anyway ... I've released the update with the "WakeUpAllDelayedCalls" procedure in the "rtcSrvModule.pas" unit. Since this is also the unit where the "TRtcServerModule" component is implemented, it will be in the "uses" clause of any unit implementing server-side remote functions, so calling "WakeUpAllDelayedCalls" from the "finalize" section of a unit where delayed calls are used would probably be the "cleanest" solution.


Title: Re: TRtcMessengerServer enhancement request/suggestion.
Post by: Kas on July 25, 2018, 05:11:30 PM
Thank you very much, that is enough.
I will prepare an example ( simple and easy ) and post it here.


Title: Re: TRtcMessengerServer enhancement request/suggestion.
Post by: Kas on July 25, 2018, 06:21:20 PM
Code:
unit Main;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes,
  Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, rtcConn, rtcSrvModule,
  rtcPortalGate, rtcSystem, rtcInfo, rtcMsgSrv, rtcTcpSrv, Vcl.StdCtrls,
  rtcDataSrv;

type
  TForm6 = class(TForm)
    RtcMessageServer1: TRtcMessageServer;
    RtcTcpServer1: TRtcTcpServer;
    Gateway: TRtcPortalGateway;
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure FormCreate(Sender: TObject);
    procedure RtcMessageServer1Disconnect(Sender: TRtcConnection);
    procedure RtcTcpServer1Connect(Sender: TRtcConnection);
    procedure RtcTcpServer1DataReceived(Sender: TRtcConnection);
    procedure RtcTcpServer1Disconnect(Sender: TRtcConnection);
  private
  public
  end;

var
  Form6: TForm6;

implementation

{$R *.dfm}

procedure TForm6.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  RtcTcpServer1.StopListen;
  RtcMessageServer1.StopListen;
  WakeUpAllDelayedCalls;
  RtcTcpServer1.Disconnect;
end;

procedure TForm6.FormCreate(Sender: TObject);
begin
  RtcMessageServer1.Listen;
  RtcTcpServer1.Listen;
end;

procedure TForm6.RtcMessageServer1Disconnect(Sender: TRtcConnection);
begin
  TRtcConnection(Sender.Info.asObj['parCon']).Disconnect;
  Sender.Info.asObj['parCon'] := nil;
end;

procedure TForm6.RtcTcpServer1Connect(Sender: TRtcConnection);
var
  Conn: TRtcMessageServer;
begin
  Conn := TRtcMessageServer(RtcMessageServer1.GetConnection);
  Conn.Info.asObj['parCon'] := Sender;
  Sender.Info.asObj['con'] := Conn;
  Sender.Info.asObj['req'] := TMemoryStream.Create;
  Sender.Info.asObj['res'] := TMemoryStream.Create;
  Sender.Info.asInteger['reqsize'] := 0;
end;

procedure TForm6.RtcTcpServer1DataReceived(Sender: TRtcConnection);
const
  CONTENT_LEN = 'CONTENT-LENGTH:';
  CRLF = #13#10;

  function GetRequestSize(buf: RtcByteArray): Integer;
  var
    st, ss: RtcString;
    p, ct: Integer;
  begin
    Result := 0;
    p := PosEx(CRLF + CRLF, buf);
    if p > -1 then
    begin
      st := Upper_Case(RtcBytesZeroToString(buf, 0, p + 3));
      ct := PosEx(CONTENT_LEN, st);
      if ct > 0 then
        ss := RtcBytesZeroToString(buf, ct + Length(CONTENT_LEN), PosEx(CRLF, st,
          ct) - (ct + Length(CONTENT_LEN)) - 1)
      else
        Exit;
      Result := Str2IntDef(ss, 0) + Length(st);
    end;
  end;

var
  buf: RtcByteArray;
  aReq, aAns: TMemoryStream;
  rs: Integer;
  conn: TRtcMessageServer;
begin
  if not RtcMessageServer1.isListening then
  begin
    Sender.Disconnect;
    Exit;
  end;

  aReq := TMemoryStream(Sender.Info.asObj['req']);
  buf := Sender.ReadEx;
  aReq.WriteBuffer(buf[0], Length(buf));

  rs := Sender.Info.asInteger['reqsize'];
  if rs = 0 then
  begin
    rs := GetRequestSize(buf);
    if rs = 0 then
    begin
      Sender.Disconnect;
      Exit;
    end;
    Sender.Info.asInteger['reqsize'] := rs;
  end;

  if rs <> aReq.Size then
  begin
    if rs < aReq.Size then
      Sender.Disconnect;
    Exit;
  end;

  aReq.Position := 0;
  aAns := TMemoryStream(Sender.Info.asObj['res']);
  conn := TRtcMessageServer(Sender.Info.asObj['con']);
  conn.ProcessData(aReq, aAns);
  if aAns.Size > 0 then
  begin
    aAns.Position := 0;
    SetLength(buf, aAns.Size);
    aAns.ReadBuffer(buf[0], aAns.Size);
    if not Application.Terminated then
      Sender.WriteEx(buf);
    aAns.Clear;
    aReq.Clear;
    Sender.Info.asInteger['reqsize'] := 0;
  end
  else
  begin
    Sender.Disconnect;
    Exit;
  end;
end;

procedure TForm6.RtcTcpServer1Disconnect(Sender: TRtcConnection);
begin
  RtcMessageServer1.PutConnection(Sender.Info.asObj['con']);
  Sender.Info.asObj['con'] := nil;
  TMemoryStream(Sender.Info.asObj['req']).Free;
  Sender.Info.asObj['req'] := nil;
  TMemoryStream(Sender.Info.asObj['res']).Free;
  Sender.Info.asObj['res'] := nil;
end;

end.

Things to know about this example:
RTC ProcessData does support partial request , but i kept the code above as an example.
It assume the HTTP header (only the header not the whole request ) is not fragmented or will disconnect , this should not be a problem as fragmentation is very unlikely for the first MTU size (around 1500 bytes) when sending, so while the header size is less than MTU we are safe .


Title: Re: TRtcMessengerServer enhancement request/suggestion.
Post by: D.Tkalcec (RTC) on July 25, 2018, 07:06:12 PM
Ignore my question about your example code (question deleted). I've just realized that you are calculating the size of the complete request stream (including request headers) in the "rs" variable and not just the request content body.


Title: Re: TRtcMessengerServer enhancement request/suggestion.
Post by: Kas on July 25, 2018, 07:11:03 PM
rs is the request size in full ( header and content length) ,if received length is more than one request then this is not standard HTTP protocol ( 1.0 and 1.1 ) and should disconnect , right ?
Because ProcessData is simple procedure and doesn't return if the connection should be dropped or how seek the request stream to the full request been received currently ProcessData will eat the extra data and do nothing.

Try this
  aReq.WriteBuffer(buf[0], 1);
  aReq.Position := 0;
  aAns := TMemoryStream(Sender.Info.asObj['res']);
  conn := TRtcMessageServer(Sender.Info.asObj['con']);
  conn.ProcessData(aReq, aAns);

it will work like nothing happen.


Title: Re: TRtcMessengerServer enhancement request/suggestion.
Post by: D.Tkalcec (RTC) on July 25, 2018, 07:17:32 PM
OK, so it's a quick "request format" check.


Title: Re: TRtcMessengerServer enhancement request/suggestion.
Post by: Kas on July 25, 2018, 07:24:44 PM
Yes exactly.
This will do the job, while waiting for your RTC SDK to support HTTP2 ;) with full (http pipelining)


Title: Re: TRtcMessengerServer enhancement request/suggestion.
Post by: D.Tkalcec (RTC) on July 25, 2018, 07:49:26 PM
I'm not sure I follow. What do you mean by "waiting for your RTC SDK to support HTTP2"? You know that HTTP/2 is only going to be implemented on HTTP connection components (TRtcHttpServer and TRtcHttpClient). Right?


Title: Re: TRtcMessengerServer enhancement request/suggestion.
Post by: Kas on July 25, 2018, 08:21:11 PM
I imagined the feeding mechanism for requests as stream and the way delayed call internally will be huge change, and this will affect all components including RtcMessageServer, i imagined you will centralize the request handling code ( HTTP1 and HTTP2 ) and use it cross components components, i thought you will let the TRtcRequest build itself from the data received or a special builder class to help with HTTP2 pipelining, but it seems you will build it only for HTTP server and client.
In all cases i wish you good luck.