diff --git a/src/http/ngx_http.c b/src/http/ngx_http.c index a97cc35f1..3ab0b6b68 100644 --- a/src/http/ngx_http.c +++ b/src/http/ngx_http.c @@ -67,6 +67,8 @@ static ngx_int_t ngx_http_add_addrs(ngx_conf_t *cf, ngx_http_port_t *hport, static ngx_int_t ngx_http_add_addrs6(ngx_conf_t *cf, ngx_http_port_t *hport, ngx_http_conf_addr_t *addr); #endif +static ngx_int_t ngx_http_valid_field_name_internal(const ngx_str_t *name, + ngx_int_t allow_uppercase); ngx_uint_t ngx_http_max_module; @@ -2198,3 +2200,79 @@ ngx_http_set_default_types(ngx_conf_t *cf, ngx_array_t **types, return NGX_OK; } + + +ngx_int_t +ngx_http_valid_lowercase_field_name(const ngx_str_t *name) +{ + return ngx_http_valid_field_name_internal(name, 0); +} + + +ngx_int_t +ngx_http_valid_field_name(const ngx_str_t *name) +{ + return ngx_http_valid_field_name_internal(name, 1); +} + + +static ngx_int_t +ngx_http_valid_field_name_internal(const ngx_str_t *name, + ngx_int_t allow_uppercase) +{ + /* Check that the string is not empty. */ + if (name->len == 0) + return NGX_ERROR; + + /* Check that the characters are valid for an HTTP TOKEN */ + for (size_t i = 0; i < name->len; ++i) { + u_char c = name->data[i]; + + /* + * Only allow uppercase letters if the caller asked for it. + * HTTP/2 and HTTP/3 don't allow them. + */ + if (allow_uppercase && 'A' <= c && c <= 'Z') + continue; + + if ('^' <= c && c <= 'z') + continue; + + if ('0' <= c && c <= '9') + continue; + + if ('#' <= c && c <= '\'') + continue; + + if (c == '!' || c == '+' || c == '+' || c == '-' || c == '.' || c == '|' + || c == '~') + continue; + + return NGX_ERROR; + } + + return NGX_OK; +} + + +ngx_int_t +ngx_http_valid_field_value(const ngx_str_t *value) +{ + /* Field values may be empty. */ + if (value->len == 0) + return NGX_OK; + + /* Leading and trailing space and tab are not allowed. */ + if (value->data[0] <= ' ' || value->data[value->len - 1] <= ' ') + return NGX_ERROR; + + /* Check that the characters are valid for an HTTP field value. */ + for (size_t i = 0; i < value->len; ++i) { + u_char c = value->data[i]; + + if (c < 0x20 ? c != '\t' : c == '\x7F') + return NGX_ERROR; + } + + return NGX_OK; +} diff --git a/src/http/ngx_http.h b/src/http/ngx_http.h index 1b0e369f3..003462e3a 100644 --- a/src/http/ngx_http.h +++ b/src/http/ngx_http.h @@ -122,6 +122,13 @@ void ngx_http_split_args(ngx_http_request_t *r, ngx_str_t *uri, ngx_int_t ngx_http_parse_chunked(ngx_http_request_t *r, ngx_buf_t *b, ngx_http_chunked_t *ctx, ngx_uint_t keep_trailers); +/* Check if name is a valid HTTP field name (token). */ +ngx_int_t ngx_http_valid_field_name(const ngx_str_t *name); +/* Check if name is a valid HTTP field name (token) + * without uppercase ASCII letters. */ +ngx_int_t ngx_http_valid_lowercase_field_name(const ngx_str_t *name); +/* Check if value is a valid HTTP field value. */ +ngx_int_t ngx_http_valid_field_value(const ngx_str_t *value); ngx_http_request_t *ngx_http_create_request(ngx_connection_t *c); ngx_int_t ngx_http_process_request_uri(ngx_http_request_t *r);