1

I am a creating a very simple server that accepts http request from Browser(Safari) and responding some dump HTTP response back such as "Hello World" Message.

My program was blocked on the recv() function because it doesn't know whether the the client(browser) finish sending the HTTP request and recv() is a blocking function. (A very typical question)

The most popular answer I found is to send the length of the message before sending the message. This solution is good but it doesn't work for me because I have no control on what is being sent from the client. And as far as I know, the browser does not send any message length before sending the real message.

The second most popular answer to to use asy I/O such as select() or poll(). But, personally, I don't think it is really a good strategy because once I had already received all the request message from the client, then, of course, I would like to go to the next step to handle the request. Why would I still waste my time and resource to wait for something that will never come even though it is not blocking anymore? (Creating threads poses similar question)

The solution I came up with is to check whether the size of the message received equal to the buffer size. For example, let's say I set the recvBufferSize to be 32 and the total size of the request message is 70. Then I will receive three packets of size 32, 32, 6 respectively. I can tell that the client finish sending the request because the last packet's size is not equal to the recvBuffersize(32).

However, as you can see, problems occurs when the request message's size is 64/96/128......

Other approaches may be like setting timeout, but I am not sure whether they are good or not.

And I want to build all the thing by myself so I may not be interested in any library such as zeromq or Boost.Asio

Can some people give some advice on my approach or provide some other better ways to solve the problem? Thanks a lot!

hclee
  • 35
  • 5
  • 1
    Your approach does not work for any size, you have no guarantee that your recv calls will get 32/32/6 bytes as in your example. You could get 20/12/16/16/3/3. – Mat Jan 10 '15 at 07:09
  • 1
    O yes!!!, you are right. I didn't think about that. I am actually looking for the best approaches and which one do you prefer? check the length before or asy I/O or timeout or anything else ? – hclee Jan 10 '15 at 07:22
  • HTTP is a TCP protocol. Which implements a stream, it does not use "messages". The number of bytes you get from recv() is completely arbitrary, just not 0. – Hans Passant Jan 10 '15 at 07:51
  • @HansPassant On the contrary. HTTP consists of request messages and response messages, and they are both well-defined and well-delimited. What applies to TCP itself doesn't necessarily apply to protocols layered over it. – user207421 Jan 10 '15 at 09:35
  • There is plenty of library support available for HTTP and anybody would be unwise to not use it. But as long as you are doing it yourself with recv() then it is entirely up to you to parse the transfer length and call recv() as often as necessary to get the entire response. – Hans Passant Jan 10 '15 at 09:43

1 Answers1

3

If you're implementing the HTTP protocol you need to study the HTTP RFCs. There are several different ways you can know the request length, starting with the Content-length header, and the combined lengths of the chunks if the client is using chunked transfer encoding.

user207421
  • 305,947
  • 44
  • 307
  • 483
  • Thanks for your reply. However, all the messages I received from the client is like this and no length is mentioned at all GET /Streaming/testlist.m3u8 HTTP/1.1\n Host: 1xx.xx.xx.xxx:8889 Accept-Encoding: gzip, deflate Accept:text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 User-Agent: Mozilla/5.0 (iPad; CPU OS 7_0_4 like Mac OS X) AppleWebKit/537.51.1 (KHTML, like Gecko) Version/7.0 Mobile/11B554a Safari/9537.53 Accept-Language: zh-tw DNT: 1 Connection: keep-alive – hclee Jan 10 '15 at 07:15
  • 2
    So that's the request. If a GET request ends with a blank line I believe that's the end of it. But don't rely on me, read the RFC. However I would note that that isn't valid HTTP. The line terminator should be \r\n, and there should be one after every header. If you can't rely on the client, you have a much bigger problem than can possibly be answered here. – user207421 Jan 10 '15 at 07:21
  • 1
    For completeness a reference to the latest HTTP RFCs (723X): http://www.w3.org/Protocols/ – alk Jan 10 '15 at 07:35
  • "The presence of a message-body in a request is signaled by the inclusion of a Content-Length or Transfer-Encoding header field in the request's message-headers." If neither of those headers are present, no body is present, so stop reading when the blank line following the headers is reached. Otherwise, read the body based on the length/encoding specified. "A server SHOULD read and forward a message-body on any request; if the request method does not include defined semantics for an entity-body, then the message-body SHOULD be ignored when handling the request." – Remy Lebeau Jan 10 '15 at 18:25