TFPHTTPServer issues lazarus / 38-Networking and Web Programming ---------------------------------------------------------------------- ChristianH · 2019-01-26 13:22 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 · 2019-01-26 14:15 Is server threaded? ---------------------------------------------------------------------- ChristianH · 2019-01-26 14:19 Yes, i tried it with and without threaded. The behavior is the same. Christian ---------------------------------------------------------------------- sash · 2019-01-26 14:43 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. ---------------------------------------------------------------------- ChristianH · 2019-01-27 12:29 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 · 2019-01-27 16:02 And again, The first thing you should check is availability of server Quotewhat about simple plain files served to browser? then Quotedetailed log (from of your server app), with Request (at least) and Response headers included. ---------------------------------------------------------------------- ChristianH · 2019-01-27 19:11 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][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i unit UWebServer; {$mode objfpc}{$H+} interface uses  Classes, SysUtils, blcksock, synsock; type  { TTCPRequest }  TTCPRequest = class  private    FRequest: TStringList;    FSocket: TTCPBlockSocket;    FStream: TStream;    FContentType: string;    FSent: Boolean;     FMethod: string;    FProtocol: string;    FURI: string;  public    constructor Create;    destructor Destroy; override;     procedure Send;     property Method: string read FMethod;    property Protocol: string read FProtocol;    property URI: string read FURI;     property Stream: TStream read FStream write FStream;    property ContentType: string read FContentType write FContentType;    property Request: TStringList read FRequest;  end;   TOnRequestNotify = procedure(Sender: TObject; const ARequest: TTCPRequest) of object;  TOnErrorNotify = procedure(Sender: TObject; const AError: string) of object;   { TTCPThread }  TTCPThread = class(TThread)  private    FSocket: TTCPBlockSocket;    FOnRequest: TOnRequestNotify;  protected    procedure Execute; override;  public    constructor Create(const ASock: TSocket; const AOnRequest: TOnRequestNotify);    destructor Destroy; override;   end;   { TServerThread }  TServerThread = class(TThread)  private    FOnError: TOnErrorNotify;    FOnRequest: TOnRequestNotify;     FPort: integer;  protected    procedure Execute; override;  public    constructor Create(const APort: integer);    destructor Destroy; override;     property OnError: TOnErrorNotify read FOnError write FOnError;    property OnRequest: TOnRequestNotify read FOnRequest write FOnRequest;  end; implementation uses Synautil; { TTCPRequest }constructor TTCPRequest.Create;begin  FContentType := 'application/octet-stream';  FStream := nil;  FRequest := TStringList.Create;end; destructor TTCPRequest.Destroy;begin  Send;  FRequest.Free;  inherited;end; procedure TTCPRequest.Send;begin  if FSent then exit;  FSent := true;  if not assigned(FSocket) then    exit;   if assigned(FStream) then  begin    FSocket.SendString('HTTP/1.0 200' + CRLF);    FSocket.SendString('Content-type: '+ FContentType + CRLF);    FSocket.SendString('Content-length: ' + IntToStr(FStream.Size) + CRLF);    FSocket.SendString('Connection: close' + CRLF);    FSocket.SendString('Date: ' + Rfc822DateTime(now) + CRLF);    FSocket.SendString('Server: Synapse TCP' + CRLF);    FSocket.SendString('' + CRLF);    FSocket.SendStreamRaw(FStream);  end  else    FSocket.SendString('HTTP/1.0 404' + CRLF);end; { TServerThread } procedure TServerThread.Execute;var  ListenerSocket: TTCPBlockSocket;begin  ListenerSocket := TTCPBlockSocket.Create;  if (ListenerSocket.LastError <> 0) and assigned(FOnError) then    FOnError(self, ListenerSocket.GetErrorDescEx);   with ListenerSocket do  begin    CreateSocket;    if (LastError <> 0) and assigned(FOnError) then      FOnError(self, GetErrorDescEx);    Family := SF_IP4;    setLinger(True, 10000);    bind('0.0.0.0', IntToStr(FPort));    listen;     while not terminated do    begin    if (CanRead(100)) and (LastError = 0) then        TTCPThread.Create(Accept, FOnRequest);      sleep(10);    end;  end;  ListenerSocket.Free;end; constructor TServerThread.Create(const APort: integer);begin  inherited Create(False);  FPort := APort;end; destructor TServerThread.Destroy;begin  Terminate;  WaitFor;  inherited;end;  { TTCPThread } procedure TTCPThread.Execute;var  str: string;  timeout: integer;  Request: TTCPRequest;begin  while (FSocket.WaitingData = 0) and (not Terminated) do    Sleep(10);   if Terminated then    exit;   timeout := 120000;  Request := TTCPRequest.Create;  try    str := FSocket.RecvString(timeout);     Request.FRequest.Add(str);     Request.FSocket := FSocket;    Request.FMethod := fetch(str, ' ');    Request.FUri := fetch(str, ' ');    Request.FProtocol := fetch(str, ' ');     repeat      str := FSocket.RecvString(Timeout);      Request.FRequest.Add(str);    until str = '';     if assigned(FOnRequest) then      FOnRequest(self, Request);  finally    Request.Free;  end;end; constructor TTCPThread.Create(const ASock: TSocket; const AOnRequest: TOnRequestNotify);begin  FreeOnTerminate := True;  FSocket := TTCPBlockSocket.Create;  FSocket.Socket := aSock;  FSocket.GetSins;  FOnRequest := AOnRequest;  inherited Create(False);end; destructor TTCPThread.Destroy;begin  Terminate;   FSocket.Free;  inherited;end;  end.Regards Christian ---------------------------------------------------------------------- sash · 2019-01-27 20:47 Quote from: ChristianH on January 27, 2019, 08:11:39 pmI 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. ---------------------------------------------------------------------- ChristianH · 2019-01-28 07:25 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 · 2019-01-28 10:15 Quote from: ChristianH on January 28, 2019, 08:25:08 amThe 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.