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
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 singlerecv
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
orPOST
etc.).