mirror of
https://github.com/espressif/esp-idf.git
synced 2025-08-04 13:14: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 */
|
||||
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;
|
||||
|
@@ -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
|
||||
*
|
||||
|
@@ -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 */
|
||||
|
@@ -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
|
||||
--------------
|
||||
|
||||
|
@@ -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 恢复
|
||||
--------
|
||||
|
||||
|
Reference in New Issue
Block a user