On Thu, 30 Jul 2009, Przemyslaw Czerpak wrote: Hi,
> BTW why did you use different stop condtions in current readRequest() > code instead of exact replication of above socket_*() code, i.e: > > cRequest := "" > nLen := 1 > cBuf := Space( 4096 ) > DO WHILE AT( CR_LF + CR_LF, cRequest ) == 0 .AND. nLen > 0 > nLen := hb_InetRecv( hSocket, @cBuf ) > cRequest += Left( cBuf, nLen ) > ENDDO > ??? I looked closer at this wole code to find the answer myslef and as I can see the version which uses socket_*() API is wrong. It can work but does not have to. cRequest := "" nLen := 1 DO WHILE AT( CR_LF + CR_LF, cRequest ) == 0 .AND. nLen > 0 nLen := socket_recv( hSocket, @cBuf ) cRequest += cBuf ENDDO In above code you do not check for additional CONTENT-LENGTH data. If you are lucky man and your sever IP buffer receive in one IP packet terminating CR_LF + CR_LF with the CONTENT-LENGTH data then it will be attached to cBuf read in last socket_recv(). If you are not so lucky, i.e. IP connection divides data into smaller peaces or data exceed single IP size and your code was too fast and read data before kernel joined IP frames so they can be accessed by single recv() then it will not work correctly. It means that this code has random behavior in all low level socket libraries and have to be fixed. It's not guarantied that single recv() returns more then 1 character and there is no guarantied that you receive in single recv() the same number of bytes as you send in single send(). The data can be routed through different networks with different transport layers so it can be divided into very small peaces and then joined by receivers. It's TCP/IP feature. You should write all code expecting the worst possible case, i.e. single byte from each recv() or joined many send() buffers. Number of bytes read by single recv() is out of programmer control and it depends on random for programmer conditions so even extensive tests cannot confirm that code is correct if it's not written to be safe for any number of bytes read by single recv(). I think you should look at Mindaugas' uhttpd2 code and function ParseRequestHeader() and take the algorithm from it. Below is fixed readRequest() from httpsrv but I think you should use more elegant solution in like in Mindaugas code for final version. Use this as temporary fix. I haven't check rest of httpsrv code but if you have any other places where you expect some strictly defined size of single socket_recv() or hb_inetRecv() then you must fix them. It may also explains some random behavior in your tests or why sometimes it was not working correctly, i.e. once per few times the CONTENT-LENGTH data was dropped or cut when socket_*() API were used. HTH. best regards, Przemek STATIC FUNCTION readRequest( hSocket, /* @ */ cRequest ) LOCAL cBuf, nLen, nPos /* receive query */ #ifdef USE_HB_INET cRequest := hb_InetRecvEndBlock( hSocket, CR_LF + CR_LF, @nLen ) #else cRequest := "" DO WHILE .T. nLen := socket_recv( hSocket, @cBuf ) IF nLen <= 0 EXIT ENDIF cRequest += cBuf IF CR_LF + CR_LF $ cRequest EXIT ENDIF ENDDO #endif /* receive CONTENT-LENGTH data */ IF nLen > 0 nPos := HB_ATI( CR_LF + "CONTENT-LENGTH:", cRequest ) IF nPos > 0 nPos := Val( Substr( cRequest, nPos + 17, 10 ) ) IF nPos > 0 #ifdef USE_HB_INET cBuf := Space( nPos ) nLen := hb_InetRecvAll( hSocket, @cBuf, nPos ) IF nLen < 0 nLen := -1 ELSE cRequest += Left( cBuf, nLen ) ENDIF #else /* we have to decrease number of bytes to read by already read * data after CR_LF + CR_LF */ nPos -= Len( cRequest ) - At( CR_LF + CR_LF, cRequest ) - 3 WHILE nPos > 0 nLen := socket_recv( hSocket, @cBuf, nPos ) IF nLen <= 0 EXIT ENDIF cRequest += cBuf nPos -= nLen ENDDO #endif ENDIF ENDIF ENDIF #ifdef DEBUG_ACTIVE hb_ToOutDebug( "readRequest(): nLen = %i, cRequest = %s \n\r", nLen, cRequest ) #endif RETURN nLen _______________________________________________ Harbour mailing list Harbour@harbour-project.org http://lists.harbour-project.org/mailman/listinfo/harbour