Recent

Author Topic: TFPHTTPServer issues  (Read 4022 times)

ChristianH

  • New Member
  • *
  • Posts: 46
TFPHTTPServer issues
« on: January 26, 2019, 02:22:38 pm »
Hi,

i have a problem with the HTTP Server class. Under some circumstances the server ignores the request of the client. In my case (see the attached example) i want to open a video in VLC. Videolan opens the Dash Index file, and then it reads the first initialization segment. According to the VLC log it now tries to get the first video segment, but the server simply does not get the connection request. The result is that VLC freezes.

Maybe someone has an idea?

Christian

sash

  • Sr. Member
  • ****
  • Posts: 366
Re: TFPHTTPServer issues
« Reply #1 on: January 26, 2019, 03:15:14 pm »
Is server threaded?
Lazarus 2.0.10 FPC 3.2.0 x86_64-linux-gtk2 @ Ubuntu 20.04 XFCE

ChristianH

  • New Member
  • *
  • Posts: 46
Re: TFPHTTPServer issues
« Reply #2 on: January 26, 2019, 03:19:24 pm »
Yes, i tried it with and without threaded. The behavior is the same.

Christian

sash

  • Sr. Member
  • ****
  • Posts: 366
Re: TFPHTTPServer issues
« Reply #3 on: January 26, 2019, 03:43:19 pm »
I don't know how exactly your client works, I just guess it expects ranged partial content, while TFPHTTPServer's file serving is very basic (not to say dumb).

And what about simple plain files served to browser?

To know more, it's better to see detailed log, with Request and Response headers included.

Lazarus 2.0.10 FPC 3.2.0 x86_64-linux-gtk2 @ Ubuntu 20.04 XFCE

ChristianH

  • New Member
  • *
  • Posts: 46
Re: TFPHTTPServer issues
« Reply #4 on: January 27, 2019, 01:29:13 pm »
The example on the first post has the same issues. In theory a server should load the MPD file,

http://192.168.100.120:8082/ateme.mpd, then the init segment and after this the mp4 chunks. VLC does according to the logs the following:

[4184] adaptive stream filter debug: Retrieving http://192.168.100.120:8082/test-0-init.mp4v @0
[4184] main stream filter debug: resolving 192.168.100.120 ...
[4184] main stream filter debug: connecting to 192.168.100.120 port 8082 ...
..
[4184] adaptive stream filter debug: Retrieving http://192.168.100.120:8082/test-0-5245071.mp4v @0
- freeze, while the cpu usage raises up to 100%.

The web server receives:
/ateme.mpd
/ateme.mpd
/test-0-init.mp4v

The retrieving test-0-5245071.mp4v should fail since i don't provide this file (yet), but the server should at least get a connection request. I'm not sure where the issue is located, but it seem that Result:=Sockets.fpAccept(Socket,@Faddr,@L);  freezes in Function TInetServer.Accept : Longint;

Christian

sash

  • Sr. Member
  • ****
  • Posts: 366
Re: TFPHTTPServer issues
« Reply #5 on: January 27, 2019, 05:02:46 pm »
And again,

The first thing you should check is availability of server
Quote
what about simple plain files served to browser?
then
Quote
detailed log (from of your server app), with Request (at least) and Response headers included.
Lazarus 2.0.10 FPC 3.2.0 x86_64-linux-gtk2 @ Ubuntu 20.04 XFCE

ChristianH

  • New Member
  • *
  • Posts: 46
Re: TFPHTTPServer issues
« Reply #6 on: January 27, 2019, 08:11:39 pm »
I don't understand what you mean with checking if the server is available. What i can say is that i made a test server using Synapse TCP and this one works like it should. Not sure why, but i will post the class once i finished it.

