refactor(httpd): extract shared header field-value lookup helper

This commit is contained in:
Ashish Sharma
2026-06-16 16:04:55 +08:00
parent 9f84a7c3e3
commit 4fa92fb4bb

View File

@@ -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" */