diff src/http/v3/ngx_http_v3_request.c @ 8226:268f4389130d quic

Refactored HTTP/3 parser.
author Roman Arutyunyan <arut@nginx.com>
date Wed, 18 Mar 2020 13:46:35 +0300
parents 1307308c3cf1
children 31f7c697b6d9
line wrap: on
line diff
--- a/src/http/v3/ngx_http_v3_request.c
+++ b/src/http/v3/ngx_http_v3_request.c
@@ -10,15 +10,6 @@
 #include <ngx_http.h>
 
 
-#define NGX_HTTP_V3_FRAME_DATA          0x00
-#define NGX_HTTP_V3_FRAME_HEADERS       0x01
-#define NGX_HTTP_V3_FRAME_CANCEL_PUSH   0x03
-#define NGX_HTTP_V3_FRAME_SETTINGS      0x04
-#define NGX_HTTP_V3_FRAME_PUSH_PROMISE  0x05
-#define NGX_HTTP_V3_FRAME_GOAWAY        0x07
-#define NGX_HTTP_V3_FRAME_MAX_PUSH_ID   0x0d
-
-
 static ngx_int_t ngx_http_v3_process_pseudo_header(ngx_http_request_t *r,
     ngx_str_t *name, ngx_str_t *value);
 
@@ -47,6 +38,110 @@ struct {
 
 
 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;
+    enum {
+        sw_start = 0,
+        sw_prev,
+        sw_headers,
+        sw_last,
+        sw_done
+    };
+
+    c = r->connection;
+    st = r->h3_parse;
+
+    if (st == NULL) {
+        ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 parse header");
+
+        st = ngx_pcalloc(c->pool, sizeof(ngx_http_v3_parse_headers_t));
+        if (st == NULL) {
+            goto failed;
+        }
+
+        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;
+    }
+
+    for ( /* void */ ; b->pos < b->last; b->pos++) {
+
+        rc = ngx_http_v3_parse_headers(c, st, *b->pos);
+
+        if (rc == NGX_ERROR) {
+            goto failed;
+        }
+
+        if (rc == NGX_AGAIN) {
+            continue;
+        }
+
+        name = &st->header_rep.header.name;
+        value = &st->header_rep.header.value;
+
+        if (r->state == sw_start
+            && ngx_http_v3_process_pseudo_header(r, name, value) != NGX_OK)
+        {
+            if (rc == NGX_DONE) {
+                r->state = sw_last;
+            } else {
+                r->state = sw_prev;
+            }
+
+        } else if (rc == NGX_DONE) {
+            r->state = sw_done;
+        }
+
+        if (r->state == sw_start) {
+            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);
+
+        /* XXX r->lowcase_index = i; */
+
+        return NGX_OK;
+    }
+
+    return NGX_AGAIN;
+
+failed:
+
+    return r->state == sw_start ? NGX_HTTP_PARSE_INVALID_REQUEST
+                                : NGX_HTTP_PARSE_INVALID_HEADER;
+
+done:
+
+    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 parse header done");
+
+    return NGX_HTTP_PARSE_HEADER_DONE;
+}
+
+#if 0
+ngx_int_t
 ngx_http_v3_parse_header(ngx_http_request_t *r, ngx_buf_t *b, ngx_uint_t pseudo)
 {
     u_char                *p, ch;
@@ -167,11 +262,14 @@ again:
                 break;
             }
 
-            /* fall through */
+            length &= 0x3fffff;
+            state = sw_header_block;
+            break;
 
         case sw_length_3:
 
-            length &= 0x3fffff;
+            length = (length << 8) + ch;
+            length &= 0x3fffffff;
             state = sw_header_block;
             break;
 
@@ -567,6 +665,7 @@ failed:
 
     return NGX_HTTP_PARSE_INVALID_REQUEST;
 }
+#endif
 
 
 static ngx_int_t
@@ -576,6 +675,10 @@ ngx_http_v3_process_pseudo_header(ngx_ht
     ngx_uint_t         i;
     ngx_connection_t  *c;
 
+    if (name->len == 0 || name->data[0] != ':') {
+        return NGX_DECLINED;
+    }
+
     c = r->connection;
 
     if (name->len == 7 && ngx_strncmp(name->data, ":method", 7) == 0) {
@@ -635,14 +738,10 @@ ngx_http_v3_process_pseudo_header(ngx_ht
         return NGX_OK;
     }
 
-    if (name->len && name->data[0] == ':') {
-        ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0,
-                       "http3 unknown pseudo header \"%V\" \"%V\"",
-                       name, value);
-        return NGX_OK;
-    }
+    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0,
+                   "http3 unknown pseudo header \"%V\" \"%V\"", name, value);
 
-    return NGX_DONE;
+    return NGX_OK;
 }
 
 
@@ -789,7 +888,7 @@ ngx_http_v3_create_header(ngx_http_reque
         b->last = (u_char *) ngx_http_v3_encode_prefix_int(b->last, 25, 4);
         *b->last = 0;
         b->last = (u_char *) ngx_http_v3_encode_prefix_int(b->last, 3, 7);
-        b->last = ngx_sprintf(b->last, "%03ui ", r->headers_out.status);
+        b->last = ngx_sprintf(b->last, "%03ui", r->headers_out.status);
     }
 
     if (r->headers_out.server == NULL) {