Forum > Networking and Web Programming

TFPHTTPServer, client disconnect, "Missing HTTP protocol version in request" err

(1/2) > >>

torumyax:
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:
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:
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:

--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} --- 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  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---r:=FSocket.Read(FBuffer[1],ReadBufLen);
returns 0, (I believe this is a Windows specific behavior.)



--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---  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  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---    if ((r=0) and (FSocket.LastError = 0)) then      HandleDisconnectedByClient();



--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---{ 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<ReadBuflen) then      SetLength(FBuffer,r);     // +Added    if ((r=0) and (FSocket.LastError = 0)) then      HandleDisconnectedByClient();    //  end; 
I have no idea what side effects it might have. And I'm sure there are some other cases when this condition ((r=0) and (FSocket.LastError = 0)) might be met other than "client disconnect"..

But I vaguely remember when I use TCPClient in .net, TCPClient socket/Networkstream never returned 0 (callback never called if there is no data to read) as long as it's connected.

I could simply ignore the client disconnect, but

--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---it IS an error condition (client went away unexpectedly) and you should be aware of it.
So, please some one ...


Please see this thread.

http://lists.freepascal.org/pipermail/fpc-pascal/2014-April/041715.html

http://lists.freepascal.org/pipermail/fpc-pascal/2014-April/041719.html


torumyax:
I've found a similar code in c++.


--- Code: C  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---    // Receive until the peer closes the connection    do {         iResult = recv(ConnectSocket, recvbuf, recvbuflen, 0);        if ( iResult > 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


--- Quote ---If 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.
--- End quote ---

https://msdn.microsoft.com/en-us/library/ms145145(v=vs.110).aspx


So, below would be fine?


--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---     SetLength(FBuffer,ReadBufLen);    r:=FSocket.Read(FBuffer[1],ReadBufLen);     If r<0 then      HandleRequestError(EHTTPServer.Create(SErrReadingSocket));    if (r=0) then      HandleDisconnectedByClient();    if (r<ReadBuflen) then      SetLength(FBuffer,r); 

Navigation

[0] Message Index

[#] Next page

Go to full version