Reputation: 33
I have an assignment to write a HTTP server using c. The server reads requests and sends a response accordingly. When the request is a path to a file I need to read the file content and send it as a response to the client.
There is no limit for the file size so I read it by chunks and send the response by chunks. The teacher said that if a recv/send call fails after already writing part of the response it is OK to close the connection and continue, but the client should be notified that the response wasn't sent correctly.
My question is, assuming a send call fails, trying to send a message that the response wasn't sent correctly will probably fail again. How can I notify the client that there was an error sending the response otherwise?
Upvotes: 3
Views: 801
Reputation: 182743
Your teacher is not saying that your server should notify the client, but that the client should (already) be notified by recv()
and that, therefore, there's nothing special you need to do on the server side except close the connection.
1 That is, assuming your teacher is not confused.
Upvotes: 2
Reputation: 595349
The teacher said that if a recv/send call fails after already writing part of the response it is OK to close the connection and continue, but the client should be notified that the response wasn't sent correctly.
First, you should not be calling recv()
once you start send()
'ing a response, until the response has been sent in full. You cannot start recv()
'ing the next request until after the current response is finished.
Second, if recv()
or send()
fails for any reason, you MUST close the current connection, there is no other option.
My question is, assuming a send call fails, trying to send a message that the response wasn't sent correctly will probably fail again. How can I notify the client that there was an error sending the response otherwise?
You cannot, nor should you be trying to. If that is what your teacher is telling you to do, then either you are misunderstanding what your teacher is actually saying, or your teacher does not understand how HTTP actually works.
When a connection failure occurs, closing the connection is the only option. If the client has not already failed on its side, it will (eventually) detect the closure (or timeout) and will know the response failed by virtue of the fact that the response was not received in full. How it detects the end of the response depends on how the response is formatted (see RFC 2616 Section 4.4 Message Length for details).
Do be careful - there is ONE condition where a connection closure is not an indication of a failed response! If the server:
is NOT responding to a HEAD
request;
is NOT responding with a 1xx
, 204
, or 304
reply code;
is NOT sending either a Content-Length
or Transfer-Encoding: identity
response header;
is NOT sending the response body in multipart/byteranges
format;
Then the response is completed by the server closing the connection gracefully (an intentional close by the server using shutdown(SD_SEND)
or shutdown(SD_BOTH)
, which sends a TCP packet with the FIN
flag enabled. On some platforms, including Windows, close()
/closesocket()
will perform an implicit shutdown, but it is best to be explicit).
The client has to look at the response headers to detect how the response is being sent and act accordingly. If it falls into this last condition, only a graceful disconnect is to be treated as success. Any other kind of disconnect is to be treated as a failure. Because of this, a server should always send a Content-Length
or Transfer-Encoding
header, at a minimum. It avoids the ambiguity of what a disconnect represents.
Upvotes: 0
Reputation: 310840
Your teacher's statement doesn't make sense as stated, or is ambiguous. HTTP status codes precede the payload. If there is an error writing the payload there is no way of informing the peer other than resetting the connection, if you know how to do that, or if (as is most probable) it has already happened as a result of the sending error.
Upvotes: 1