1

I tried to write a simple http server using socket programming in C. I want to first try that the server could send back the HTML file without considering what kind of request is been received.

Here's the header and the body :

char httpHeader[100000] = 
"HTTP/1.1 200 OK\r\n"
"Content-Type: text/html; charset=UTF-8\r\n\r\n"
"<!DOCTYPE html>\r\n"
"<html><head><title>Testing</title></head>\r\n"
"<body><p>Testing</p></body><html>\r\n";

Here's the procedure of sending package:

while(1) {
if ( (connfd = accept(listenfd, NULL, NULL) ) < 0 ) {
    fprintf(stderr, "accept error\n");
    exit(EXIT_FAILURE);
}

if (send(connfd, httpHeader, sizeof(httpHeader), 0) == -1) {
    fprintf(stderr, "send error\n");
    exit(EXIT_FAILURE);
};

if ( close(connfd) < 0 ) {
    fprintf(stderr, "close error\n");
    exit(EXIT_FAILURE);
}
}

I bind the socket on port 8080, and using telnet to test whether it's working or not. After running the server and send request by telnet in the same machine, the client side successfully receive the whole package without any error.

But when I try to connect the server using Chrome, it failed. The GET error : "net::ERR_CONNECTION_RESET 200 (OK)" showed up. When I check the network session in DevTool, I saw that the response header is received by Chrome, showing "HTTP/1.1 200 OK Content-Type: text/html; charset=UTF-8", but did not see the HTML file.

Is the header format wrong? I check the protocol again but not sure where I do wrong.

3
  • 1
    Possible duplicate of Http client receives no response when server reads only headers from request. In short: you need to actually read the full request in the server before you send the response. Commented Oct 16, 2019 at 5:59
  • @SteffenUllrich An HTTP server is allowed to send a response before fully reading the request, but it must be a properly formatted response, and only when sending a failure response (see RFC 2616 section 8.2.2). Commented Oct 16, 2019 at 23:35
  • @RemyLebeau: ok, the more correct explanation is that the request should be read in full before closing the socket. This is also what the question I've linked to shows. Commented Oct 17, 2019 at 4:10

2 Answers 2

4

Such kind of problems typically occur when the server is closing the connection while there are still unread data from the client. In your case the server is closing the connection without reading the request from the client. But even if you've read the full request the problem might still happen since the client might have sent multiple requests (HTTP pipelining).

The HTTP standard even has a recommendation how a proper close should be done and specifically addresses the problem you get. From RFC 7230 section 6.6 "Tear-down":

If a server performs an immediate close of a TCP connection, there is a significant risk that the client will not be able to read the last HTTP response. If the server receives additional data from the client on a fully closed connection, such as another request that was sent by the client before receiving the server's response, the server's TCP stack will send a reset packet to the client; unfortunately, the reset packet might erase the client's unacknowledged input buffers before they can be read and interpreted by the client's HTTP parser.

To avoid the TCP reset problem, servers typically close a connection in stages. First, the server performs a half-close by closing only the write side of the read/write connection. The server then continues to read from the connection until it receives a corresponding close by the client, or until the server is reasonably certain that its own TCP stack has received the client's acknowledgement of the packet(s) containing the server's last response. Finally, the server fully closes the connection.

Apart from that: it is strongly recommended (SHOULD in the standard) that you clearly mark the size of the body either by using a Content-length header or by using chunked transfer encoding - instead of just closing the connection. It is also strongly recommended that you signal the client that no more requests will be accepted on this connection by adding a Connection: close header.

In general: HTTP is way more complex then one might think just by looking at a few examples. There is a standard which describes how clients and server should behave and there is a reason that this standard is long. Please follow it nevertheless if you intend to implement your own HTTP stack instead of just using existing implementations.

Sign up to request clarification or add additional context in comments.

Comments

0

I’m afraid this isn’t as tested as I’d like it to be, but what strikes me is that you’re not listening to the client before sending data to it. My hypothesis is that Chrome may be detecting that somehow so /maybe/ adding a receive might make a difference.

To be sure though, you could try using Wireshark to monitor the request and compare with the traffic sent request to a full server, which should help diagnose differences.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.