]> git.kaiwu.me - nginx.git/commitdiff
Parsing HTTP/3 request body.
authorRoman Arutyunyan <arut@nginx.com>
Fri, 27 Mar 2020 16:41:06 +0000 (19:41 +0300)
committerRoman Arutyunyan <arut@nginx.com>
Fri, 27 Mar 2020 16:41:06 +0000 (19:41 +0300)
src/http/ngx_http.h
src/http/ngx_http_parse.c
src/http/ngx_http_request.c
src/http/ngx_http_request_body.c
src/http/v3/ngx_http_v3.h
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 8772001c0188ae01e390d1e54cd661776a9efc33..a0946c95a803e672e3de7f2a66204539a4c1e84a 100644 (file)
@@ -63,6 +63,9 @@ struct ngx_http_chunked_s {
     ngx_uint_t           state;
     off_t                size;
     off_t                length;
+#if (NGX_HTTP_V3)
+    void                *h3_parse;
+#endif
 };
 
 
index 28aa8b0dd18f3cf1188a24486cf25abb10f9eb30..92bcf12ad1ad02010af55e87b63fe9307d9987a7 100644 (file)
@@ -2185,6 +2185,12 @@ ngx_http_parse_chunked(ngx_http_request_t *r, ngx_buf_t *b,
         sw_trailer_header_almost_done
     } state;
 
+#if (NGX_HTTP_V3)
+    if (r->http_version == NGX_HTTP_VERSION_30) {
+        return ngx_http_v3_parse_request_body(r, b, ctx);
+    }
+#endif
+
     state = ctx->state;
 
     if (state == sw_chunk_data && ctx->size == 0) {
@@ -2371,6 +2377,11 @@ ngx_http_parse_chunked(ngx_http_request_t *r, ngx_buf_t *b,
         }
     }
 
+    if (b->last_buf) {
+        /* XXX client prematurely closed connection */
+        return NGX_ERROR;
+    }
+
 data:
 
     ctx->state = state;
index 6f168c8bdbe29cdc020f474e45dd807fc69ef9cc..4368e79c028f271feffb07591de3d47905f66751 100644 (file)
@@ -709,6 +709,7 @@ ngx_http_alloc_request(ngx_connection_t *c)
 #if (NGX_HTTP_V3)
     if (hc->quic) {
         r->http_version = NGX_HTTP_VERSION_30;
+        r->headers_in.chunked = 1;
     }
 #endif
 
index c4f092e59b1da71df1e50b44ea80eb36a3485852..b07d8562fe84abb96860c1ecb018883d64760795 100644 (file)
@@ -343,11 +343,10 @@ ngx_http_do_read_client_request_body(ngx_http_request_t *r)
             }
 
             if (n == 0) {
-                ngx_log_error(NGX_LOG_INFO, c->log, 0,
-                              "client prematurely closed connection");
+                rb->buf->last_buf = 1;
             }
 
-            if (n == 0 || n == NGX_ERROR) {
+            if (n == NGX_ERROR) {
                 c->error = 1;
                 return NGX_HTTP_BAD_REQUEST;
             }
@@ -355,7 +354,7 @@ ngx_http_do_read_client_request_body(ngx_http_request_t *r)
             rb->buf->last += n;
             r->request_length += n;
 
-            if (n == rest) {
+            if (n == rest || n == 0) {
                 /* pass buffer to request body filter chain */
 
                 out.buf = rb->buf;
@@ -805,11 +804,7 @@ ngx_http_test_expect(ngx_http_request_t *r)
 
     if (r->expect_tested
         || r->headers_in.expect == NULL
-        || r->http_version < NGX_HTTP_VERSION_11
-#if (NGX_HTTP_V2)
-        || r->stream != NULL
-#endif
-       )
+        || r->http_version != NGX_HTTP_VERSION_11)
     {
         return NGX_OK;
     }
@@ -914,6 +909,11 @@ ngx_http_request_body_length_filter(ngx_http_request_t *r, ngx_chain_t *in)
             b->last_buf = 1;
         }
 
+        if (cl->buf->last_buf && rb->rest > 0) {
+            /* XXX client prematurely closed connection */
+            return NGX_ERROR;
+        }
+
         *ll = tl;
         ll = &tl->next;
     }
@@ -950,7 +950,16 @@ ngx_http_request_body_chunked_filter(ngx_http_request_t *r, ngx_chain_t *in)
         }
 
         r->headers_in.content_length_n = 0;
-        rb->rest = 3;
+
+#if (NGX_HTTP_V3)
+        if (r->http_version == NGX_HTTP_VERSION_30) {
+            rb->rest = 1;
+
+        } else
+#endif
+        {
+            rb->rest = 3;
+        }
     }
 
     out = NULL;
