Merge branch 'feature/partial_download_over_single_connection' into 'master'

feat(esp_https_ota): Support partial downloading of OTA over single connection

Closes IDF-13400

See merge request espressif/esp-idf!41911
This commit is contained in:
Nilesh Kale
2025-10-16 18:32:15 +08:00
3 changed files with 79 additions and 5 deletions

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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