changeset 8405:d2759e4cc437 quic

HTTP/3: split header parser in two functions. The first one parses pseudo-headers and is analagous to the request line parser in HTTP/1. The second one parses regular headers and is analogous to the header parser in HTTP/1. Additionally, error handling of client passing malformed uri is now fixed.
author Roman Arutyunyan <arut@nginx.com>
date Tue, 19 May 2020 15:29:10 +0300
parents e5d4f057a6cb
children 66feab03d9b7
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, 82 insertions(+), 73 deletions(-) [+]
line wrap: on
line diff
--- a/src/http/ngx_http_request.c
+++ b/src/http/ngx_http_request.c
@@ -1164,7 +1164,7 @@ ngx_http_process_request_line(ngx_event_
         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_request(r, r->header_in);
             break;
 #endif
 
--- a/src/http/v3/ngx_http_v3.h
+++ b/src/http/v3/ngx_http_v3.h
@@ -67,6 +67,7 @@ typedef struct {
 } ngx_http_v3_header_t;
 
 
+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_request_body(ngx_http_request_t *r, ngx_buf_t *b,
     ngx_http_chunked_t *ctx);
--- a/src/http/v3/ngx_http_v3_request.c
+++ b/src/http/v3/ngx_http_v3_request.c
@@ -38,21 +38,14 @@ struct {
 
 
 ngx_int_t
-ngx_http_v3_parse_header(ngx_http_request_t *r, ngx_buf_t *b)
+ngx_http_v3_parse_request(ngx_http_request_t *r, ngx_buf_t *b)
 {
-    size_t                        n;
+    size_t                        len;
     u_char                       *p;
-    ngx_int_t                     rc;
+    ngx_int_t                     rc, n;
     ngx_str_t                    *name, *value;
     ngx_connection_t             *c;
     ngx_http_v3_parse_headers_t  *st;
-    enum {
-        sw_start = 0,
-        sw_prev,
-        sw_headers,
-        sw_last,
-        sw_done
-    };
 
     c = r->connection;
     st = r->h3_parse;
@@ -68,23 +61,6 @@ ngx_http_v3_parse_header(ngx_http_reques
         r->h3_parse = st;
     }
 
-    switch (r->state) {
-
-    case sw_prev:
-        r->state = sw_headers;
-        return NGX_OK;
-
-    case sw_done:
-        goto done;
-
-    case sw_last:
-        r->state = sw_done;
-        return NGX_OK;
-
-    default:
-        break;
-    }
-
     while (b->pos < b->last) {
         rc = ngx_http_v3_parse_headers(c, st, *b->pos++);
 
@@ -99,52 +75,34 @@ ngx_http_v3_parse_header(ngx_http_reques
         name = &st->header_rep.header.name;
         value = &st->header_rep.header.value;
 
-        if (r->state == sw_start) {
-
-            if (ngx_http_v3_process_pseudo_header(r, name, value) == NGX_OK) {
-                if (rc == NGX_OK) {
-                    continue;
-                }
-
-                r->state = sw_done;
-
-            } else if (rc == NGX_OK) {
-                r->state = sw_prev;
-
-            } else {
-                r->state = sw_last;
-            }
+        n = ngx_http_v3_process_pseudo_header(r, name, value);
 
-            n = (r->method_end - r->method_start) + 1
-                + (r->uri_end - r->uri_start) + 1
-                + sizeof("HTTP/3") - 1;
-
-            p = ngx_pnalloc(c->pool, n);
-            if (p == NULL) {
-                goto failed;
-            }
-
-            r->request_start = p;
+        if (n == NGX_ERROR) {
+            goto failed;
+        }
 
-            p = ngx_cpymem(p, r->method_start, r->method_end - r->method_start);
-            *p++ = ' ';
-            p = ngx_cpymem(p, r->uri_start, r->uri_end - r->uri_start);
-            *p++ = ' ';
-            p = ngx_cpymem(p, "HTTP/3", sizeof("HTTP/3") - 1);
-
-            r->request_end = p;
-
-        } else if (rc == NGX_DONE) {
-            r->state = sw_done;
+        if (n == NGX_OK && rc == NGX_OK) {
+            continue;
         }
 
-        r->header_name_start = name->data;
-        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);
+        len = (r->method_end - r->method_start) + 1
+            + (r->uri_end - r->uri_start) + 1
+            + sizeof("HTTP/3") - 1;
+
+        p = ngx_pnalloc(c->pool, len);
+        if (p == NULL) {
+            goto failed;
+        }
 
-        /* XXX r->lowcase_index = i; */
+        r->request_start = p;
+
+        p = ngx_cpymem(p, r->method_start, r->method_end - r->method_start);
+        *p++ = ' ';
+        p = ngx_cpymem(p, r->uri_start, r->uri_end - r->uri_start);
+        *p++ = ' ';
+        p = ngx_cpymem(p, "HTTP/3", sizeof("HTTP/3") - 1);
+
+        r->request_end = p;
 
         return NGX_OK;
     }
@@ -153,14 +111,64 @@ ngx_http_v3_parse_header(ngx_http_reques
 
 failed:
 
-    return r->state == sw_start ? NGX_HTTP_PARSE_INVALID_REQUEST
-                                : NGX_HTTP_PARSE_INVALID_HEADER;
+    return NGX_HTTP_PARSE_INVALID_REQUEST;
+}
+
+
+ngx_int_t
+ngx_http_v3_parse_header(ngx_http_request_t *r, ngx_buf_t *b)
+{
+    ngx_int_t                     rc;
+    ngx_str_t                    *name, *value;
+    ngx_connection_t             *c;
+    ngx_http_v3_parse_headers_t  *st;
+
+    c = r->connection;
+    st = r->h3_parse;
+
+    if (st->state == 0) {
+        if (r->header_name_start == NULL) {
+            name = &st->header_rep.header.name;
+
+            if (name->len && name->data[0] != ':') {
+                goto done;
+            }
+        }
+
+        ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
+                       "http3 parse header done");
+
+        return NGX_HTTP_PARSE_HEADER_DONE;
+    }
+
+    while (b->pos < b->last) {
+        rc = ngx_http_v3_parse_headers(c, st, *b->pos++);
+
+        if (rc == NGX_ERROR) {
+            return NGX_HTTP_PARSE_INVALID_HEADER;
+        }
+
+        if (rc != NGX_AGAIN) {
+            goto done;
+        }
+    }
+
+    return NGX_AGAIN;
 
 done:
 
-    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 parse header done");
+    name = &st->header_rep.header.name;
+    value = &st->header_rep.header.value;
 
-    return NGX_HTTP_PARSE_HEADER_DONE;
+    r->header_name_start = name->data;
+    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);
+
+    /* XXX r->lowcase_index = i; */
+
+    return NGX_OK;
 }