From cfc056018c739403c0ba0d5c502455e069bd9e10 Mon Sep 17 00:00:00 2001 From: "hrushikesh.bhosale" Date: Mon, 15 Sep 2025 11:37:30 +0530 Subject: [PATCH] fix(esp_http_server): Fix async requests on same socket blocking issue 1. In async requests, if the two or more requests are made on same socket then it used to block the second request. 2. The main thread is used to block on select call. And there done no FD_SET for particular fd. Closes https://github.com/espressif/esp-idf/issues/16998 --- .../esp_http_server/src/esp_httpd_priv.h | 13 +++++++++++++ components/esp_http_server/src/httpd_main.c | 9 --------- components/esp_http_server/src/httpd_txrx.c | 18 ++++++++++++++++++ 3 files changed, 31 insertions(+), 9 deletions(-) diff --git a/components/esp_http_server/src/esp_httpd_priv.h b/components/esp_http_server/src/esp_httpd_priv.h index 47591e8434..334642da65 100644 --- a/components/esp_http_server/src/esp_httpd_priv.h +++ b/components/esp_http_server/src/esp_httpd_priv.h @@ -37,6 +37,19 @@ extern "C" { /* Formats a log string to prepend context function name */ #define LOG_FMT(x) "%s: " x, __func__ +/** + * @brief Control message data structure for internal use. Sent to control socket. + */ +struct httpd_ctrl_data { + enum httpd_ctrl_msg { + HTTPD_CTRL_SHUTDOWN, + HTTPD_CTRL_WORK, + HTTPD_CTRL_MAX, + } hc_msg; + httpd_work_fn_t hc_work; + void *hc_work_arg; +}; + /** * @brief Thread related data for internal use */ diff --git a/components/esp_http_server/src/httpd_main.c b/components/esp_http_server/src/httpd_main.c index bc85c9e470..6468bcdab7 100644 --- a/components/esp_http_server/src/httpd_main.c +++ b/components/esp_http_server/src/httpd_main.c @@ -134,15 +134,6 @@ exit: return ESP_FAIL; } -struct httpd_ctrl_data { - enum httpd_ctrl_msg { - HTTPD_CTRL_SHUTDOWN, - HTTPD_CTRL_WORK, - } hc_msg; - httpd_work_fn_t hc_work; - void *hc_work_arg; -}; - esp_err_t httpd_queue_work(httpd_handle_t handle, httpd_work_fn_t work, void *arg) { if (handle == NULL || work == NULL) { diff --git a/components/esp_http_server/src/httpd_txrx.c b/components/esp_http_server/src/httpd_txrx.c index 475eb84fea..b7c2c939f5 100644 --- a/components/esp_http_server/src/httpd_txrx.c +++ b/components/esp_http_server/src/httpd_txrx.c @@ -12,6 +12,7 @@ #include #include "esp_httpd_priv.h" #include +#include "ctrl_sock.h" static const char *TAG = "httpd_txrx"; @@ -699,6 +700,11 @@ esp_err_t httpd_req_async_handler_complete(httpd_req_t *r) return ESP_ERR_INVALID_ARG; } + // Get server handle and control socket info before freeing the request + struct httpd_data *hd = (struct httpd_data *) r->handle; + int msg_fd = hd->msg_fd; + int port = hd->config.ctrl_port; + struct httpd_req_aux *ra = r->aux; ra->sd->for_async_req = false; free(ra->scratch); @@ -709,6 +715,18 @@ esp_err_t httpd_req_async_handler_complete(httpd_req_t *r) free(r->aux); free(r); + // Send a dummy control message(httpd_ctrl_data) to unblock the main HTTP server task from the select() call. + // Since the current connection FD was marked as inactive for async requests, the main task + // will now re-add this FD to its select() descriptor list. This ensures that subsequent requests + // on the same FD are processed correctly + struct httpd_ctrl_data msg = {.hc_msg = HTTPD_CTRL_MAX}; + int ret = cs_send_to_ctrl_sock(msg_fd, port, &msg, sizeof(msg)); + if (ret < 0) { + ESP_LOGW(TAG, LOG_FMT("failed to send socket notification")); + return ESP_FAIL; + } + + ESP_LOGD(TAG, LOG_FMT("socket notification sent")); return ESP_OK; }