]> git.kaiwu.me - nginx.git/commitdiff
HTTP/3: skip unknown frames on request stream.
authorRoman Arutyunyan <arut@nginx.com>
Mon, 24 Aug 2020 06:56:36 +0000 (09:56 +0300)
committerRoman Arutyunyan <arut@nginx.com>
Mon, 24 Aug 2020 06:56:36 +0000 (09:56 +0300)
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.

src/http/v3/ngx_http_v3_parse.c
src/http/v3/ngx_http_v3_parse.h
src/http/v3/ngx_http_v3_request.c

index 1a7aa17f8f9c13df0a40e86d8eeb19afe83248fc..8f47b4d99f9b2a8a621f0387a0db5b81c70ee092 100644 (file)
@@ -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;
index 0c0af33b72e70c3a53cbffb7f76df334dd9c9083..856f021bd67addffb2a50ccb2d6358abd9bfef5f 100644 (file)
@@ -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;
index fe3c79bf0835dbcab47c534505465f43bac656b8..d9f4c9d553ac898daacf71fa75ee4803e54c745a 100644 (file)
@@ -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;