feat(esp_http_client): adds support to save response headers

Closes https://github.com/espressif/esp-idf/issues/17695
This commit is contained in:
Ashish Sharma
2025-10-08 15:17:06 +08:00
parent 148e333495
commit c8f1fa86a2
9 changed files with 189 additions and 4 deletions

View File

@@ -41,4 +41,29 @@ menu "ESP HTTP client"
help
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_HTTP_CLIENT_SAVE_RESPONSE_HEADERS
bool "Save response headers"
default n
help
This option will enable saving of response headers in esp_http_client component.
When enabled, upto ESP_HTTP_CLIENT_MAX_SAVED_RESPONSE_HEADERS headers are saved.
Enabling this option will increase the memory footprint of the component.
config ESP_HTTP_CLIENT_MAX_SAVED_RESPONSE_HEADERS
depends on ESP_HTTP_CLIENT_SAVE_RESPONSE_HEADERS
int "Maximum number of response headers"
default 10
help
This config option helps in setting the maximum number of response headers that
can be saved in esp_http_client component.
config ESP_HTTP_CLIENT_MAX_RESPONSE_HEADER_SIZE
depends on ESP_HTTP_CLIENT_SAVE_RESPONSE_HEADERS
int "Maximum size of response header"
default 128
help
This config option helps in setting the maximum size of response header that
can be saved in esp_http_client component.
Note that the same size is used for key and value in the response headers.
endmenu

View File

