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 b2b2df1e7a
commit 1db7fac8da
9 changed files with 188 additions and 4 deletions
+25
View File
@@ -48,4 +48,29 @@ menu "ESP HTTP client"
default y
help
Migrate ESP HTTP Client to use PSA Crypto.
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
@@ -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) {
@@ -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.
@@ -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;
@@ -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);