TFPHTTPServer, client disconnect, "Missing HTTP protocol version in request" err lazarus / 38-Networking and Web Programming ---------------------------------------------------------------------- torumyax · 2018-03-17 06:08 I'm trying to implement an embedded HTTP server using TFPHTTPServer from fcl-web library. First, I compiled the example project which comes from fpc. simplehttpserver.pas C:\lazarus\fpc\3.0.4\source\packages\fcl-web\examples\httpserver https://github.com/alrieckert/freepascal/blob/master/packages/fcl- web/examples/httpserver/simplehttpserver.pas For testing, I accessed to the server using normal browser. After a short period of time, I get a lots of [Debugger Exception Notification] Project *** raised exception class 'EHTTPServer' with message: Missing HTTP protocol version in request At first, I had no idea why. I thought this was browser's problem and I was trying to figure out why the browser is not sending HTTP protocol version in the request. But it turns out ... it's just client browsers disconnected. http://lists.freepascal.org/pipermail/fpc- pascal/2014-April/041720.html So, looks like it's NOT about the HTTP protocol version. unit fphttpserver;  resourcestring   SErrMissingProtocol = 'Missing HTTP protocol version in request'; maybe something like SErrDisconnectedByClient = 'Disconnected by client'; And I looked for "IgnoreLostConnections" property but in vain. Try to "try .. catch" without directly editing the TFPHTTPServer ... failed. I think TFPHTTPConnection needs OnDisconnectByClient or something.. But am not really familiar with socket networking... I mean I just started lazarus a few month ago... What should I do? Also, related, the example simplehttpserver.pas gives me simplehttpserver.pas(10,49) Fatal: Cannot find wmecho used by simplehttpserver of the Project Inspector. Removing the wmecho from using fixed problem. I'm using Lazarus 1.8.2 r57369 FPC 3.0.4 x86_64-win64-win32/win64 ---------------------------------------------------------------------- torumyax · 2018-03-17 12:16 OK, I think I manage to add "OnDisconnectedByClient" to TFPHttpServer class. I just Copied fphttpserver.pp from C:\lazarus\fpc\3.0.4\source\packages\fcl-web\src\base and rename it to fphttpserver2.pas and included to a project and made some changes. It seems to be working.. at least  'Missing HTTP protocol version in request' exception won't show up every time browser disconnect itself with timeout. Also I made some change to 'Error reading data from the socket' exception, so that OnError will be called instead of exception. This will be normally called when you close browser right after you send request to the server. I attached the source. I haven't tested this much because I haven't even started my project yet. DISCLAIMER: I haven't tested on other platforms, and I don't really know what I am doing. So please let me know if I'm doing it wrong. ---------------------------------------------------------------------- Thaddy · 2018-03-17 15:42 I have absolutely no clue (well, I have...) why you did not use inheritance. There's no need to copy the unit. Simply include it and derive from the class you want to extend. ---------------------------------------------------------------------- torumyax · 2018-03-18 02:01 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  why you did not use inheritance. Well, (1) because I 'm not trying to extend it. (Sorry my English is bad.) I'm trying to fix it. (2) because this is a test to see what caused the problem and if the fix works or not and it was easier for me to just copy in this case just like git clone. (3) I'm hoping if this fix is indeed correct, some one who are much more experienced than I am could implement it. The problem is when 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 r:=FSocket.Read(FBuffer[1],ReadBufLen); returns 0, (I believe this is a Windows specific behavior.) 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   If (Pos('HTTP/',S)<>1) then    Raise EHTTPServer.CreateHelp(SErrMissingProtocol,400); this is called which is wrong and it gives us a wrong error message. So, what I did was adding (and some more..) 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     if ((r=0) and (FSocket.LastError = 0)) then      HandleDisconnectedByClient(); 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 { TFPHTTPConnection } function TFPHTTPConnection.ReadString : String;   Procedure FillBuffer;   Var    R : Integer;   begin    SetLength(FBuffer,ReadBufLen);    r:=FSocket.Read(FBuffer[1],ReadBufLen);     If r<0 then      // -Deleted      //Raise EHTTPServer.Create(SErrReadingSocket);      //       // +Added      HandleRequestError(EHTTPServer.Create(SErrReadingSocket));      //   if (r 0 )            printf("Bytes received: %d\n", iResult);        else if ( iResult == 0 )            printf("Connection closed\n");        else          printf("recv failed: %d\n", WSAGetLastError());     } while( iResult > 0 );  https://msdn.microsoft.com/en- us/library/windows/desktop/ms740121%28v=vs.85%29.aspx and this QuoteIf the remote host shuts down the Socket connection with the Shutdown method, and all available data has been received, the EndReceive method will complete immediately and return zero bytes. https://msdn.microsoft.com/en-us/library/ms145145(v=vs.110).aspx So, below would be 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      SetLength(FBuffer,ReadBufLen);    r:=FSocket.Read(FBuffer[1],ReadBufLen);     If r<0 then      HandleRequestError(EHTTPServer.Create(SErrReadingSocket));    if (r=0) then      HandleDisconnectedByClient();    if (r'') then        InterPretHeader(Result,S);    Until (S='');    Result.RemoteAddress := SocketAddrToString(FSocket.RemoteAddress);    Result.ServerPort := FServer.Port;  except    FreeAndNil(Result);    Raise;  end;end; 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 procedure TFPHTTPConnection.HandleRequest; Var  Req : TFPHTTPConnectionRequest;  Resp : TFPHTTPConnectionResponse; begin  Try    SetupSocket; // < this is for **ux. don't know     // Read headers.    Req:=ReadRequestHeaders;    ////////////////////////////////////////// //////////////////////////////////    // +Added    if not Assigned(Req) then      exit;    ///////////////////////////////////// /////////////////////////////////////// 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 fphttpserverType  TFPHTTPConnection = Class;  // +Added  ///////////// ///////////////////////////////////////////////////////////////  TDisconnectedByClientHandler = Procedure (Sender : TObject) of object;  ///////////////////////////////////////////////////////////////////// /////// 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   TFPHTTPConnection = Class(TObject)    private  // +Added  //////////// ////////////////////////////////////////////////////////////////    FOnDisconnected: TDisconnectedByClientHandler;   ///////////////////// ///////////////////////////////////////////////////////  Protected  // +Added  ////////////////////////////////////////////////////////////// //////////////    procedure HandleDisconnectedByClient(); virtual;    ////////////////////////////////////////////////////////////////////// //////  Public  // +Added  /////////////////////////////////////////// /////////////////////////////////    Property OnDisconnectedByClient : TDisconnectedByClientHandler Read FOnDisconnected Write FOnDisconnected;    ////////////////////////////////////////////////// //////////////////////////  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 procedure TFPCustomHttpServer.DoConnect(Sender: TObject; Data: TSocketStream); Var  Con : TFPHTTPConnection; begin  Con:=CreateConnection(Data);  try    Con.FServer:=Self;    Con.OnRequestError:=@HandleRequestError;    ////////////////////////// //////////////////////////////////////////////////    // +Added    Con.OnDisconnectedByClient:=@HandleDisconnectedByClient;    ////////// //////////////////////////////////////////////////////////////////    if Threaded then      CreateConnectionThread(Con)    else      begin    Con.HandleRequest;      end;  finally    if not Threaded then      Con.Free;  end;end;