From 3c64eea401b137dc230ffe75628ed3a298e26d4b Mon Sep 17 00:00:00 2001 From: 0xFEEDC0DE64 Date: Tue, 2 Jun 2026 16:54:23 +0200 Subject: [PATCH] feat(httpd): avoid useless string copy by introducing httpd_req_get_url_query_str_ptr() --- .../esp_http_server/include/esp_http_server.h | 30 +++++++++++++++++++ components/esp_http_server/src/httpd_parse.c | 30 +++++++++++++++++++ 2 files changed, 60 insertions(+) diff --git a/components/esp_http_server/include/esp_http_server.h b/components/esp_http_server/include/esp_http_server.h index b4beb20dd13..9bfa653c0e6 100644 --- a/components/esp_http_server/include/esp_http_server.h +++ b/components/esp_http_server/include/esp_http_server.h @@ -1053,6 +1053,36 @@ size_t httpd_req_get_url_query_len(httpd_req_t *r); */ esp_err_t httpd_req_get_url_query_str(httpd_req_t *r, char *buf, size_t buf_len); +/** + * @brief Similar to httpd_req_get_url_query_str() but avoids the string copy + * + * @note + * - This API is meant to be used with std::string_view or similar + * - Presently, the user can fetch the full URL query string, but decoding + * will have to be performed by the user. Request headers can be read using + * httpd_req_get_hdr_value_str() to know the 'Content-Type' (eg. Content-Type: + * application/x-www-form-urlencoded) and then the appropriate decoding + * algorithm needs to be applied. + * - This API is supposed to be called only from the context of + * a URI handler where httpd_req_t* request pointer is valid + * - The byte range between buf and buf_len should only be used withing + * the URI handler and not after since it will lead to use after free + * errors + * + * @param[in] r The request being responded to + * @param[out] buf Pointer to a pointer that should be updated to the begin of + * the buffer + * @param[out] buf_len Pointer of length of output buffer + * + * @return + * - ESP_OK : Query is found in the request URL and copied to buffer + * - ESP_FAIL : uri is empty + * - ESP_ERR_NOT_FOUND : Query not found + * - ESP_ERR_INVALID_ARG : Null arguments + * - ESP_ERR_HTTPD_INVALID_REQ : Invalid HTTP request pointer + */ +esp_err_t httpd_req_get_url_query_str_ptr(httpd_req_t *r, const char **buf, size_t *buf_len); + /** * @brief Helper function to get a URL query tag from a query * string of the type param1=val1¶m2=val2 diff --git a/components/esp_http_server/src/httpd_parse.c b/components/esp_http_server/src/httpd_parse.c index d097db5f197..8105c440251 100644 --- a/components/esp_http_server/src/httpd_parse.c +++ b/components/esp_http_server/src/httpd_parse.c @@ -1014,6 +1014,36 @@ esp_err_t httpd_req_get_url_query_str(httpd_req_t *r, char *buf, size_t buf_len) return ESP_ERR_NOT_FOUND; } +esp_err_t httpd_req_get_url_query_str_ptr(httpd_req_t *r, const char **buf, size_t *buf_len) +{ + if (r == NULL || buf == NULL) { + return ESP_ERR_INVALID_ARG; + } + + if (!httpd_valid_req(r)) { + return ESP_ERR_HTTPD_INVALID_REQ; + } + + if (r->uri[0] == '\0') { + ESP_LOGD(TAG, "uri is empty"); + return ESP_FAIL; + } + + struct httpd_req_aux *ra = r->aux; + struct http_parser_url *res = &ra->url_parse_res; + + /* Check if query field is present in the URL */ + if (res->field_set & (1 << UF_QUERY)) { + *buf = r->uri + res->field_data[UF_QUERY].off; + + /* Query data length does not include terminating null */ + *buf_len = res->field_data[UF_QUERY].len; + + return ESP_OK; + } + return ESP_ERR_NOT_FOUND; +} + /* Get the length of the value string of a header request field */ size_t httpd_req_get_hdr_value_len(httpd_req_t *r, const char *field) {