changeset 8233:1e45c02f6376 quic

HTTP/3 $request_line variable.
author Roman Arutyunyan <arut@nginx.com>
date Wed, 18 Mar 2020 20:22:16 +0300
parents 253cf267f95a
children 19bb9edcd8bd
files src/http/ngx_http_request.c src/http/v3/ngx_http_v3_request.c
diffstat 2 files changed, 37 insertions(+), 540 deletions(-) [+]
line wrap: on
line diff
--- a/src/http/ngx_http_request.c
+++ b/src/http/ngx_http_request.c
@@ -1177,7 +1177,7 @@ ngx_http_process_request_line(ngx_event_
 
             r->request_line.len = r->request_end - r->request_start;
             r->request_line.data = r->request_start;
-            r->request_length = r->header_in->pos - r->request_start;
+            r->request_length = r->header_in->pos - r->request_start; /* XXX */
 
             ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
                            "http request line: \"%V\"", &r->request_line);
@@ -1593,7 +1593,7 @@ ngx_http_process_request_headers(ngx_eve
             ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                            "http header done");
 
-            r->request_length += r->header_in->pos - r->header_name_start;
+            r->request_length += r->header_in->pos - r->header_name_start; /* XXX */
 
             r->http_state = NGX_HTTP_PROCESS_REQUEST_STATE;
 
