diff options
| author | Roman Arutyunyan <arut@nginx.com> | 2020-08-24 09:56:36 +0300 |
|---|---|---|
| committer | Roman Arutyunyan <arut@nginx.com> | 2020-08-24 09:56:36 +0300 |
| commit | d294369915461ba764426c709301b6c66ed33681 (patch) | |
| tree | 46e9bef435e7e40be5ca421b1c7e8a4465c304f1 | |
| parent | 46173bd4b40023fd5e35bfe77b9ac2205e0c6bb0 (diff) | |
| download | nginx-d294369915461ba764426c709301b6c66ed33681.tar.gz nginx-d294369915461ba764426c709301b6c66ed33681.tar.bz2 | |
HTTP/3: skip unknown frames on request stream.
As per HTTP/3 draft 29, section 4.1:
Frames of unknown types (Section 9), including reserved frames
(Section 7.2.8) MAY be sent on a request or push stream before,
after, or interleaved with other frames described in this section.
Also, trailers frame is now used as an indication of the request body end.
| -rw-r--r-- | src/http/v3/ngx_http_v3_parse.c | 63 | ||||
| -rw-r--r-- | src/http/v3/ngx_http_v3_parse.h | 2 | ||||
| -rw-r--r-- | src/http/v3/ngx_http_v3_request.c | 6 |
3 files changed, 60 insertions, 11 deletions
diff --git a/src/http/v3/ngx_http_v3_parse.c b/src/http/v3/ngx_http_v3_parse.c index 1a7aa17f8..8f47b4d99 100644 --- a/src/http/v3/ngx_http_v3_parse.c +++ b/src/http/v3/ngx_http_v3_parse.c @@ -155,7 +155,9 @@ ngx_http_v3_parse_headers(ngx_connection_t *c, ngx_http_v3_parse_headers_t *st, ngx_int_t rc; enum { sw_start = 0, + sw_type, sw_length, + sw_skip, sw_prefix, sw_verify, sw_header_rep, @@ -168,10 +170,18 @@ ngx_http_v3_parse_headers(ngx_connection_t *c, ngx_http_v3_parse_headers_t *st, ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 parse headers"); - if (ch != NGX_HTTP_V3_FRAME_HEADERS) { - return NGX_HTTP_V3_ERR_FRAME_UNEXPECTED; + st->state = sw_type; + + /* fall through */ + + case sw_type: + + rc = ngx_http_v3_parse_varlen_int(c, &st->vlint, ch); + if (rc != NGX_DONE) { + return rc; } + st->type = st->vlint.value; st->state = sw_length; break; @@ -184,12 +194,26 @@ ngx_http_v3_parse_headers(ngx_connection_t *c, ngx_http_v3_parse_headers_t *st, st->length = st->vlint.value; - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, - "http3 parse headers len:%ui", st->length); + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http3 parse headers type:%ui, len:%ui", + st->type, st->length); + + if (st->type != NGX_HTTP_V3_FRAME_HEADERS) { + st->state = st->length > 0 ? sw_skip : sw_type; + break; + } st->state = sw_prefix; break; + case sw_skip: + + if (--st->length == 0) { + st->state = sw_type; + } + + break; + case sw_prefix: if (st->length-- == 0) { @@ -1529,7 +1553,8 @@ ngx_http_v3_parse_data(ngx_connection_t *c, ngx_http_v3_parse_data_t *st, enum { sw_start = 0, sw_type, - sw_length + sw_length, + sw_skip }; switch (st->state) { @@ -1549,8 +1574,11 @@ ngx_http_v3_parse_data(ngx_connection_t *c, ngx_http_v3_parse_data_t *st, return rc; } - if (st->vlint.value != NGX_HTTP_V3_FRAME_DATA) { - return NGX_HTTP_V3_ERR_FRAME_UNEXPECTED; + st->type = st->vlint.value; + + if (st->type == NGX_HTTP_V3_FRAME_HEADERS) { + /* trailers */ + goto done; } st->state = sw_length; @@ -1565,10 +1593,25 @@ ngx_http_v3_parse_data(ngx_connection_t *c, ngx_http_v3_parse_data_t *st, st->length = st->vlint.value; - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, - "http3 parse data frame len:%ui", st->length); + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http3 parse data type:%ui, len:%ui", + st->type, st->length); - goto done; + if (st->type != NGX_HTTP_V3_FRAME_DATA && st->length > 0) { + st->state = sw_skip; + break; + } + + st->state = sw_type; + return NGX_OK; + + case sw_skip: + + if (--st->length == 0) { + st->state = sw_type; + } + + break; } return NGX_AGAIN; diff --git a/src/http/v3/ngx_http_v3_parse.h b/src/http/v3/ngx_http_v3_parse.h index 0c0af33b7..856f021bd 100644 --- a/src/http/v3/ngx_http_v3_parse.h +++ b/src/http/v3/ngx_http_v3_parse.h @@ -76,6 +76,7 @@ typedef struct { typedef struct { ngx_uint_t state; + ngx_uint_t type; ngx_uint_t length; ngx_http_v3_parse_varlen_int_t vlint; ngx_http_v3_parse_header_block_prefix_t prefix; @@ -107,6 +108,7 @@ typedef struct { typedef struct { ngx_uint_t state; + ngx_uint_t type; ngx_uint_t length; ngx_http_v3_parse_varlen_int_t vlint; } ngx_http_v3_parse_data_t; diff --git a/src/http/v3/ngx_http_v3_request.c b/src/http/v3/ngx_http_v3_request.c index fe3c79bf0..d9f4c9d55 100644 --- a/src/http/v3/ngx_http_v3_request.c +++ b/src/http/v3/ngx_http_v3_request.c @@ -418,7 +418,11 @@ ngx_http_v3_parse_request_body(ngx_http_request_t *r, ngx_buf_t *b, continue; } - /* rc == NGX_DONE */ + if (rc == NGX_DONE) { + return NGX_DONE; + } + + /* rc == NGX_OK */ ctx->size = st->length; ctx->state = sw_start; |