This code is just a small proof of concept if something else is wrong, but it seem to work fine ;)
Code: Pascal  [Select][+][-]
  1. unit UWebServer;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, SysUtils, blcksock, synsock;
  9.  
  10. type
  11.   { TTCPRequest }
  12.   TTCPRequest = class
  13.   private
  14.     FRequest: TStringList;
  15.     FSocket: TTCPBlockSocket;
  16.     FStream: TStream;
  17.     FContentType: string;
  18.     FSent: Boolean;
  19.  
  20.     FMethod: string;
  21.     FProtocol: string;
  22.     FURI: string;
  23.   public
  24.     constructor Create;
  25.     destructor Destroy; override;
  26.  
  27.     procedure Send;
  28.  
  29.     property Method: string read FMethod;
  30.     property Protocol: string read FProtocol;
  31.     property URI: string read FURI;
  32.  
  33.     property Stream: TStream read FStream write FStream;
  34.     property ContentType: string read FContentType write FContentType;
  35.     property Request: TStringList read FRequest;
  36.   end;
  37.  
  38.   TOnRequestNotify = procedure(Sender: TObject; const ARequest: TTCPRequest) of object;
  39.   TOnErrorNotify = procedure(Sender: TObject; const AError: string) of object;
  40.  
  41.   { TTCPThread }
  42.   TTCPThread = class(TThread)
  43.   private
  44.     FSocket: TTCPBlockSocket;
  45.     FOnRequest: TOnRequestNotify;
  46.   protected
  47.     procedure Execute; override;
  48.   public
  49.     constructor Create(const ASock: TSocket; const AOnRequest: TOnRequestNotify);
  50.     destructor Destroy; override;
  51.  
  52.   end;
  53.  
  54.   { TServerThread }
  55.   TServerThread = class(TThread)
  56.   private
  57.     FOnError: TOnErrorNotify;
  58.     FOnRequest: TOnRequestNotify;
  59.  
  60.     FPort: integer;
  61.   protected
  62.     procedure Execute; override;
  63.   public
  64.     constructor Create(const APort: integer);
  65.     destructor Destroy; override;
  66.  
  67.     property OnError: TOnErrorNotify read FOnError write FOnError;
  68.     property OnRequest: TOnRequestNotify read FOnRequest write FOnRequest;
  69.   end;
  70.  
  71. implementation
  72.  
  73. uses Synautil;
  74.  
  75. { TTCPRequest }
  76. constructor TTCPRequest.Create;
  77. begin
  78.   FContentType := 'application/octet-stream';
  79.   FStream := nil;
  80.   FRequest := TStringList.Create;
  81. end;
  82.  
  83. destructor TTCPRequest.Destroy;
  84. begin
  85.   Send;
  86.   FRequest.Free;
  87.   inherited;
  88. end;
  89.  
  90. procedure TTCPRequest.Send;
  91. begin
  92.   if FSent then exit;
  93.   FSent := true;
  94.   if not assigned(FSocket) then
  95.     exit;
  96.  
  97.   if assigned(FStream) then
  98.   begin
  99.     FSocket.SendString('HTTP/1.0 200' + CRLF);
  100.     FSocket.SendString('Content-type: '+ FContentType + CRLF);
  101.     FSocket.SendString('Content-length: ' + IntToStr(FStream.Size) + CRLF);
  102.     FSocket.SendString('Connection: close' + CRLF);
  103.     FSocket.SendString('Date: ' + Rfc822DateTime(now) + CRLF);
  104.     FSocket.SendString('Server: Synapse TCP' + CRLF);
  105.     FSocket.SendString('' + CRLF);
  106.     FSocket.SendStreamRaw(FStream);
  107.   end
  108.   else
  109.     FSocket.SendString('HTTP/1.0 404' + CRLF);
  110. end;
  111.  
  112. { TServerThread }
  113.  
  114. procedure TServerThread.Execute;
  115. var
  116.   ListenerSocket: TTCPBlockSocket;
  117. begin
  118.   ListenerSocket := TTCPBlockSocket.Create;
  119.   if (ListenerSocket.LastError <> 0) and assigned(FOnError) then
  120.     FOnError(self, ListenerSocket.GetErrorDescEx);
  121.  
  122.   with ListenerSocket do
  123.   begin
  124.     CreateSocket;
  125.     if (LastError <> 0) and assigned(FOnError) then
  126.       FOnError(self, GetErrorDescEx);
  127.     Family := SF_IP4;
  128.     setLinger(True, 10000);
  129.     bind('0.0.0.0', IntToStr(FPort));
  130.     listen;
  131.  
  132.     while not terminated do
  133.     begin
  134.       if (CanRead(100)) and (LastError = 0) then
  135.         TTCPThread.Create(Accept, FOnRequest);
  136.       sleep(10);
  137.     end;
  138.   end;
  139.   ListenerSocket.Free;
  140. end;
  141.  
  142. constructor TServerThread.Create(const APort: integer);
  143. begin
  144.   inherited Create(False);
  145.   FPort := APort;
  146. end;
  147.  
  148. destructor TServerThread.Destroy;
  149. begin
  150.   Terminate;
  151.   WaitFor;
  152.   inherited;
  153. end;
  154.  
  155.  
  156. { TTCPThread }
  157.  
  158. procedure TTCPThread.Execute;
  159. var
  160.   str: string;
  161.   timeout: integer;
  162.   Request: TTCPRequest;
  163. begin
  164.   while (FSocket.WaitingData = 0) and (not Terminated) do
  165.     Sleep(10);
  166.  
  167.   if Terminated then
  168.     exit;
  169.  
  170.   timeout := 120000;
  171.   Request := TTCPRequest.Create;
  172.   try
  173.     str := FSocket.RecvString(timeout);
  174.  
  175.     Request.FRequest.Add(str);
  176.  
  177.     Request.FSocket := FSocket;
  178.     Request.FMethod := fetch(str, ' ');
  179.     Request.FUri := fetch(str, ' ');
  180.     Request.FProtocol := fetch(str, ' ');
  181.  
  182.     repeat
  183.       str := FSocket.RecvString(Timeout);
  184.       Request.FRequest.Add(str);
  185.     until str = '';
  186.  
  187.     if assigned(FOnRequest) then
  188.       FOnRequest(self, Request);
  189.   finally
  190.     Request.Free;
  191.   end;
  192. end;
  193.  
  194. constructor TTCPThread.Create(const ASock: TSocket; const AOnRequest: TOnRequestNotify);
  195. begin
  196.   FreeOnTerminate := True;
  197.   FSocket := TTCPBlockSocket.Create;
  198.   FSocket.Socket := aSock;
  199.   FSocket.GetSins;
  200.   FOnRequest := AOnRequest;
  201.   inherited Create(False);
  202. end;
  203.  
  204. destructor TTCPThread.Destroy;
  205. begin
  206.   Terminate;
  207.  
  208.   FSocket.Free;
  209.   inherited;
  210. end;
  211.  
  212.  
  213. end.