--- a/src/http/v3/ngx_http_v3_request.c
+++ b/src/http/v3/ngx_http_v3_request.c
@@ -40,6 +40,8 @@ struct {
 ngx_int_t
 ngx_http_v3_parse_header(ngx_http_request_t *r, ngx_buf_t *b)
 {
+    size_t                        n;
+    u_char                       *p;
     ngx_int_t                     rc;
     ngx_str_t                    *name, *value;
     ngx_connection_t             *c;
@@ -97,23 +99,45 @@ 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
-            && ngx_http_v3_process_pseudo_header(r, name, value) != NGX_OK)
-        {
-            if (rc == NGX_DONE) {
+        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;
-            } else {
-                r->state = sw_prev;
+            }
+
+            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;
+
+            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 (r->state == sw_start) {
-            continue;
-        }
-
         r->header_name_start = name->data;
         r->header_name_end = name->data + name->len;
         r->header_start = value->data;
@@ -139,533 +163,6 @@ 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;
-    ngx_str_t              name, value;
-    ngx_int_t              rc;
-    ngx_uint_t             length, index, insert_count, sign, base, delta_base,
-                           huffman, dynamic, offset;
-    ngx_connection_t      *c;
-    ngx_http_v3_header_t  *h;
-    enum {
-        sw_start = 0,
-        sw_length,
-        sw_length_1,
-        sw_length_2,
-        sw_length_3,
-        sw_header_block,
-        sw_req_insert_count,
-        sw_delta_base,
-        sw_read_delta_base,
-        sw_header,
-        sw_old_header,
-        sw_header_ri,
-        sw_header_pbi,
-        sw_header_lri,
-        sw_header_lpbi,
-        sw_header_l_name_len,
-        sw_header_l_name,
-        sw_header_value_len,
-        sw_header_read_value_len,
-        sw_header_value
-    } state;
-
-    c = r->connection;
-
-    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
-                   "http3 parse header, pseudo:%ui", pseudo);
-
-    if (r->state == sw_old_header) {
-        r->state = sw_header;
-        return NGX_OK;
-    }
-
-    length = r->h3_length;
-    index = r->h3_index;
-    insert_count = r->h3_insert_count;
-    sign = r->h3_sign;
-    delta_base = r->h3_delta_base;
-    huffman = r->h3_huffman;
-    dynamic = r->h3_dynamic;
-    offset = r->h3_offset;
-
-    name.data = r->header_name_start;
-    name.len = r->header_name_end - r->header_name_start;
-    value.data = r->header_start;
-    value.len = r->header_end - r->header_start;
-
-    if (r->state == sw_start) {
-        length = 1;
-    }
-
-again:
-
-    state = r->state;
-
-    if (state == sw_header && length == 0) {
-        r->state = sw_start;
-        return NGX_HTTP_PARSE_HEADER_DONE;
-    }
-
-    for (p = b->pos; p < b->last; p++) {
-
-        if (state >= sw_header_block && length-- == 0) {
-            goto failed;
-        }
-
-        ch = *p;
-
-        switch (state) {
-
-        case sw_start:
-
-            if (ch != NGX_HTTP_V3_FRAME_HEADERS) {
-                goto failed;
-            }
-
-            r->request_start = p;
-            state = sw_length;
-            break;
-
-        case sw_length:
-
-            length = ch;
-            if (length & 0xc0) {
-                state = sw_length_1;
-                break;
-            }
-
-            state = sw_header_block;
-            break;
-
-        case sw_length_1:
-
-            length = (length << 8) + ch;
-            if ((length & 0xc000) != 0x4000) {
-                state = sw_length_2;
-                break;
-            }
-
-            length &= 0x3fff;
-            state = sw_header_block;
-            break;
-
-        case sw_length_2:
-
-            length = (length << 8) + ch;
-            if ((length & 0xc00000) != 0x800000) {
-                state = sw_length_3;
-                break;
-            }
-
-            length &= 0x3fffff;
-            state = sw_header_block;
-            break;
-
-        case sw_length_3:
-
-            length = (length << 8) + ch;
-            length &= 0x3fffffff;
-            state = sw_header_block;
-            break;
-
-        case sw_header_block:
-
-            ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
-                           "http3 header block length:%ui", length);
-
-            if (ch != 0xff) {
-                insert_count = ch;
-                state = sw_delta_base;
-                break;
-            }
-
-            insert_count = 0;
-            state = sw_req_insert_count;
-            break;
-
-        case sw_req_insert_count:
-
-            insert_count = (insert_count << 7) + (ch & 0x7f);
-            if (ch & 0x80) {
-                break;
-            }
-
-            insert_count += 0xff;
-            state = sw_delta_base;
-            break;
-
-        case sw_delta_base:
-
-            sign = (ch & 0x80) ? 1 : 0;
-            delta_base = ch & 0x7f;
-
-            if (delta_base != 0x7f) {
-                ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0,
-                               "http3 header block "
-                               "insert_count:%ui, sign:%ui, delta_base:%ui",
-                               insert_count, sign, delta_base);
-                goto done;
-            }
-
-            delta_base = 0;
-            state = sw_read_delta_base;
-            break;
-
-        case sw_read_delta_base:
-
-            delta_base = (delta_base << 7) + (ch & 0x7f);
-            if (ch & 0x80) {
-                break;
-            }
-
-            delta_base += 0x7f;
-
-            ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0,
-                           "http3 header block "
-                           "insert_count:%ui, sign:%ui, delta_base:%ui",
-                           insert_count, sign, delta_base);
-            goto done;
-
-        case sw_header:
-
-            index = 0;
-            huffman = 0;
-            ngx_str_null(&name);
-            ngx_str_null(&value);
-
-            if (ch & 0x80) {
-                /* Indexed Header Field */
-
-                dynamic = (ch & 0x40) ? 0 : 1;
-                index = ch & 0x3f;
-
-                if (index != 0x3f) {
-                    goto done;
-                }
-
-                index = 0;
-                state = sw_header_ri;
-                break;
-            }
-
-            if (ch & 0x40) {
-                /* Literal Header Field With Name Reference */
-
-                dynamic = (ch & 0x10) ? 0 : 1;
-                index = ch & 0x0f;
-
-                if (index != 0x0f) {
-                    state = sw_header_value_len;
-                    break;
-                }
-
-                index = 0;
-                state = sw_header_lri;
-                break;
-            }
-
-            if (ch & 0x20) {
-                /* Literal Header Field Without Name Reference */
-
-                huffman = (ch & 0x08) ? 1 : 0;
-                name.len = ch & 0x07;
-
-                if (name.len == 0) {
-                    goto failed;
-                }
-
-                if (name.len != 0x07) {
-                    offset = 0;
-                    state = sw_header_l_name;
-                    break;
-                }
-
-                name.len = 0;
-                state = sw_header_l_name_len;
-                break;
-            }
-
-            if (ch & 10) {
-                /* Indexed Header Field With Post-Base Index */
-
-                dynamic = 2;
-                index = ch & 0x0f;
-
-                if (index != 0x0f) {
-                    goto done;
-                }
-
-                index = 0;
-                state = sw_header_pbi;
-                break;
-            }
-
-            /* Literal Header Field With Post-Base Name Reference */
-
-            dynamic = 2;
-            index = ch & 0x07;
-
-            if (index != 0x07) {
-                state = sw_header_value_len;
-                break;
-            }
-
-            index = 0;
-            state = sw_header_lpbi;
-            break;
-
-        case sw_header_ri:
-
-            index = (index << 7) + (ch & 0x7f);
-            if (ch & 0x80) {
-                break;
-            }
-
-            index += 0x3f;
-            goto done;
-
-        case sw_header_pbi:
-
-            index = (index << 7) + (ch & 0x7f);
-            if (ch & 0x80) {
-                break;
-            }
-
-            index += 0x0f;
-            goto done;
-
-        case sw_header_lri:
-
-            index = (index << 7) + (ch & 0x7f);
-            if (ch & 0x80) {
-                break;
-            }
-
-            index += 0x0f;
-            state = sw_header_value_len;
-            break;
-
-        case sw_header_lpbi:
-
-            index = (index << 7) + (ch & 0x7f);
-            if (ch & 0x80) {
-                break;
-            }
-
-            index += 0x07;
-            state = sw_header_value_len;
-            break;
-
-
-        case sw_header_l_name_len:
-
-            name.len = (name.len << 7) + (ch & 0x7f);
-            if (ch & 0x80) {
-                break;
-            }
-
-            name.len += 0x07;
-            offset = 0;
-            state = sw_header_l_name;
-            break;
-
-        case sw_header_l_name:
-            if (offset++ == 0) {
-                name.data = p;
-            }
-
-            if (offset != name.len) {
-                break;
-            }
-
-            if (huffman) {
-                if (ngx_http_v3_decode_huffman(c, &name) != NGX_OK) {
-                    goto failed;
-                }
-            }
-
-            state = sw_header_value_len;
-            break;
-
-        case sw_header_value_len:
-
-            huffman = (ch & 0x80) ? 1 : 0;
-            value.len = ch & 0x7f;
-
-            if (value.len == 0) {
-                value.data = p;
-                goto done;
-            }
-
-            if (value.len != 0x7f) {
-                offset = 0;
-                state = sw_header_value;
-                break;
-            }
-
-            value.len = 0;
-            state = sw_header_read_value_len;
-            break;
-
-        case sw_header_read_value_len:
-
-            value.len = (value.len << 7) + (ch & 0x7f);
-            if (ch & 0x80) {
-                break;
-            }
-
-            value.len += 0x7f;
-            offset = 0;
-            state = sw_header_value;
-            break;
-
-        case sw_header_value:
-
-            if (offset++ == 0) {
-                value.data = p;
-            }
-
-            if (offset != value.len) {
-                break;
-            }
-
-            if (huffman) {
-                if (ngx_http_v3_decode_huffman(c, &value) != NGX_OK) {
-                    goto failed;
-                }
-            }
-
-            goto done;
-
-        case sw_old_header:
-
-            break;
-        }
-    }
-
-    b->pos = p;
-    r->state = state;
-    r->h3_length = length;
-    r->h3_index = index;
-    r->h3_insert_count = insert_count;
-    r->h3_sign = sign;
-    r->h3_delta_base = delta_base;
-    r->h3_huffman = huffman;
-    r->h3_dynamic = dynamic;
-    r->h3_offset = offset;
-
-    /* XXX fix large reallocations */
-    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;
-
-    /* XXX r->lowcase_index = i; */
-
-    return NGX_AGAIN;
-
-done:
-
-    b->pos = p + 1;
-    r->state = sw_header;
-    r->h3_length = length;
-    r->h3_insert_count = insert_count;
-    r->h3_sign = sign;
-    r->h3_delta_base = delta_base;
-
-    if (state < sw_header) {
-        if (ngx_http_v3_check_insert_count(c, insert_count) != NGX_OK) {
-            return NGX_DONE;
-        }
-
-        goto again;
-    }
-
-    if (sign == 0) {
-        base = insert_count + delta_base;
-    } else {
-        base = insert_count - delta_base - 1;
-    }
-
-    ngx_log_debug5(NGX_LOG_DEBUG_HTTP, c->log, 0,
-                   "http3 header %s[%ui], base:%ui, \"%V\":\"%V\"",
-                   dynamic ? "dynamic" : "static", index, base, &name, &value);
-
-    if (name.data == NULL) {
-
-        if (dynamic == 2) {
-            index = base - index - 1;
-        } else if (dynamic == 1) {
-            index += base;
-        }
-
-        h = ngx_http_v3_lookup_table(c, dynamic, index);
-        if (h == NULL) {
-            goto failed;
-        }
-
-        name = h->name;
-
-        if (value.data == NULL) {
-            value = h->value;
-        }
-    }
-
-    /* XXX ugly reallocation for the trailing '\0' */
-
-    p = ngx_pnalloc(c->pool, name.len + value.len + 2);
-    if (p == NULL) {
-        return NGX_ERROR;
-    }
-
-    ngx_memcpy(p, name.data, name.len);
-    name.data = p;
-    ngx_memcpy(p + name.len + 1, value.data, value.len);
-    value.data = p + name.len + 1;
-
-    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0,
-                   "http3 header \"%V\":\"%V\"", &name, &value);
-
-    if (pseudo) {
-        rc = ngx_http_v3_process_pseudo_header(r, &name, &value);
-
-        if (rc == NGX_ERROR) {
-            goto failed;
-        }
-
-        if (rc == NGX_OK) {
-            r->request_end = p + 1;
-            goto again;
-        }
-
-        /* rc == NGX_DONE */
-
-        r->state = sw_old_header;
-    }
-
-    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
-                   "http3 header left:%ui", length);
-
-    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 */
-
-    /* XXX r->lowcase_index = i; */
-
-    return NGX_OK;
-
-failed:
-
-    return NGX_HTTP_PARSE_INVALID_REQUEST;
-}
-#endif
-
 
 static ngx_int_t
 ngx_http_v3_process_pseudo_header(ngx_http_request_t *r, ngx_str_t *name,
@@ -675,7 +172,7 @@ ngx_http_v3_process_pseudo_header(ngx_ht
     ngx_connection_t  *c;
 
     if (name->len == 0 || name->data[0] != ':') {
-        return NGX_DECLINED;
+        return NGX_DONE;
     }
 
     c = r->connection;