From 709b869a345236696476eb810e3a671316f0efa5 Mon Sep 17 00:00:00 2001 From: "nilesh.kale" Date: Mon, 15 Sep 2025 17:21:56 +0530 Subject: [PATCH] feat(esp_https_ota): Support partial downloading of OTA over single connection This commit added support to download OTA with partial download feature over single HTTP connection if server supports persistent connection. --- components/esp_http_client/esp_http_client.c | 26 ++++++++++++-- .../esp_http_client/include/esp_http_client.h | 36 +++++++++++++++++++ components/esp_https_ota/src/esp_https_ota.c | 22 ++++++++++-- 3 files changed, 79 insertions(+), 5 deletions(-) diff --git a/components/esp_http_client/esp_http_client.c b/components/esp_http_client/esp_http_client.c index d413cb655c..6ac883da5d 100644 --- a/components/esp_http_client/esp_http_client.c +++ b/components/esp_http_client/esp_http_client.c @@ -185,7 +185,7 @@ static const char *HTTP_METHOD_MAPPING[] = { "REPORT" }; -static esp_err_t esp_http_client_request_send(esp_http_client_handle_t client, int write_len); +esp_err_t esp_http_client_request_send(esp_http_client_handle_t client, int write_len); static esp_err_t esp_http_client_connect(esp_http_client_handle_t client); static esp_err_t esp_http_client_send_post_data(esp_http_client_handle_t client); @@ -701,8 +701,12 @@ error: } #endif -static esp_err_t esp_http_client_prepare(esp_http_client_handle_t client) +esp_err_t esp_http_client_prepare(esp_http_client_handle_t client) { + if (client == NULL) { + return ESP_FAIL; + } + esp_err_t ret = ESP_OK; client->process_again = 0; client->response->data_process = 0; @@ -1711,8 +1715,12 @@ static int http_client_prepare_first_line(esp_http_client_handle_t client, int w return first_line_len; } -static esp_err_t esp_http_client_request_send(esp_http_client_handle_t client, int write_len) +esp_err_t esp_http_client_request_send(esp_http_client_handle_t client, int write_len) { + if (client == NULL) { + return ESP_FAIL; + } + int first_line_len = 0; if (!client->first_line_prepared) { if ((first_line_len = http_client_prepare_first_line(client, write_len)) < 0) { @@ -2065,3 +2073,15 @@ esp_http_state_t esp_http_client_get_state(esp_http_client_handle_t client) } return client->state; } + +bool esp_http_client_is_persistent_connection(esp_http_client_handle_t client) +{ + if (client == NULL) { + return false; + } + + if (http_should_keep_alive(client->parser)) { + return true; + } + return false; +} diff --git a/components/esp_http_client/include/esp_http_client.h b/components/esp_http_client/include/esp_http_client.h index 2955d1942b..48d30d4857 100644 --- a/components/esp_http_client/include/esp_http_client.h +++ b/components/esp_http_client/include/esp_http_client.h @@ -343,6 +343,33 @@ esp_http_client_handle_t esp_http_client_init(const esp_http_client_config_t *co */ esp_err_t esp_http_client_perform(esp_http_client_handle_t client); +/** + * @brief Prepare HTTP client for a new request + * This function initializes the client state and prepares authentication if needed. + * It should be called before sending a request. + * + * @param[in] client The esp_http_client handle + * + * @return + * - ESP_OK on successful + * - ESP_FAIL on error + */ +esp_err_t esp_http_client_prepare(esp_http_client_handle_t client); + +/** + * @brief Send HTTP request headers and data + * This function sends the HTTP request line, headers, and any post data to the server. + * + * @param[in] client The esp_http_client handle + * @param[in] write_len Length of data to write (for POST/PUT requests) + * + * @return + * - ESP_OK on successful + * - ESP_FAIL on error + * - ESP_ERR_HTTP_WRITE_DATA if write operation fails + */ +esp_err_t esp_http_client_request_send(esp_http_client_handle_t client, int write_len); + /** * @brief Cancel an ongoing HTTP request. This API closes the current socket and opens a new socket with the same esp_http_client context. * @@ -866,6 +893,15 @@ esp_err_t esp_http_client_get_chunk_length(esp_http_client_handle_t client, int */ esp_http_state_t esp_http_client_get_state(esp_http_client_handle_t client); +/** + * @brief Check if persistent connection is supported by the server + * + * @param[in] client The HTTP client handle + * + * @return true if persistent connection is supported, false otherwise + */ +bool esp_http_client_is_persistent_connection(esp_http_client_handle_t client); + #ifdef __cplusplus } #endif diff --git a/components/esp_https_ota/src/esp_https_ota.c b/components/esp_https_ota/src/esp_https_ota.c index 2315138382..59e7887e1c 100644 --- a/components/esp_https_ota/src/esp_https_ota.c +++ b/components/esp_https_ota/src/esp_https_ota.c @@ -165,7 +165,22 @@ static esp_err_t _http_connect(esp_https_ota_t *https_ota_handle) * is enabled */ int post_len = esp_http_client_get_post_field(https_ota_handle->http_client, &post_data); - err = esp_http_client_open(https_ota_handle->http_client, post_len); + +#if CONFIG_ESP_HTTPS_OTA_ENABLE_PARTIAL_DOWNLOAD + // If support_persistent_connection is enabled and this is a subsequent request, skip connection + if (esp_http_client_is_persistent_connection(https_ota_handle->http_client) && https_ota_handle->state == ESP_HTTPS_OTA_IN_PROGRESS) { + ESP_LOGD(TAG, "Using existing connection for partial download"); + err = esp_http_client_prepare(https_ota_handle->http_client); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Failed to reset HTTP client response state: %s", esp_err_to_name(err)); + return err; + } + err = esp_http_client_request_send(https_ota_handle->http_client, post_len); + } else +#endif + { + err = esp_http_client_open(https_ota_handle->http_client, post_len); + } if (err != ESP_OK) { ESP_LOGE(TAG, "Failed to open HTTP connection: %s", esp_err_to_name(err)); return err; @@ -827,7 +842,10 @@ esp_err_t esp_https_ota_perform(esp_https_ota_handle_t https_ota_handle) #if CONFIG_ESP_HTTPS_OTA_ENABLE_PARTIAL_DOWNLOAD if (handle->partial_http_download) { if (handle->state == ESP_HTTPS_OTA_IN_PROGRESS && handle->image_length > handle->binary_file_len) { - esp_http_client_close(handle->http_client); + // Only close connection if support_persistent_connection is not enabled + if (!esp_http_client_is_persistent_connection(handle->http_client)) { + esp_http_client_close(handle->http_client); + } char *header_val = NULL; int header_size = 0; #if CONFIG_ESP_HTTPS_OTA_DECRYPT_CB