Merge branch 'feature/move_partial_download_code_under_config' into 'master'

feat(esp_http_client): move partial download related code under config

Closes IDF-13464

See merge request espressif/esp-idf!40270
This commit is contained in:
Aditya Patwardhan
2025-08-11 11:09:49 +05:30
11 changed files with 71 additions and 7 deletions

View File

@@ -29,6 +29,12 @@ menu "ESP HTTP client"
This option will enable injection of a custom tcp_transport handle, so the http operation
will be performed on top of the user defined transport abstraction (if configured)
config ESP_HTTP_CLIENT_ENABLE_GET_CONTENT_RANGE
bool "Enable content range functionality"
default n
help
This enables use of content range header in esp_http_client component.
config ESP_HTTP_CLIENT_EVENT_POST_TIMEOUT
int "Time in millisecond to wait for posting event"
default 2000

View File

@@ -67,7 +67,9 @@ typedef struct {
int64_t data_process; /*!< data processed */
int method; /*!< http method */
bool is_chunked;
#if CONFIG_ESP_HTTP_CLIENT_ENABLE_GET_CONTENT_RANGE
int64_t content_range; /*!< content range */
#endif
} esp_http_data_t;
typedef struct {
@@ -279,6 +281,7 @@ static int http_on_header_value(http_parser *parser, const char *at, size_t leng
if (client->current_header_key == NULL) {
return 0;
}
#if CONFIG_ESP_HTTP_CLIENT_ENABLE_GET_CONTENT_RANGE
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");
@@ -301,7 +304,9 @@ static int http_on_header_value(http_parser *parser, const char *at, size_t leng
} else {
ESP_LOGE(TAG, "Invalid Content-Range format (missing '/')");
}
} else if (strcasecmp(client->current_header_key, "Location") == 0) {
} else
#endif
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) {
@@ -1859,10 +1864,12 @@ int64_t esp_http_client_get_content_length(esp_http_client_handle_t client)
return client->response->content_length;
}
#if CONFIG_ESP_HTTP_CLIENT_ENABLE_GET_CONTENT_RANGE
int64_t esp_http_client_get_content_range(esp_http_client_handle_t client)
{
return client->response->content_range;
}
#endif
bool esp_http_client_is_chunked_response(esp_http_client_handle_t client)
{

View File

@@ -644,6 +644,7 @@ 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);
#if CONFIG_ESP_HTTP_CLIENT_ENABLE_GET_CONTENT_RANGE || __DOXYGEN__
/**
* @brief Get http response content range (from header Content-Range)
* The returned value is valid only if this function is invoked after
@@ -656,6 +657,7 @@ int64_t esp_http_client_get_content_length(esp_http_client_handle_t client);
* - Content-Range value as bytes
*/
int64_t esp_http_client_get_content_range(esp_http_client_handle_t client);
#endif
/**
* @brief Close http connection, still kept all http request resources

View File

@@ -25,4 +25,12 @@ menu "ESP HTTPS OTA"
This config option helps in setting the time in millisecond to wait for event to be posted to the
system default event loop. Set it to -1 if you need to set timeout to portMAX_DELAY.
config ESP_HTTPS_OTA_ENABLE_PARTIAL_DOWNLOAD
bool "Enable partial HTTP download for OTA"
default n
select ESP_HTTP_CLIENT_ENABLE_GET_CONTENT_RANGE
help
This enables use of range header in esp_https_ota component.
The firmware image will be downloaded over multiple HTTP requests.
endmenu

View File

@@ -62,8 +62,10 @@ typedef struct {
const esp_http_client_config_t *http_config; /*!< ESP HTTP client configuration */
http_client_init_cb_t http_client_init_cb; /*!< Callback after ESP HTTP client is initialised */
bool bulk_flash_erase; /*!< Erase entire flash partition during initialization. By default flash partition is erased during write operation and in chunk of 4K sector size */
#if CONFIG_ESP_HTTPS_OTA_ENABLE_PARTIAL_DOWNLOAD || __DOXYGEN__
bool partial_http_download; /*!< Enable Firmware image to be downloaded over multiple HTTP requests */
int max_http_request_size; /*!< Maximum request size for partial HTTP download */
#endif
uint32_t buffer_caps; /*!< The memory capability to use when allocating the buffer for OTA update. Default capability is MALLOC_CAP_DEFAULT */
bool ota_resumption; /*!< Enable resumption in downloading of OTA image between reboots */
size_t ota_image_bytes_written; /*!< Number of OTA image bytes written to flash so far, updated by the application when OTA data is written successfully in the target OTA partition. */

View File

