From 4fa92fb4bba65bbc8e14349354c7332f73ca71bc Mon Sep 17 00:00:00 2001 From: Ashish Sharma Date: Tue, 16 Jun 2026 16:04:55 +0800 Subject: [PATCH] refactor(httpd): extract shared header field-value lookup helper --- components/esp_http_server/src/httpd_parse.c | 165 ++++++++----------- 1 file changed, 71 insertions(+), 94 deletions(-) diff --git a/components/esp_http_server/src/httpd_parse.c b/components/esp_http_server/src/httpd_parse.c index 44f1d6d6d4a..7775b17fafa 100644 --- a/components/esp_http_server/src/httpd_parse.c +++ b/components/esp_http_server/src/httpd_parse.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2018-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2018-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -1046,6 +1046,60 @@ esp_err_t httpd_req_get_url_query_str_ptr(httpd_req_t *r, const char **buf, size return ESP_ERR_NOT_FOUND; } +/* Advance the scratch pointer past the current header line to the next one. + * Header lines are separated by null characters (their line terminators are + * overwritten with '\0' during parsing). */ +static const char *httpd_next_hdr(const char *hdr_ptr) +{ + /* Jump to the end of the current field-value string */ + hdr_ptr = 1 + strchr(hdr_ptr, '\0'); + + /* Skip all null characters with which the line terminators were overwritten */ + while (*hdr_ptr == '\0') { + hdr_ptr++; + } + return hdr_ptr; +} + +/* Locate the value of a header field within the request's scratch buffer. + * Returns a pointer to the NULL-terminated value (leading spaces skipped), + * or NULL if the field is not present. The caller must validate r/field and + * the request pointer before calling. */ +static const char *httpd_find_hdr_value(struct httpd_req_aux *ra, const char *field) +{ + const char *hdr_ptr = ra->scratch; /*!< Request headers are kept in scratch buffer */ + unsigned count = ra->req_hdrs_count; /*!< Count set during parsing */ + const size_t field_len = strlen(field); + + while (count--) { + /* Search for the ':' character. Else, it would mean + * that the field is invalid */ + const char *val_ptr = strchr(hdr_ptr, ':'); + if (!val_ptr) { + break; + } + + /* If the field does not match, continue searching. Compare lengths + * first as the field from the header is not null terminated (has ':' + * in the end). */ + if (((size_t)(val_ptr - hdr_ptr) != field_len) || + strncasecmp(hdr_ptr, field, field_len)) { + if (count) { + hdr_ptr = httpd_next_hdr(hdr_ptr); + } + continue; + } + + /* Skip ':' and any preceding spaces */ + val_ptr++; + while (*val_ptr == ' ') { + val_ptr++; + } + return val_ptr; + } + return NULL; +} + /* 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) { @@ -1057,48 +1111,8 @@ size_t httpd_req_get_hdr_value_len(httpd_req_t *r, const char *field) return 0; } - struct httpd_req_aux *ra = r->aux; - const char *hdr_ptr = ra->scratch; /*!< Request headers are kept in scratch buffer */ - unsigned count = ra->req_hdrs_count; /*!< Count set during parsing */ - - while (count--) { - /* Search for the ':' character. Else, it would mean - * that the field is invalid - */ - const char *val_ptr = strchr(hdr_ptr, ':'); - if (!val_ptr) { - break; - } - - /* If the field, does not match, continue searching. - * Compare lengths first as field from header is not - * null terminated (has ':' in the end). - */ - if ((val_ptr - hdr_ptr != strlen(field)) || - (strncasecmp(hdr_ptr, field, strlen(field)))) { - if (count) { - /* Jump to end of header field-value string */ - hdr_ptr = 1 + strchr(hdr_ptr, '\0'); - - /* Skip all null characters (with which the line - * terminators had been overwritten) */ - while (*hdr_ptr == '\0') { - hdr_ptr++; - } - } - continue; - } - - /* Skip ':' */ - val_ptr++; - - /* Skip preceding space */ - while ((*val_ptr != '\0') && (*val_ptr == ' ')) { - val_ptr++; - } - return strlen(val_ptr); - } - return 0; + const char *val_ptr = httpd_find_hdr_value(r->aux, field); + return val_ptr ? strlen(val_ptr) : 0; } /* Get the value of a field from the request headers */ @@ -1112,58 +1126,21 @@ esp_err_t httpd_req_get_hdr_value_str(httpd_req_t *r, const char *field, char *v return ESP_ERR_HTTPD_INVALID_REQ; } - struct httpd_req_aux *ra = r->aux; - const char *hdr_ptr = ra->scratch; /*!< Request headers are kept in scratch buffer */ - unsigned count = ra->req_hdrs_count; /*!< Count set during parsing */ - - while (count--) { - /* Search for the ':' character. Else, it would mean - * that the field is invalid - */ - const char *val_ptr = strchr(hdr_ptr, ':'); - if (!val_ptr) { - break; - } - - /* If the field, does not match, continue searching. - * Compare lengths first as field from header is not - * null terminated (has ':' in the end). - */ - if ((val_ptr - hdr_ptr != strlen(field)) || - (strncasecmp(hdr_ptr, field, strlen(field)))) { - if (count) { - /* Jump to end of header field-value string */ - hdr_ptr = 1 + strchr(hdr_ptr, '\0'); - - /* Skip all null characters (with which the line - * terminators had been overwritten) */ - while (*hdr_ptr == '\0') { - hdr_ptr++; - } - } - continue; - } - - /* Skip ':' */ - val_ptr++; - - /* Skip preceding space */ - while ((*val_ptr != '\0') && (*val_ptr == ' ')) { - val_ptr++; - } - - /* Get the NULL terminated value and copy it to the caller's buffer. - * Note `strlcpy()` will always return the size of the source string - * including terminimating null.*/ - size_t full_size = strlcpy(val, val_ptr, val_size); - - /* If buffer length is smaller than needed, return truncation error */ - if (val_size < full_size) { - return ESP_ERR_HTTPD_RESULT_TRUNC; - } - return ESP_OK; + const char *val_ptr = httpd_find_hdr_value(r->aux, field); + if (val_ptr == NULL) { + return ESP_ERR_NOT_FOUND; } - return ESP_ERR_NOT_FOUND; + + /* Get the NULL terminated value and copy it to the caller's buffer. + * Note `strlcpy()` will always return the size of the source string + * including terminating null. */ + size_t full_size = strlcpy(val, val_ptr, val_size); + + /* If buffer length is smaller than needed, return truncation error */ + if (val_size < full_size) { + return ESP_ERR_HTTPD_RESULT_TRUNC; + } + return ESP_OK; } /* Helper function to get a cookie value from a cookie string of the type "cookie1=val1; cookie2=val2" */