From 9b14abc1f5b7ceef78debce5164f6949e2026ab6 Mon Sep 17 00:00:00 2001 From: "nilesh.kale" Date: Wed, 30 Jul 2025 10:33:59 +0530 Subject: [PATCH 1/2] feat(esp_http_client): handle error while reading data from server This commit updated API esp_http_cleint_perform() to handle error and dispatched error event if any error occured whiling reading data from server. --- components/esp_common/src/esp_err_to_name.c | 14 ++++++ components/esp_http_client/esp_http_client.c | 43 ++++++++++++++++--- .../esp_http_client/include/esp_http_client.h | 10 +++++ 3 files changed, 61 insertions(+), 6 deletions(-) diff --git a/components/esp_common/src/esp_err_to_name.c b/components/esp_common/src/esp_err_to_name.c index 3fe660c929..93c19275ac 100644 --- a/components/esp_common/src/esp_err_to_name.c +++ b/components/esp_common/src/esp_err_to_name.c @@ -656,6 +656,20 @@ static const esp_err_msg_t esp_err_msg_table[] = { # endif # ifdef ESP_ERR_HTTP_CONNECTION_CLOSED ERR_TBL_IT(ESP_ERR_HTTP_CONNECTION_CLOSED), /* 28680 0x7008 Read FIN from peer and the connection closed */ +# endif +# ifdef ESP_ERR_HTTP_NOT_MODIFIED + ERR_TBL_IT(ESP_ERR_HTTP_NOT_MODIFIED), /* 28681 0x7009 HTTP 304 Not Modified, no update available */ +# endif +# ifdef ESP_ERR_HTTP_RANGE_NOT_SATISFIABLE + ERR_TBL_IT(ESP_ERR_HTTP_RANGE_NOT_SATISFIABLE), /* 28682 0x700a HTTP 416 Range Not Satisfiable, + requested range in header is incorrect */ +# endif +# ifdef ESP_ERR_HTTP_READ_TIMEOUT + ERR_TBL_IT(ESP_ERR_HTTP_READ_TIMEOUT), /* 28683 0x700b HTTP data read timeout */ +# endif +# ifdef ESP_ERR_HTTP_INCOMPLETE_DATA + ERR_TBL_IT(ESP_ERR_HTTP_INCOMPLETE_DATA), /* 28684 0x700c Incomplete data received, less than + Content-Length or last chunk */ # endif // components/esp-tls/esp_tls_errors.h # ifdef ESP_ERR_ESP_TLS_BASE diff --git a/components/esp_http_client/esp_http_client.c b/components/esp_http_client/esp_http_client.c index 1bde313fa6..d13bd15f85 100644 --- a/components/esp_http_client/esp_http_client.c +++ b/components/esp_http_client/esp_http_client.c @@ -1334,7 +1334,7 @@ int esp_http_client_read(esp_http_client_handle_t client, char *buffer, int len) esp_err_t esp_http_client_perform(esp_http_client_handle_t client) { - esp_err_t err; + esp_err_t err = ESP_FAIL; do { if (client->process_again) { esp_http_client_prepare(client); @@ -1409,23 +1409,53 @@ esp_err_t esp_http_client_perform(esp_http_client_handle_t client) return err; } while (client->response->is_chunked && !client->is_chunk_complete) { - if (esp_http_client_get_data(client) <= 0) { + int ret = esp_http_client_get_data(client); + if (ret <= 0) { if (client->is_async && errno == EAGAIN) { return ESP_ERR_HTTP_EAGAIN; } + if (client->connection_info.method != HTTP_METHOD_HEAD && !client->is_chunk_complete) { + ESP_LOGE(TAG, "Incomplete chunked data received %d", ret); + + if (ret == ESP_ERR_TCP_TRANSPORT_CONNECTION_TIMEOUT) { + err = ESP_ERR_HTTP_READ_TIMEOUT; + } else if (ret == ESP_ERR_TCP_TRANSPORT_CONNECTION_CLOSED_BY_FIN) { + err = ESP_ERR_HTTP_CONNECTION_CLOSED; + } else { + err = ESP_ERR_HTTP_INCOMPLETE_DATA; + } + } ESP_LOGD(TAG, "Read finish or server requests close"); break; } } while (client->response->data_process < client->response->content_length) { - if (esp_http_client_get_data(client) <= 0) { + int ret = esp_http_client_get_data(client); + if (ret <= 0) { if (client->is_async && errno == EAGAIN) { return ESP_ERR_HTTP_EAGAIN; } + if (client->connection_info.method != HTTP_METHOD_HEAD && client->response->data_process < client->response->content_length) { + ESP_LOGE(TAG, "Incomplete data received, ret=%d, %"PRId64"/%"PRId64" bytes", ret, client->response->data_process, client->response->content_length); + + if (ret == ESP_ERR_TCP_TRANSPORT_CONNECTION_TIMEOUT) { + err = ESP_ERR_HTTP_READ_TIMEOUT; + } else if (ret == ESP_ERR_TCP_TRANSPORT_CONNECTION_CLOSED_BY_FIN) { + err = ESP_ERR_HTTP_CONNECTION_CLOSED; + } else { + err = ESP_ERR_HTTP_INCOMPLETE_DATA; + } + } ESP_LOGD(TAG, "Read finish or server requests close"); break; } } + + if (err != ESP_OK) { + http_dispatch_event(client, HTTP_EVENT_ERROR, esp_transport_get_error_handle(client->transport), 0); + http_dispatch_event_to_event_loop(HTTP_EVENT_ERROR, &client, sizeof(esp_http_client_handle_t)); + } + http_dispatch_event(client, HTTP_EVENT_ON_FINISH, NULL, 0); http_dispatch_event_to_event_loop(HTTP_EVENT_ON_FINISH, &client, sizeof(esp_http_client_handle_t)); @@ -1440,11 +1470,12 @@ esp_err_t esp_http_client_perform(esp_http_client_handle_t client) } } break; - default: + default: break; } - } while (client->process_again); - return ESP_OK; + } while (client->process_again && err == ESP_OK); + + return err; } int64_t esp_http_client_fetch_headers(esp_http_client_handle_t client) diff --git a/components/esp_http_client/include/esp_http_client.h b/components/esp_http_client/include/esp_http_client.h index 7a127fb315..088a57f00a 100644 --- a/components/esp_http_client/include/esp_http_client.h +++ b/components/esp_http_client/include/esp_http_client.h @@ -245,6 +245,10 @@ typedef enum { #define ESP_ERR_HTTP_CONNECTING (ESP_ERR_HTTP_BASE + 6) /*!< HTTP connection hasn't been established yet */ #define ESP_ERR_HTTP_EAGAIN (ESP_ERR_HTTP_BASE + 7) /*!< Mapping of errno EAGAIN to esp_err_t */ #define ESP_ERR_HTTP_CONNECTION_CLOSED (ESP_ERR_HTTP_BASE + 8) /*!< Read FIN from peer and the connection closed */ +#define ESP_ERR_HTTP_NOT_MODIFIED (ESP_ERR_HTTP_BASE + 9) /*!< HTTP 304 Not Modified, no update available */ +#define ESP_ERR_HTTP_RANGE_NOT_SATISFIABLE (ESP_ERR_HTTP_BASE + 10) /*!< HTTP 416 Range Not Satisfiable, requested range in header is incorrect */ +#define ESP_ERR_HTTP_READ_TIMEOUT (ESP_ERR_HTTP_BASE + 11) /*!< HTTP data read timeout */ +#define ESP_ERR_HTTP_INCOMPLETE_DATA (ESP_ERR_HTTP_BASE + 12) /*!< Incomplete data received, less than Content-Length or last chunk */ /** * @brief Start a HTTP session @@ -282,6 +286,12 @@ esp_http_client_handle_t esp_http_client_init(const esp_http_client_config_t *co * @return * - ESP_OK on successful * - ESP_FAIL on error + * - ESP_ERR_HTTP_CONNECTING is timed-out before connection is made + * - ESP_ERR_HTTP_WRITE_DATA is timed-out before request fully sent + * - ESP_ERR_HTTP_EAGAIN is timed-out before any data was ready + * - ESP_ERR_HTTP_READ_TIMEOUT if read operation times out + * - ESP_ERR_HTTP_INCOMPLETE_DATA if read operation returns less data than expected + * - ESP_ERR_HTTP_CONNECTION_CLOSED if server closes the connection */ esp_err_t esp_http_client_perform(esp_http_client_handle_t client); From e4e2f88566794f0c07b08037fa840370ccc5735c Mon Sep 17 00:00:00 2001 From: "nilesh.kale" Date: Fri, 29 Aug 2025 11:24:54 +0530 Subject: [PATCH 2/2] fix(esp_http_client): fix dispatching of finish event condition This commit updates the condition for dispatching of FINISH event. With this, FINISH event will be dispatched after complete data is read. Closes https://github.com/espressif/esp-idf/issues/17437 --- components/esp_http_client/esp_http_client.c | 6 +++--- components/esp_http_client/include/esp_http_client.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/components/esp_http_client/esp_http_client.c b/components/esp_http_client/esp_http_client.c index d13bd15f85..cdfa0a3ab7 100644 --- a/components/esp_http_client/esp_http_client.c +++ b/components/esp_http_client/esp_http_client.c @@ -1454,11 +1454,11 @@ esp_err_t esp_http_client_perform(esp_http_client_handle_t client) if (err != ESP_OK) { http_dispatch_event(client, HTTP_EVENT_ERROR, esp_transport_get_error_handle(client->transport), 0); http_dispatch_event_to_event_loop(HTTP_EVENT_ERROR, &client, sizeof(esp_http_client_handle_t)); + } else { + http_dispatch_event(client, HTTP_EVENT_ON_FINISH, NULL, 0); + http_dispatch_event_to_event_loop(HTTP_EVENT_ON_FINISH, &client, sizeof(esp_http_client_handle_t)); } - http_dispatch_event(client, HTTP_EVENT_ON_FINISH, NULL, 0); - http_dispatch_event_to_event_loop(HTTP_EVENT_ON_FINISH, &client, sizeof(esp_http_client_handle_t)); - client->response->buffer->raw_len = 0; if (!http_should_keep_alive(client->parser)) { ESP_LOGD(TAG, "Close connection"); diff --git a/components/esp_http_client/include/esp_http_client.h b/components/esp_http_client/include/esp_http_client.h index 088a57f00a..1f6c388467 100644 --- a/components/esp_http_client/include/esp_http_client.h +++ b/components/esp_http_client/include/esp_http_client.h @@ -40,7 +40,7 @@ typedef enum { and will be deprecated in future versions esp-idf */ HTTP_EVENT_ON_HEADER, /*!< Occurs when receiving each header sent from the server */ HTTP_EVENT_ON_DATA, /*!< Occurs when receiving data from the server, possibly multiple portions of the packet */ - HTTP_EVENT_ON_FINISH, /*!< Occurs when finish a HTTP session */ + HTTP_EVENT_ON_FINISH, /*!< Occurs when complete data is received */ HTTP_EVENT_DISCONNECTED, /*!< The connection has been disconnected */ HTTP_EVENT_REDIRECT, /*!< Intercepting HTTP redirects to handle them manually */ } esp_http_client_event_id_t;