From c5dba210fb4feb7a4052433b25613fad3f74fe77 Mon Sep 17 00:00:00 2001 From: Ashish Sharma Date: Tue, 16 Jun 2026 16:08:01 +0800 Subject: [PATCH] feat(httpd): add httpd_req_get_hdr_value_str_ptr() to avoid value copy --- .../esp_http_server/include/esp_http_server.h | 27 +++++++++++++++++++ components/esp_http_server/src/httpd_parse.c | 24 +++++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/components/esp_http_server/include/esp_http_server.h b/components/esp_http_server/include/esp_http_server.h index 01fd06df1f9..9ed1db4fc7f 100644 --- a/components/esp_http_server/include/esp_http_server.h +++ b/components/esp_http_server/include/esp_http_server.h @@ -1007,6 +1007,33 @@ size_t httpd_req_get_hdr_value_len(httpd_req_t *r, const char *field); */ esp_err_t httpd_req_get_hdr_value_str(httpd_req_t *r, const char *field, char *val, size_t val_size); +/** + * @brief Similar to httpd_req_get_hdr_value_str() but avoids the string copy + * + * @note + * - This API is meant to be used with std::string_view or similar + * - The returned pointer references the header value kept in the request's + * internal scratch buffer. It is NULL-terminated; val_len is provided for + * convenience (e.g. constructing a std::string_view without a strlen()). + * - This API is supposed to be called only from the context of + * a URI handler where httpd_req_t* request pointer is valid. + * - The returned pointer must only be used within the URI handler and not + * after, since it will lead to use after free errors. In particular, once + * httpd_resp_send() is called all request headers are purged. + * + * @param[in] r The request being responded to + * @param[in] field The field to be searched in the header + * @param[out] val Pointer to a pointer that will be updated to the value string + * @param[out] val_len Pointer to a length that will be updated with the value length + * + * @return + * - ESP_OK : Field found; *val points to the value string and *val_len holds its length + * - ESP_ERR_NOT_FOUND : Key not found + * - ESP_ERR_INVALID_ARG : Null arguments + * - ESP_ERR_HTTPD_INVALID_REQ : Invalid HTTP request pointer + */ +esp_err_t httpd_req_get_hdr_value_str_ptr(httpd_req_t *r, const char *field, const char **val, size_t *val_len); + /** * @brief Get Query string length from the request URL * diff --git a/components/esp_http_server/src/httpd_parse.c b/components/esp_http_server/src/httpd_parse.c index 7775b17fafa..5b4a97f3913 100644 --- a/components/esp_http_server/src/httpd_parse.c +++ b/components/esp_http_server/src/httpd_parse.c @@ -1143,6 +1143,30 @@ esp_err_t httpd_req_get_hdr_value_str(httpd_req_t *r, const char *field, char *v return ESP_OK; } +esp_err_t httpd_req_get_hdr_value_str_ptr(httpd_req_t *r, const char *field, const char **val, size_t *val_len) +{ + /* val and val_len are output pointers that are dereferenced below, so they + * must be validated along with the other arguments to avoid a NULL write */ + if (r == NULL || field == NULL || val == NULL || val_len == NULL) { + return ESP_ERR_INVALID_ARG; + } + + if (!httpd_valid_req(r)) { + return ESP_ERR_HTTPD_INVALID_REQ; + } + + const char *val_ptr = httpd_find_hdr_value(r->aux, field); + if (val_ptr == NULL) { + return ESP_ERR_NOT_FOUND; + } + + /* The value lives NULL-terminated in the request scratch buffer; return a + * pointer to it instead of copying. Valid only within the URI handler. */ + *val = val_ptr; + *val_len = strlen(val_ptr); + return ESP_OK; +} + /* Helper function to get a cookie value from a cookie string of the type "cookie1=val1; cookie2=val2" */ esp_err_t static httpd_cookie_key_value(const char *cookie_str, const char *key, char *val, size_t *val_size) {