@@ -52,10 +52,12 @@ struct esp_https_ota_handle {
size_t ota_upgrade_buf_size;
int binary_file_len;
int image_length;
#if CONFIG_ESP_HTTPS_OTA_ENABLE_PARTIAL_DOWNLOAD
int max_http_request_size;
bool partial_http_download;
#endif
esp_https_ota_state state;
bool bulk_flash_erase;
bool partial_http_download;
int max_authorization_retries;
#if CONFIG_ESP_HTTPS_OTA_DECRYPT_CB
decrypt_cb_t decrypt_cb;
@@ -316,8 +318,10 @@ esp_err_t esp_https_ota_begin(const esp_https_ota_config_t *ota_config, esp_http
return ESP_ERR_NO_MEM;
}
#if CONFIG_ESP_HTTPS_OTA_ENABLE_PARTIAL_DOWNLOAD
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->max_authorization_retries = ota_config->http_config->max_authorization_retries;
if (https_ota_handle->max_authorization_retries == 0) {
@@ -356,13 +360,18 @@ esp_err_t esp_https_ota_begin(const esp_https_ota_config_t *ota_config, esp_http
* Partial cases ('from-to') are handled separately below based on the remaining data to
* be downloaded and the max_http_request_size.
*/
if (https_ota_handle->binary_file_len > 0 && !https_ota_handle->partial_http_download) {
if (https_ota_handle->binary_file_len > 0
#if CONFIG_ESP_HTTPS_OTA_ENABLE_PARTIAL_DOWNLOAD
&& !https_ota_handle->partial_http_download
#endif
) {
char *header_val = NULL;
asprintf(&header_val, "bytes=%d-", https_ota_handle->binary_file_len);
esp_http_client_set_header(https_ota_handle->http_client, "Range", header_val);
free(header_val);
}
#if CONFIG_ESP_HTTPS_OTA_ENABLE_PARTIAL_DOWNLOAD
if (https_ota_handle->partial_http_download) {
esp_http_client_set_method(https_ota_handle->http_client, HTTP_METHOD_HEAD);
@@ -435,6 +444,7 @@ esp_err_t esp_https_ota_begin(const esp_https_ota_config_t *ota_config, esp_http
}
esp_http_client_set_method(https_ota_handle->http_client, HTTP_METHOD_GET);
}
#endif
err = _http_connect(https_ota_handle);
if (err == ESP_ERR_HTTP_RANGE_NOT_SATISFIABLE && https_ota_handle->binary_file_len > 0) {
@@ -445,6 +455,7 @@ esp_err_t esp_https_ota_begin(const esp_https_ota_config_t *ota_config, esp_http
// If range in request header is not satisfiable, restart download from beginning
esp_http_client_delete_header(https_ota_handle->http_client, "Range");
#if CONFIG_ESP_HTTPS_OTA_ENABLE_PARTIAL_DOWNLOAD
if (https_ota_handle->partial_http_download && https_ota_handle->image_length > https_ota_handle->max_http_request_size) {
char *header_val = NULL;
asprintf(&header_val, "bytes=0-%d", https_ota_handle->max_http_request_size - 1);
@@ -456,6 +467,7 @@ esp_err_t esp_https_ota_begin(const esp_https_ota_config_t *ota_config, esp_http
esp_http_client_set_header(https_ota_handle->http_client, "Range", header_val);
free(header_val);
}
#endif
err = _http_connect(https_ota_handle);
}
@@ -468,7 +480,10 @@ esp_err_t esp_https_ota_begin(const esp_https_ota_config_t *ota_config, esp_http
esp_https_ota_dispatch_event(ESP_HTTPS_OTA_CONNECTED, NULL, 0);
}
if (!https_ota_handle->partial_http_download) {
#if CONFIG_ESP_HTTPS_OTA_ENABLE_PARTIAL_DOWNLOAD
if (!https_ota_handle->partial_http_download)
#endif
{
https_ota_handle->image_length = esp_http_client_get_content_length(https_ota_handle->http_client);
#if CONFIG_ESP_HTTPS_OTA_DECRYPT_CB
/* In case of pre ecnrypted OTA, actual image size of OTA binary includes header size
@@ -783,7 +798,10 @@ esp_err_t esp_https_ota_perform(esp_https_ota_handle_t https_ota_handle)
ESP_LOGE(TAG, "data read %d, errno %d", data_read, errno);
return ESP_FAIL;
}
if (!handle->partial_http_download || (handle->partial_http_download && handle->image_length == handle->binary_file_len)) {
#if CONFIG_ESP_HTTPS_OTA_ENABLE_PARTIAL_DOWNLOAD
if (!handle->partial_http_download || (handle->partial_http_download && handle->image_length == handle->binary_file_len))
#endif
{
handle->state = ESP_HTTPS_OTA_SUCCESS;
}
break;
@@ -792,6 +810,7 @@ esp_err_t esp_https_ota_perform(esp_https_ota_handle_t https_ota_handle)
return ESP_FAIL;
break;
}
#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);
@@ -820,6 +839,7 @@ esp_err_t esp_https_ota_perform(esp_https_ota_handle_t https_ota_handle)
return ESP_ERR_HTTPS_OTA_IN_PROGRESS;
}
}
#endif
return ESP_OK;
}
@@ -827,9 +847,12 @@ bool esp_https_ota_is_complete_data_received(esp_https_ota_handle_t https_ota_ha
{
bool ret = false;
esp_https_ota_t *handle = (esp_https_ota_t *)https_ota_handle;
#if CONFIG_ESP_HTTPS_OTA_ENABLE_PARTIAL_DOWNLOAD
if (handle->partial_http_download) {
ret = (handle->image_length == handle->binary_file_len);
} else {
} else
#endif
{
ret = esp_http_client_is_complete_data_received(handle->http_client);
}
return ret;

View File

@@ -41,7 +41,13 @@ Please refer to :ref:`ESP-TLS: TLS Server Verification <esp_tls_server_verificat
Partial Image Download over HTTPS
---------------------------------
To use the partial image download feature, enable ``partial_http_download`` configuration in ``esp_https_ota_config_t``. When this configuration is enabled, firmware image will be downloaded in multiple HTTP requests of specified sizes. Maximum content length of each request can be specified by setting ``max_http_request_size`` to the required value.
To use the partial image download feature, you need to:
* **Enable the component-level configuration**: enable :ref:`CONFIG_ESP_HTTPS_OTA_ENABLE_PARTIAL_DOWNLOAD` in menuconfig (``Component config````ESP HTTPS OTA````Enable partial HTTP download for OTA``)
* **Enable the feature in your application**: Set the ``partial_http_download`` field in :cpp:struct:`esp_https_ota_config_t` configuration structure
When this configuration is enabled, firmware image will be downloaded in multiple HTTP requests of specified sizes. Maximum content length of each request can be specified by setting ``max_http_request_size`` to the required value.
This option is useful while fetching image from a service like AWS S3, where mbedTLS Rx buffer size (:ref:`CONFIG_MBEDTLS_SSL_IN_CONTENT_LEN`) can be set to a lower value which is not possible without enabling this configuration.

View File

@@ -104,3 +104,10 @@ Binary data format has been dropped. `CONFIG_ESP_COREDUMP_DATA_FORMAT_BIN` is no
CRC data integrity check has been dropped. `ESP_COREDUMP_CHECKSUM_CRC32` is no longer supported. SHA256 is now the default checksum algorithm.
The function :cpp:func:`esp_core_dump_partition_and_size_get()` now returns `ESP_ERR_NOT_FOUND` for blank (erased) partitions instead of `ESP_ERR_INVALID_SIZE`.
OTA Updates
-----------
The partial download functionality in ESP HTTPS OTA has been moved under a configuration option in order to reduce the memory footprint if partial download is not used.
To use partial download features in your OTA applications, you need to enable the component-level configuration :ref:`CONFIG_ESP_HTTPS_OTA_ENABLE_PARTIAL_DOWNLOAD` in menuconfig (``Component config````ESP HTTPS OTA````Enable partial HTTP download for OTA``).

View File

@@ -31,6 +31,7 @@ menu "Example Configuration"
config EXAMPLE_ENABLE_PARTIAL_HTTP_DOWNLOAD
bool "Enable partial HTTP download"
default n
select ESP_HTTPS_OTA_ENABLE_PARTIAL_DOWNLOAD
select ESP_TLS_CLIENT_SESSION_TICKETS
help
This enables use of Range header in esp_https_ota component.

View File

@@ -2,6 +2,7 @@ CONFIG_EXAMPLE_FIRMWARE_UPGRADE_URL="FROM_STDIN"
CONFIG_EXAMPLE_SKIP_COMMON_NAME_CHECK=y
CONFIG_EXAMPLE_SKIP_VERSION_CHECK=y
CONFIG_EXAMPLE_OTA_RECV_TIMEOUT=3000
CONFIG_ESP_HTTPS_OTA_ENABLE_PARTIAL_DOWNLOAD=y
CONFIG_EXAMPLE_ENABLE_PARTIAL_HTTP_DOWNLOAD=y
CONFIG_EXAMPLE_ENABLE_OTA_RESUMPTION=y

View File

@@ -2,6 +2,7 @@ CONFIG_EXAMPLE_FIRMWARE_UPGRADE_URL="FROM_STDIN"
CONFIG_EXAMPLE_SKIP_COMMON_NAME_CHECK=y
CONFIG_EXAMPLE_SKIP_VERSION_CHECK=y
CONFIG_EXAMPLE_OTA_RECV_TIMEOUT=3000
CONFIG_ESP_HTTPS_OTA_ENABLE_PARTIAL_DOWNLOAD=y
CONFIG_EXAMPLE_ENABLE_PARTIAL_HTTP_DOWNLOAD=y
CONFIG_LOG_DEFAULT_LEVEL_DEBUG=y