Merge branch 'bugfix/ota_failing_for_aws_signed_url_with_partial_download_enabled' into 'master'

fix(esp_http_client): Fix OTA failure with partial download enabled

Closes IDF-12590

See merge request espressif/esp-idf!37843
This commit is contained in:
Mahavir Jain
2025-07-01 09:39:52 +05:30
5 changed files with 83 additions and 5 deletions

View File

@@ -67,6 +67,7 @@ typedef struct {
int64_t data_process; /*!< data processed */
int method; /*!< http method */
bool is_chunked;
int64_t content_range; /*!< content range */
} esp_http_data_t;
typedef struct {
@@ -269,7 +270,29 @@ static int http_on_header_value(http_parser *parser, const char *at, size_t leng
if (client->current_header_key == NULL) {
return 0;
}
if (strcasecmp(client->current_header_key, "Location") == 0) {
if (strcasecmp(client->current_header_key, "Content-Range") == 0) {
HTTP_RET_ON_FALSE_DBG(http_utils_append_string(&client->current_header_value, at, length), -1, TAG, "Failed to append string");
int64_t total_size = -1;
client->response->content_range = -1;
char *slash_pos = strchr(client->current_header_value, '/');
if (slash_pos) {
if (slash_pos[1] == '*') {
ESP_LOGE(TAG, "Content-Range header has unknown total size (bytes A-B/*)");
} else {
char *endptr;
total_size = strtol(slash_pos + 1, &endptr, 10);
if (total_size > 0 && *endptr == '\0') {
client->response->content_range = total_size;
} else {
ESP_LOGE(TAG, "Failed to extract total size from Content-Range");
}
}
} else {
ESP_LOGE(TAG, "Invalid Content-Range format (missing '/')");
}
} else if (strcasecmp(client->current_header_key, "Location") == 0) {
HTTP_RET_ON_FALSE_DBG(http_utils_append_string(&client->location, at, length), -1, TAG, "Failed to append string");
} else if (strcasecmp(client->current_header_key, "Transfer-Encoding") == 0
&& memcmp(at, "chunked", length) == 0) {
@@ -1817,6 +1840,11 @@ int64_t esp_http_client_get_content_length(esp_http_client_handle_t client)
return client->response->content_length;
}
int64_t esp_http_client_get_content_range(esp_http_client_handle_t client)
{
return client->response->content_range;
}
bool esp_http_client_is_chunked_response(esp_http_client_handle_t client)
{
return client->response->is_chunked;

View File

@@ -232,6 +232,7 @@ typedef struct {
typedef enum {
/* 2xx - Success */
HttpStatus_Ok = 200,
HttpStatus_PartialContent = 206,
/* 3xx - Redirection */
HttpStatus_MultipleChoices = 300,
@@ -642,6 +643,19 @@ int esp_http_client_get_status_code(esp_http_client_handle_t client);
*/
int64_t esp_http_client_get_content_length(esp_http_client_handle_t client);
/**
* @brief Get http response content range (from header Content-Range)
* The returned value is valid only if this function is invoked after
* a successful call to `esp_http_client_perform`.
* Content-Range is set to -1 if parsing fails or if the Content-Range header is not present.
*
* @param[in] client The esp_http_client handle
*
* @return
* - Content-Range value as bytes
*/
int64_t esp_http_client_get_content_range(esp_http_client_handle_t client);
/**
* @brief Close http connection, still kept all http request resources
*

View File

@@ -365,20 +365,50 @@ esp_err_t esp_https_ota_begin(const esp_https_ota_config_t *ota_config, esp_http
if (https_ota_handle->partial_http_download) {
esp_http_client_set_method(https_ota_handle->http_client, HTTP_METHOD_HEAD);
err = esp_http_client_perform(https_ota_handle->http_client);
if (err == ESP_OK) {
int status = esp_http_client_get_status_code(https_ota_handle->http_client);
if (status != HttpStatus_Ok) {
ESP_LOGE(TAG, "Received incorrect http status %d", status);
err = ESP_FAIL;
goto http_cleanup;
// If server doesn't support HEAD request, we need to get image length from GET request
// using Range header
esp_http_client_set_header(https_ota_handle->http_client, "Range", "bytes=0-0");
esp_http_client_set_method(https_ota_handle->http_client, HTTP_METHOD_GET);
err = esp_http_client_perform(https_ota_handle->http_client);
if (err == ESP_OK) {
status = esp_http_client_get_status_code(https_ota_handle->http_client);
if (status != HttpStatus_Ok && status != HttpStatus_PartialContent) {
ESP_LOGE(TAG, "Received incorrect http status %d", status);
err = ESP_FAIL;
goto http_cleanup;
}
} else {
ESP_LOGE(TAG, "ESP HTTP client perform failed: %d", err);
goto http_cleanup;
}
esp_http_client_set_header(https_ota_handle->http_client, "Range", NULL);
if (status == HttpStatus_Ok) {
// If server responds with 200 OK, we can get image length from content-length header
https_ota_handle->image_length = esp_http_client_get_content_length(https_ota_handle->http_client);
} else {
// If server responds with 206 Partial Content, we can get image length from content-range header
https_ota_handle->image_length = esp_http_client_get_content_range(https_ota_handle->http_client);
}
} else {
https_ota_handle->image_length = esp_http_client_get_content_length(https_ota_handle->http_client);
}
} else {
ESP_LOGE(TAG, "ESP HTTP client perform failed: %d", err);
goto http_cleanup;
}
https_ota_handle->image_length = esp_http_client_get_content_length(https_ota_handle->http_client);
if (https_ota_handle->image_length == -1) {
ESP_LOGE(TAG, "Failed to get image length from http response");
err = ESP_FAIL;
goto http_cleanup;
}
#if CONFIG_ESP_HTTPS_OTA_DECRYPT_CB
/* In case of pre ecnrypted OTA, actual image size of OTA binary includes header size
* which stored in variable enc_img_header_size */

View File

@@ -47,6 +47,9 @@ This option is useful while fetching image from a service like AWS S3, where mbe
Default value of mbedTLS Rx buffer size is set to 16 KB. By using ``partial_http_download`` with ``max_http_request_size`` of 4 KB, size of mbedTLS Rx buffer can be reduced to 4 KB. With this configuration, memory saving of around 12 KB is expected.
.. note::
If the server uses chunked transfer encoding, partial downloads are not feasible because the total content length is not known in advance.
OTA Resumption
--------------

View File

@@ -47,6 +47,9 @@ ESP HTTPS OTA 升级
mbedTLS Rx buffer 的默认大小为 16 KB但如果将 ``partial_http_download````max_http_request_size`` 设置为 4 KB便能将 mbedTLS Rx 的 buffer 减小到 4 KB。使用这一配置方式预计可以节省约 12 KB 内存。
.. note::
如果服务器使用分块传输编码,则无法进行部分下载,因为无法预先获知总内容长度。
OTA 恢复
--------