Mercurial > hg > nginx
changeset 8406:66feab03d9b7 quic
HTTP/3: restricted symbols in header names.
As per HTTP/3 draft 27, a request or response containing uppercase header
field names MUST be treated as malformed. Also, existing rules applied
when parsing HTTP/1 header names are also applied to HTTP/3 header names:
- null character is not allowed
- underscore character may or may not be treated as invalid depending on the
value of "underscores_in_headers"
- all non-alphanumeric characters with the exception of '-' are treated as
invalid
Also, the r->locase_header field is now filled while parsing an HTTP/3
header.
Error logging for invalid headers is fixed as well.
author | Roman Arutyunyan <arut@nginx.com> |
---|---|
date | Tue, 19 May 2020 15:34:00 +0300 |
parents | d2759e4cc437 |
children | d6feece1288a |
files | src/http/ngx_http_request.c src/http/v3/ngx_http_v3.h src/http/v3/ngx_http_v3_request.c |
diffstat | 3 files changed, 54 insertions(+), 8 deletions(-) [+] |
line wrap: on
line diff
--- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -1511,7 +1511,8 @@ ngx_http_process_request_headers(ngx_eve switch (r->http_version) { #if (NGX_HTTP_V3) case NGX_HTTP_VERSION_30: - rc = ngx_http_v3_parse_header(r, r->header_in); + rc = ngx_http_v3_parse_header(r, r->header_in, + cscf->underscores_in_headers); break; #endif @@ -1530,9 +1531,10 @@ ngx_http_process_request_headers(ngx_eve /* there was error while a header line parsing */ ngx_log_error(NGX_LOG_INFO, c->log, 0, - "client sent invalid header line: \"%*s\"", - r->header_end - r->header_name_start, - r->header_name_start); + "client sent invalid header line: \"%*s: %*s\"", + r->header_name_end - r->header_name_start, + r->header_name_start, + r->header_end - r->header_start, r->header_start); continue; }
--- a/src/http/v3/ngx_http_v3.h +++ b/src/http/v3/ngx_http_v3.h @@ -68,7 +68,8 @@ typedef struct { ngx_int_t ngx_http_v3_parse_request(ngx_http_request_t *r, ngx_buf_t *b); -ngx_int_t ngx_http_v3_parse_header(ngx_http_request_t *r, ngx_buf_t *b); +ngx_int_t ngx_http_v3_parse_header(ngx_http_request_t *r, ngx_buf_t *b, + ngx_uint_t allow_underscores); ngx_int_t ngx_http_v3_parse_request_body(ngx_http_request_t *r, ngx_buf_t *b, ngx_http_chunked_t *ctx); ngx_chain_t *ngx_http_v3_create_header(ngx_http_request_t *r);
--- a/src/http/v3/ngx_http_v3_request.c +++ b/src/http/v3/ngx_http_v3_request.c @@ -116,16 +116,23 @@ failed: ngx_int_t -ngx_http_v3_parse_header(ngx_http_request_t *r, ngx_buf_t *b) +ngx_http_v3_parse_header(ngx_http_request_t *r, ngx_buf_t *b, + ngx_uint_t allow_underscores) { + u_char ch; ngx_int_t rc; ngx_str_t *name, *value; + ngx_uint_t hash, i, n; ngx_connection_t *c; ngx_http_v3_parse_headers_t *st; c = r->connection; st = r->h3_parse; + if (st->header_rep.state == 0) { + r->invalid_header = 0; + } + if (st->state == 0) { if (r->header_name_start == NULL) { name = &st->header_rep.header.name; @@ -164,9 +171,45 @@ done: r->header_name_end = name->data + name->len; r->header_start = value->data; r->header_end = value->data + value->len; - r->header_hash = ngx_hash_key(name->data, name->len); + + hash = 0; + i = 0; + + for (n = 0; n < name->len; n++) { + ch = name->data[n]; + + if (ch >= 'A' && ch <= 'Z') { + /* + * A request or response containing uppercase + * header field names MUST be treated as malformed + */ + return NGX_HTTP_PARSE_INVALID_HEADER; + } + + if (ch == '\0') { + return NGX_HTTP_PARSE_INVALID_HEADER; + } - /* XXX r->lowcase_index = i; */ + if (ch == '_' && !allow_underscores) { + r->invalid_header = 1; + continue; + } + + if ((ch < 'a' || ch > 'z') + && (ch < '0' || ch > '9') + && ch != '-' && ch != '_') + { + r->invalid_header = 1; + continue; + } + + hash = ngx_hash(hash, ch); + r->lowcase_header[i++] = ch; + i &= (NGX_HTTP_LC_HEADER_LEN - 1); + } + + r->header_hash = hash; + r->lowcase_index = i; return NGX_OK; }