mirror of
https://github.com/espressif/esp-idf.git
synced 2025-08-05 05:34:32 +02:00
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:
@@ -67,6 +67,7 @@ typedef struct {
|
|||||||
int64_t data_process; /*!< data processed */
|
int64_t data_process; /*!< data processed */
|
||||||
int method; /*!< http method */
|
int method; /*!< http method */
|
||||||
bool is_chunked;
|
bool is_chunked;
|
||||||
|
int64_t content_range; /*!< content range */
|
||||||
} esp_http_data_t;
|
} esp_http_data_t;
|
||||||
|
|
||||||
typedef struct {
|
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) {
|
if (client->current_header_key == NULL) {
|
||||||
return 0;
|
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");
|
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
|
} else if (strcasecmp(client->current_header_key, "Transfer-Encoding") == 0
|
||||||
&& memcmp(at, "chunked", length) == 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;
|
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)
|
bool esp_http_client_is_chunked_response(esp_http_client_handle_t client)
|
||||||
{
|
{
|
||||||
return client->response->is_chunked;
|
return client->response->is_chunked;
|
||||||
|
@@ -232,6 +232,7 @@ typedef struct {
|
|||||||
typedef enum {
|
typedef enum {
|
||||||
/* 2xx - Success */
|
/* 2xx - Success */
|
||||||
HttpStatus_Ok = 200,
|
HttpStatus_Ok = 200,
|
||||||
|
HttpStatus_PartialContent = 206,
|
||||||
|
|
||||||
/* 3xx - Redirection */
|
/* 3xx - Redirection */
|
||||||
HttpStatus_MultipleChoices = 300,
|
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);
|
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
|
* @brief Close http connection, still kept all http request resources
|
||||||
*
|
*
|
||||||
|
@@ -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) {
|
if (https_ota_handle->partial_http_download) {
|
||||||
esp_http_client_set_method(https_ota_handle->http_client, HTTP_METHOD_HEAD);
|
esp_http_client_set_method(https_ota_handle->http_client, HTTP_METHOD_HEAD);
|
||||||
|
|
||||||
err = esp_http_client_perform(https_ota_handle->http_client);
|
err = esp_http_client_perform(https_ota_handle->http_client);
|
||||||
if (err == ESP_OK) {
|
if (err == ESP_OK) {
|
||||||
int status = esp_http_client_get_status_code(https_ota_handle->http_client);
|
int status = esp_http_client_get_status_code(https_ota_handle->http_client);
|
||||||
if (status != HttpStatus_Ok) {
|
if (status != HttpStatus_Ok) {
|
||||||
ESP_LOGE(TAG, "Received incorrect http status %d", status);
|
// If server doesn't support HEAD request, we need to get image length from GET request
|
||||||
err = ESP_FAIL;
|
// using Range header
|
||||||
goto http_cleanup;
|
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 {
|
} else {
|
||||||
ESP_LOGE(TAG, "ESP HTTP client perform failed: %d", err);
|
ESP_LOGE(TAG, "ESP HTTP client perform failed: %d", err);
|
||||||
goto http_cleanup;
|
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
|
#if CONFIG_ESP_HTTPS_OTA_DECRYPT_CB
|
||||||
/* In case of pre ecnrypted OTA, actual image size of OTA binary includes header size
|
/* In case of pre ecnrypted OTA, actual image size of OTA binary includes header size
|
||||||
* which stored in variable enc_img_header_size */
|
* which stored in variable enc_img_header_size */
|
||||||
|
@@ -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.
|
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
|
OTA Resumption
|
||||||
--------------
|
--------------
|
||||||
|
|
||||||
|
@@ -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 内存。
|
mbedTLS Rx buffer 的默认大小为 16 KB,但如果将 ``partial_http_download`` 的 ``max_http_request_size`` 设置为 4 KB,便能将 mbedTLS Rx 的 buffer 减小到 4 KB。使用这一配置方式预计可以节省约 12 KB 内存。
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
如果服务器使用分块传输编码,则无法进行部分下载,因为无法预先获知总内容长度。
|
||||||
|
|
||||||
OTA 恢复
|
OTA 恢复
|
||||||
--------
|
--------
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user