Search code examples
csocketswebserver

Why web server should clear away socket receive buffer before sending response?


I am studying a tiny web server, it can receive GET-request from browser and return an html file. The serve_file-function sends response messages to browser, and the get_line-function gets a line from socket buffer. I don't know why must read & discard request headers. I try to comment the two lines and the browser show a connection reset page. I guess the server socket receive buffer is full, but I don't know the specific reason. Could anyone explain it?
source code

/* Send a regular file to the client.  Use headers, and report */

void serve_file(int client, const char *filename) {
    FILE *resource = NULL;
    int numchars = 1;
    char buf[1024];

    buf[0] = 'A'; buf[1] = '\0';

    //why?
    while ((numchars > 0) && strcmp("\n", buf))  /* read & discard request headers */
        numchars = get_line(client, buf, sizeof(buf));

    resource = fopen(filename, "r");
    if (resource == NULL)
        not_found(client);
    else {
        headers(client, filename); //send headers to tcp buffer
        cat(client, resource); //send index.html to tcp buffer
    }
    fclose(resource);
}

Solution

  • The behavior you observed is a standard socket behavior.

    If data received from a peer has not been read by the application and the application calls close on the socket then OS does not do the usual TCP connection finalization. It resets the connection immediately instead finalization. If application really wants gracefully close the connection when there is unread data in the received buffer then it must call shutdown(socket, SHUT_WR) before calling close.

    And why is the socket API implemented that way? Because this handling can avoid dos attacks. If close executes normal TCP session finalization then following attack is possible:

    • A malicious client opens a TCP connection
    • The server accepts the connection and starts receiving data
    • The client sends a continuous stream of let say random data
    • The server quickly detects that received data is wrong and calls close on the socket.
    • close just sends a FIN and then waits for the peer close. Server resources remain allocated because normal FIN just close the direction towards the client. The client still may send data and the recv buffer would not be freed.

    But when the close initiates connection reset then resources related to this TCP connection is freed immediately. A dos attack is then a bit more complicated.

    See https://www.spinics.net/lists/linux-c-programming/msg01345.html for more details.