HTTP GET server in C, long waiting (TTFB)

452 views Asked by At

I am trying to build some http server. My procedure is easy: I am getting http request, waiting to its end and send my response after that. Unfortunately there is a gap for a couple seconds between receiving a browser header and receiving an empty buffer from recv to detect that is the end and now I can send a response.

socklen_t clientAddressLength;
int clientSocket = accept(socket, (struct sockaddr *)&socketAddress, &clientAddressLength);
if (clientSocket < 0) {ESP_LOGI(TAG, "failed 3!"); goto network_task_finish;}

if (setsockopt(clientSocket, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout)) < 0)
   ESP_LOGI(TAG, "Cannot Set SO_SNDTIMEO for socket");
if (setsockopt(clientSocket, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)) < 0)
   ESP_LOGI(TAG, "Cannot Set SO_RCVTIMEO for socket");
while (1) {
   ret = recv(clientSocket, recv_buf, NETWORK_RECV_BUF_LEN - 1, 0);
   if (ret <= 0) break;
   if (ret <= 2 && *recv_buf == '\r') break;
   if (ret < NETWORK_RECV_BUF_LEN)
      recv_buf[ret] = '\0';
   ESP_LOGI(TAG, "RECV");
   if (strstr(recv_buf," HTTP/")) {
      char *ptr = recv_buf;
      if (strncmp(recv_buf, "GET ", 4) == 0)
         ptr += 4;
      else if (strncmp(recv_buf, "POST ", 4) == 0)
         ptr += 5;
      else
         continue;
      ESP_LOGI(TAG, "HEADER!");
   }
}

ESP_LOGI(TAG, "RESPONSE");
send(clientSocket, "HTTP/1.1 200 OK\r\n", 17, 0);
send(clientSocket, "Content-Type: text/html\r\n", 25, 0);
send(clientSocket, "Connection: close\r\n", 19, 0);
send(clientSocket, "\r\n", 2, 0);
send(clientSocket, "WORKS", 5, 0);
ESP_LOGI(TAG, "SEND");

log:

server: RECV
server: HEADER!
... long time ...
server: RESPONSE
server: SEND

What is an accurate way to handle the request? Maybe I dont have to wait for its end or I can detect the header end other way

1

There are 1 answers

0
Some programmer dude On BEST ANSWER

The problem doesn't seem to be that you don't know how the request ends (with a single blank line) but in how you check for it.

You have to remember that HTTP is built on top of TCP, and that TCP is a streaming protocol without message boundaries or fixed-size packets.

That means you can get the whole request in a single recv call, or two, or three or more. And you only detect the end of the header if a single recv call gives you just the empty line and nothing else, which is a very unlikely event. This might also give you a false end-of-request, as the newline might be in the middle of the header.

Instead I recommend you redesign your receiving code to call recv in a loop and append to a buffer. Then in the loop check if the last four bytes are the double newline sequence (\r\n\r\n). If it is, then you have found the end of the request and can break the loop and continue with processing the request and actually check what is wanted (GET or POST etc.).