Regards
Christian
« Last Edit: January 27, 2019, 09:05:46 pm by ChristianH »

sash

  • Sr. Member
  • ****
  • Posts: 366
Re: TFPHTTPServer issues
« Reply #7 on: January 27, 2019, 09:47:04 pm »
I don't understand what you mean with checking if the server is available.

Usually they test if http server is up, running and accessible across network in web browser.

Also, do you understand what is Request/Response headers, Content-Range and similar things related to HTTP protocol (especially when dealing with partial streams)? If not, you should, in case you want it to be implemented with FPC.
Lazarus 2.0.10 FPC 3.2.0 x86_64-linux-gtk2 @ Ubuntu 20.04 XFCE

ChristianH

  • New Member
  • *
  • Posts: 46
Re: TFPHTTPServer issues
« Reply #8 on: January 28, 2019, 08:25:08 am »
Please don't misunderstand me, i really appreciate that you try to help me. I'm aware of content-type, range and the difference between POST, GET and also other HTTP commands are not entirely unknown to me.
The reason why i disliked the idea to build an "own" tcp/http server class is that i indeed do know what i have to implement if i want to do it right.
After i stumbled over the issue with TFPHTTPServer i wrote the class above in order to check if the problem is somewhere else. Surprisingly it worked, so i suppose i have to bite the bullet and expand the code in order to support at least the range command in order to seek inside a request.

Nevertheless thanks for your attempt to help me.

Christian

sash

  • Sr. Member
  • ****
  • Posts: 366
Re: TFPHTTPServer issues
« Reply #9 on: January 28, 2019, 11:15:34 am »
The reason why i disliked the idea to build an "own" tcp/http server class is that i indeed do know what i have to implement if i want to do it right. ....
issue with TFPHTTPServer

First, you don't need "own" TFPHTTPServer, you need to implement connection response handler with proper content-range interpretation.
The problem is that this is just my guess, because I still have no idea what's going on at your side and all my attempts to clarify details of your "issue" failed. Yet, we're discussing things completely unrelated to the actual problem.
Lazarus 2.0.10 FPC 3.2.0 x86_64-linux-gtk2 @ Ubuntu 20.04 XFCE

 

TinyPortal © 2005-2018