-2

I'm trying to write a minimal HTTP server on Windows and see the response in Chrome with http://127.0.0.1/5000. The following code works sometimes ("Hello World"), but the request fails half of the time with ERR_CONNECTION_ABORTED in Chrome (even after I restart the server). Why?

Error:

enter image description here

#include <winsock2.h>
#include <iostream>
#pragma comment(lib, "ws2_32.lib")
int main()
{
    WSADATA WSAData;
    SOCKET sock, csock;
    SOCKADDR_IN sin, csin;
    WSAStartup(MAKEWORD(2,0), &WSAData);
    sock = socket(AF_INET, SOCK_STREAM, 0);
    sin.sin_addr.s_addr = INADDR_ANY;
    sin.sin_family = AF_INET;
    sin.sin_port = htons(5000);
    bind(sock, (SOCKADDR *) &sin, sizeof(sin));
    listen(sock, 0);
    while(1)
    {
        int sinsize = sizeof(csin);
        if((csock = accept(sock, (SOCKADDR *) &csin, &sinsize)) != INVALID_SOCKET)
        {
            std::string response = "HTTP/1.1 200 OK\nConnection: close\nContent-Length: 11\n\nHello World";
            send(csock, response.c_str(), response.size(), 0);
            std::cout << "done";
            closesocket(csock);
        }
    }
    return 0;
}
Basj
  • 41,386
  • 99
  • 383
  • 673
  • 2
    It's not clear from your question what app gets errors, your app or Chrome. Your app has no one error check. Consult this question for proper socket close. https://stackoverflow.com/questions/4160347/close-vs-shutdown-socket – 273K Jun 26 '22 at 16:07
  • Thank you @273K for your comment. I edited the question to make it clearer (it is the request received by Chrome which fails indeed). – Basj Jun 26 '22 at 16:18
  • Does accept or send fail when the request fails? What does Wireshark say? – Anders Jun 26 '22 at 16:57
  • @Anders Just to be sure, what do you mean by accept or send? Looking at the code, do you know what seems problematic? – Basj Jun 26 '22 at 17:01
  • The two function calls; accept and send. – Anders Jun 26 '22 at 17:03

1 Answers1

2

You fail to read the client's request before closing the connection. This usually results in the server sending a RST back to the client, which can cause the ERR_CONNECTION_ABORTED when it is processed before the response itself was processed.

As observed by another (deleted) answer, this can be "mitigated" by adding some short delay before the connection is closed, so that the response is processed by the client.

The right fix is to read the request from the client, though.

Apart from that, your response is not valid HTTP since you use \n instead of \r\n as line end and header end.


Working solution:

#include <winsock2.h>
#include <iostream>
#define DEFAULT_BUFLEN 8192
#pragma comment(lib, "ws2_32.lib")
int main()
{
    char recvbuf[DEFAULT_BUFLEN];
    WSADATA WSAData;
    SOCKET sock, csock;
    SOCKADDR_IN sin, csin;
    WSAStartup(MAKEWORD(2,0), &WSAData);
    sock = socket(AF_INET, SOCK_STREAM, 0);
    sin.sin_addr.s_addr = INADDR_ANY;
    sin.sin_family = AF_INET;
    sin.sin_port = htons(5000);
    bind(sock, (SOCKADDR *) &sin, sizeof(sin));
    listen(sock, 0);
    while (1) 
    {
        int sinsize = sizeof(csin);
        if ((csock = accept(sock, (SOCKADDR *) &csin, &sinsize)) != INVALID_SOCKET)
        {
            recv(csock, recvbuf, DEFAULT_BUFLEN, 0);
            std::string response = "HTTP/1.0 200 OK\r\nConnection: close\r\nContent-Length: 11\r\n\r\nHello World";
            send(csock, response.c_str(), response.size(), 0);
            std::cout << "done";
            closesocket(csock);
        }
    }
    return 0;
}
Basj
  • 41,386
  • 99
  • 383
  • 673
Steffen Ullrich
  • 114,247
  • 10
  • 131
  • 172
  • Thank you for your answer. "The right fix is though to read the request by the server.": do you mean I should `read(...)` just after the `send(...)` line and before the `closesocket(...)`? If you have an example code it would be great! – Basj Jun 26 '22 at 17:25
  • @Basj: A HTTP server is supposed to read the request and then acting on it in the response. This means that the usual way is to read the request *before* the response is written. In this particular case it should not matter though as long as the *full* request is read before the socket is closed. And yes, this can be as simple as `recv(...)`. But it would be better to check if the full request is actually read and otherwise recv more. For your simple test server a single large enough `recv` is likely sufficient to prove that it helps. – Steffen Ullrich Jun 26 '22 at 18:43