fix(esp_https_ota): handle ota resumption if server dosent support range requests

This commit added check to see if server supports range requets,
and fallback to OTA without resumption accordingly.

Closes https://github.com/espressif/esp-idf/pull/17960
This commit is contained in:
nilesh.kale
2026-02-11 14:40:35 +05:30
parent bf3d4f0dd9
commit 4e434f8eb8
4 changed files with 125 additions and 12 deletions
@@ -1864,6 +1864,17 @@ esp_err_t esp_http_client_close(esp_http_client_handle_t client)
return ESP_OK;
}
esp_err_t esp_http_client_clear_response_buffer(esp_http_client_handle_t client)
{
if (client == NULL) {
return ESP_ERR_INVALID_ARG;
}
if (client->response != NULL && client->response->buffer != NULL) {
esp_http_client_cached_buf_cleanup(client->response->buffer);
}
return ESP_OK;
}
esp_err_t esp_http_client_set_post_field(esp_http_client_handle_t client, const char *data, int len)
{
esp_err_t err = ESP_OK;
@@ -732,6 +732,19 @@ int64_t esp_http_client_get_content_range(esp_http_client_handle_t client);
*/
esp_err_t esp_http_client_close(esp_http_client_handle_t client);
/**
* @brief Clear cached response buffer (e.g. data received during fetch headers).
* Use this when reusing the same client handle for a new request after
* closing the connection, so the next request does not see stale data.
*
* @param[in] client The esp_http_client handle
*
* @return
* - ESP_OK
* - ESP_ERR_INVALID_ARG if client is NULL
*/
esp_err_t esp_http_client_clear_response_buffer(esp_http_client_handle_t client);
/**
* @brief This function must be the last function to call for an session.
* It is the opposite of the esp_http_client_init function and must be called with the same handle as input that a esp_http_client_init call returned.
+18 -11
View File
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2017-2025 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2017-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -59,6 +59,7 @@ struct esp_https_ota_handle {
#endif
esp_https_ota_state state;
bool bulk_flash_erase;
bool ota_resumption;
int max_authorization_retries;
#if CONFIG_ESP_HTTPS_OTA_DECRYPT_CB
decrypt_cb_t decrypt_cb;
@@ -135,12 +136,13 @@ static esp_err_t _http_handle_response_code(esp_https_ota_t *https_ota_handle, i
} else if (status_code >= HttpStatus_InternalError) {
ESP_LOGE(TAG, "Server error (%d)", status_code);
return ESP_FAIL;
} else if (https_ota_handle->binary_file_len > 0
} else if (https_ota_handle->ota_resumption
#if CONFIG_ESP_HTTPS_OTA_ENABLE_PARTIAL_DOWNLOAD
&& !https_ota_handle->partial_http_download
#endif
&& status_code != HttpStatus_PartialContent) {
ESP_LOGE(TAG, "Requested range header ignored by server");
ESP_LOGW(TAG, "Server ignored the requested Range header");
ESP_LOGW(TAG, "OTA resumption requires server with range request support.");
return ESP_ERR_HTTP_RANGE_NOT_SATISFIABLE;
}
@@ -345,6 +347,7 @@ esp_err_t esp_https_ota_begin(const esp_https_ota_config_t *ota_config, esp_http
https_ota_handle->partial_http_download = ota_config->partial_http_download;
https_ota_handle->max_http_request_size = (ota_config->max_http_request_size == 0) ? DEFAULT_REQUEST_SIZE : ota_config->max_http_request_size;
#endif
https_ota_handle->ota_resumption = ota_config->ota_resumption;
https_ota_handle->max_authorization_retries = ota_config->http_config->max_authorization_retries;
if (https_ota_handle->max_authorization_retries == 0) {
@@ -379,12 +382,13 @@ esp_err_t esp_https_ota_begin(const esp_https_ota_config_t *ota_config, esp_http
}
/*
* If OTA resumption is enabled, set the "Range" header to resume downloading the OTA image
* from the last written byte. For non-partial cases, the range pattern is 'from-'.
* Partial cases ('from-to') are handled separately below based on the remaining data to
* be downloaded and the max_http_request_size.
* If OTA resumption is enabled, always make a range request first to detect if server
* supports range requests. This helps fail early if server doesn't support range requests.
* - If resuming from NVS recovered offset: use 'bytes=offset-'
* - If starting fresh: use 'bytes=0-'
* This applies to both partial and non-partial download cases.
*/
if (https_ota_handle->binary_file_len > 0
if (https_ota_handle->ota_resumption
#if CONFIG_ESP_HTTPS_OTA_ENABLE_PARTIAL_DOWNLOAD
&& !https_ota_handle->partial_http_download
#endif
@@ -476,9 +480,10 @@ esp_err_t esp_https_ota_begin(const esp_https_ota_config_t *ota_config, esp_http
#endif
err = _http_connect(https_ota_handle);
if (err == ESP_ERR_HTTP_RANGE_NOT_SATISFIABLE && https_ota_handle->binary_file_len > 0) {
ESP_LOGE(TAG, "OTA resumption failed with err: %d", err);
ESP_LOGI(TAG, "Restarting download from beginning");
if (err == ESP_ERR_HTTP_RANGE_NOT_SATISFIABLE && https_ota_handle->ota_resumption) {
ESP_LOGE(TAG, "OTA resumption failed with err: %d.", err);
ESP_LOGI(TAG, "Falling back to OTA without resumption and restarting download from beginning");
https_ota_handle->ota_resumption = false;
https_ota_handle->binary_file_len = 0;
// If range in request header is not satisfiable, restart download from beginning
@@ -497,6 +502,8 @@ esp_err_t esp_https_ota_begin(const esp_https_ota_config_t *ota_config, esp_http
free(header_val);
}
#endif
esp_http_client_close(https_ota_handle->http_client);
esp_http_client_clear_response_buffer(https_ota_handle->http_client);
err = _http_connect(https_ota_handle);
}