@@ -60,6 +60,9 @@ typedef struct {
*/
typedef struct {
http_header_handle_t headers; /*!< http header */
#if CONFIG_ESP_HTTP_CLIENT_SAVE_RESPONSE_HEADERS
int saved_response_header_count;
#endif // CONFIG_ESP_HTTP_CLIENT_SAVE_RESPONSE_HEADERS
esp_http_buffer_t *buffer; /*!< data buffer as linked list */
int status_code; /*!< status code (integer) */
int64_t content_length; /*!< data length */
@@ -249,6 +252,23 @@ static int http_on_header_event(esp_http_client_handle_t client)
client->event.header_value = client->current_header_value;
http_dispatch_event(client, HTTP_EVENT_ON_HEADER, NULL, 0);
http_dispatch_event_to_event_loop(HTTP_EVENT_ON_HEADER, &client, sizeof(esp_http_client_handle_t));
#if CONFIG_ESP_HTTP_CLIENT_SAVE_RESPONSE_HEADERS
if (client->response->saved_response_header_count >= CONFIG_ESP_HTTP_CLIENT_MAX_SAVED_RESPONSE_HEADERS) {
ESP_LOGW(TAG, "Response header limit (%d) exceeded", CONFIG_ESP_HTTP_CLIENT_MAX_SAVED_RESPONSE_HEADERS);
} else {
if (strlen(client->current_header_key) > CONFIG_ESP_HTTP_CLIENT_MAX_RESPONSE_HEADER_SIZE ||
strlen(client->current_header_value) > CONFIG_ESP_HTTP_CLIENT_MAX_RESPONSE_HEADER_SIZE) {
ESP_LOGW(TAG, "Header '%s' exceeds max size (%d): key=%zu, value=%zu",
client->current_header_key, CONFIG_ESP_HTTP_CLIENT_MAX_RESPONSE_HEADER_SIZE,
strlen(client->current_header_key), strlen(client->current_header_value));
} else {
http_header_set(client->response->headers, client->current_header_key, client->current_header_value);
client->response->saved_response_header_count++;
}
}
#endif // CONFIG_ESP_HTTP_CLIENT_SAVE_RESPONSE_HEADERS
free(client->current_header_key);
free(client->current_header_value);
client->current_header_key = NULL;
@@ -409,6 +429,17 @@ esp_err_t esp_http_client_get_header(esp_http_client_handle_t client, const char
return http_header_get(client->request->headers, key, value);
}
#if CONFIG_ESP_HTTP_CLIENT_SAVE_RESPONSE_HEADERS
esp_err_t esp_http_client_get_response_header(esp_http_client_handle_t client, const char *key, char **value)
{
if (client == NULL || client->response == NULL || client->response->headers == NULL || key == NULL || value == NULL) {
return ESP_ERR_INVALID_ARG;
}
return http_header_get(client->response->headers, key, value);
}
#endif // CONFIG_ESP_HTTP_CLIENT_SAVE_RESPONSE_HEADERS
esp_err_t esp_http_client_delete_header(esp_http_client_handle_t client, const char *key)
{
if (client == NULL || client->request == NULL || client->request->headers == NULL || key == NULL) {
@@ -725,6 +756,12 @@ esp_err_t esp_http_client_prepare(esp_http_client_handle_t client)
free(client->auth_header);
client->auth_header = NULL;
}
#if CONFIG_ESP_HTTP_CLIENT_SAVE_RESPONSE_HEADERS
if (client->response->headers != NULL) {
http_header_clean(client->response->headers);
}
client->response->saved_response_header_count = 0;
#endif // CONFIG_ESP_HTTP_CLIENT_SAVE_RESPONSE_HEADERS
http_parser_init(client->parser, HTTP_RESPONSE);
if (client->connection_info.username) {
if (client->connection_info.auth_type == HTTP_AUTH_TYPE_BASIC) {
@@ -817,7 +854,9 @@ esp_http_client_handle_t esp_http_client_init(const esp_http_client_config_t *co
(client->request->headers = http_header_init()) &&
(client->request->buffer = calloc(1, sizeof(esp_http_buffer_t))) &&
(client->response = calloc(1, sizeof(esp_http_data_t))) &&
#if CONFIG_ESP_HTTP_CLIENT_SAVE_RESPONSE_HEADERS
(client->response->headers = http_header_init()) &&
#endif // CONFIG_ESP_HTTP_CLIENT_SAVE_RESPONSE_HEADERS
(client->response->buffer = calloc(1, sizeof(esp_http_buffer_t)))
);
@@ -1068,7 +1107,9 @@ esp_err_t esp_http_client_cleanup(esp_http_client_handle_t client)
free(client->request);
}
if (client->response) {
#if CONFIG_ESP_HTTP_CLIENT_SAVE_RESPONSE_HEADERS
http_header_destroy(client->response->headers);
#endif // CONFIG_ESP_HTTP_CLIENT_SAVE_RESPONSE_HEADERS
if (client->response->buffer) {
free(client->response->buffer->data);
esp_http_client_cached_buf_cleanup(client->response->buffer);
@@ -1451,6 +1492,9 @@ esp_err_t esp_http_client_perform(esp_http_client_handle_t client)
http_dispatch_event_to_event_loop(HTTP_EVENT_ERROR, &client, sizeof(esp_http_client_handle_t));
return err;
}
#if CONFIG_ESP_HTTP_CLIENT_SAVE_RESPONSE_HEADERS
client->response->saved_response_header_count = 0;
#endif // CONFIG_ESP_HTTP_CLIENT_SAVE_RESPONSE_HEADERS
/* falls through */
case HTTP_STATE_REQ_COMPLETE_HEADER:
if ((err = esp_http_client_send_post_data(client)) != ESP_OK) {

View File

@@ -444,11 +444,37 @@ esp_err_t esp_http_client_set_header(esp_http_client_handle_t client, const char
* @param[out] value The header value
*
* @return
* - ESP_OK
* - ESP_FAIL
* - ESP_OK: Header found
* - ESP_ERR_INVALID_ARG: Invalid arguments
* - ESP_ERR_NOT_FOUND: Header not found
*/
esp_err_t esp_http_client_get_header(esp_http_client_handle_t client, const char *key, char **value);
#if CONFIG_ESP_HTTP_CLIENT_SAVE_RESPONSE_HEADERS || __DOXYGEN__
/**
* @brief Get a response header value by key
* The value parameter will be set to NULL if there is no header which is same as
* the key specified, otherwise the address of header value will be assigned to value parameter.
* This function must be called after `esp_http_client_init`.
*
* @note Limitations:
* - Only first CONFIG_ESP_HTTP_CLIENT_MAX_SAVED_RESPONSE_HEADERS (default: 10) headers are saved
* - Headers exceeding CONFIG_ESP_HTTP_CLIENT_MAX_RESPONSE_HEADER_SIZE (default: 128) bytes are discarded
* - Multi-value headers (e.g., Set-Cookie) only retain the last value
* - Headers are case-insensitive for lookup but case-preserving for storage
*
* @param[in] client The esp_http_client handle
* @param[in] key The header key
* @param[out] value Pointer to store the header value. This pointer should not be freed by the user.
*
* @return
* - ESP_OK: Header found
* - ESP_ERR_INVALID_ARG: Invalid arguments
* - ESP_ERR_NOT_FOUND: Header not found
*/
esp_err_t esp_http_client_get_response_header(esp_http_client_handle_t client, const char *key, char **value);
#endif // CONFIG_ESP_HTTP_CLIENT_SAVE_RESPONSE_HEADERS || __DOXYGEN__
/**
* @brief Get http request username.
* The address of username buffer will be assigned to value parameter.

View File

@@ -69,6 +69,7 @@ esp_err_t http_header_get(http_header_handle_t header, const char *key, char **v
*value = item->value;
} else {
*value = NULL;
return ESP_ERR_NOT_FOUND;
}
return ESP_OK;

View File

@@ -63,7 +63,7 @@ esp_err_t http_header_destroy(http_header_handle_t header);
esp_err_t http_header_set(http_header_handle_t header, const char *key, const char *value);
/**
* @brief Sample as `http_header_set` but the value can be formated
* @brief Sample as `http_header_set` but the value can be formatted
*
* @param[in] header The header
* @param[in] key The key
@@ -84,7 +84,7 @@ int http_header_set_format(http_header_handle_t header, const char *key, const c
*
* @return
* - ESP_OK
* - ESP_FAIL
* - ESP_ERR_NOT_FOUND
*/
esp_err_t http_header_get(http_header_handle_t header, const char *key, char **value);