index d28074d37f50ba4de3e7cd821975f78a1e0d8db0..3f35e985e093cddbca20856e2593391e37bced71 100644 (file)
@@ -68,6 +68,8 @@ typedef struct {
 
 
 ngx_int_t ngx_http_v3_parse_header(ngx_http_request_t *r, ngx_buf_t *b);
+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);
 ngx_chain_t *ngx_http_v3_create_trailers(ngx_http_request_t *r);
 
index 0fd44bc40f44ab75e6df9dd9404af464bbd85b3e..3be3802edcb2b60549806911be13878fc71154c9 100644 (file)
@@ -1421,3 +1421,61 @@ done:
     st->state = sw_start;
     return NGX_DONE;
 }
+
+
+ngx_int_t
+ngx_http_v3_parse_data(ngx_connection_t *c, ngx_http_v3_parse_data_t *st,
+    u_char ch)
+{
+    enum {
+        sw_start = 0,
+        sw_type,
+        sw_length
+    };
+
+    switch (st->state) {
+
+    case sw_start:
+
+        ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 parse data");
+
+        st->state = sw_type;
+
+        /* fall through */
+
+    case sw_type:
+
+        if (ngx_http_v3_parse_varlen_int(c, &st->vlint, ch) != NGX_DONE) {
+            break;
+        }
+
+        if (st->vlint.value != NGX_HTTP_V3_FRAME_DATA) {
+            return NGX_ERROR;
+        }
+
+        st->state = sw_length;
+        break;
+
+    case sw_length:
+
+        if (ngx_http_v3_parse_varlen_int(c, &st->vlint, ch) != NGX_DONE) {
+            break;
+        }
+
+        st->length = st->vlint.value;
+
+        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
+                       "http3 parse data frame len:%ui", st->length);
+
+        goto done;
+    }
+
+    return NGX_AGAIN;
+
+done:
+
+    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 parse data done");
+
+    st->state = sw_start;
+    return NGX_DONE;
+}
index 959da7941d074ddf7abe9fb6fc9c5d093e437324..ec78c7c35921cc0659a4e3d46c6beb71b51a5432 100644 (file)
@@ -105,6 +105,13 @@ typedef struct {
 } ngx_http_v3_parse_control_t;
 
 
+typedef struct {
+    ngx_uint_t                      state;
+    ngx_uint_t                      length;
+    ngx_http_v3_parse_varlen_int_t  vlint;
+} ngx_http_v3_parse_data_t;
+
+
 ngx_int_t ngx_http_v3_parse_varlen_int(ngx_connection_t *c,
     ngx_http_v3_parse_varlen_int_t *st, u_char ch);
 ngx_int_t ngx_http_v3_parse_prefix_int(ngx_connection_t *c,
@@ -141,5 +148,8 @@ ngx_int_t ngx_http_v3_parse_header_iwnr(ngx_connection_t *c,
 
 ngx_int_t ngx_http_v3_parse_decoder(ngx_connection_t *c, void *data, u_char ch);
 
+ngx_int_t ngx_http_v3_parse_data(ngx_connection_t *c,
+    ngx_http_v3_parse_data_t *st, u_char ch);
+
 
 #endif /* _NGX_HTTP_V3_PARSE_H_INCLUDED_ */
index 756a6f90dfd40f1bcc44517a3271aedf2ee2944b..911dbab364e2b3f160c74b939a2a4d621182d2f3 100644 (file)
@@ -241,6 +241,69 @@ ngx_http_v3_process_pseudo_header(ngx_http_request_t *r, ngx_str_t *name,
 }
 
 
+ngx_int_t
+ngx_http_v3_parse_request_body(ngx_http_request_t *r, ngx_buf_t *b,
+    ngx_http_chunked_t *ctx)
+{
+    ngx_int_t                  rc;
+    ngx_connection_t          *c;
+    ngx_http_v3_parse_data_t  *st;
+
+    c = r->connection;
+    st = ctx->h3_parse;
+
+    if (st == NULL) {
+        ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
+                       "http3 parse request body");
+
+        st = ngx_pcalloc(c->pool, sizeof(ngx_http_v3_parse_data_t));
+        if (st == NULL) {
+            goto failed;
+        }
+
+        r->h3_parse = st;
+    }
+
+    if (ctx->size) {
+        return NGX_OK;
+    }
+
+    while (b->pos < b->last) {
+        rc = ngx_http_v3_parse_data(c, st, *b->pos++);
+
+        if (rc == NGX_ERROR) {
+            goto failed;
+        }
+
+        if (rc == NGX_AGAIN) {
+            continue;
+        }
+
+        /* rc == NGX_DONE */
+
+        ctx->size = st->length;
+        return NGX_OK;
+    }
+
+    if (!b->last_buf) {
+        ctx->length = 1;
+        return NGX_AGAIN;
+    }
+
+    if (st->state) {
+        goto failed;
+    }
+
+    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 parse header done");
+
+    return NGX_DONE;
+
+failed:
+
+    return NGX_ERROR;
+}
+
+
 ngx_chain_t *
 ngx_http_v3_create_header(ngx_http_request_t *r)
 {