diff src/http/v3/ngx_http_v3_tables.c @ 7681:38c0898b6df7 quic

HTTP/3.
author Roman Arutyunyan <arut@nginx.com>
date Fri, 13 Mar 2020 19:36:33 +0300
parents
children 268f4389130d
line wrap: on
line diff
new file mode 100644
--- /dev/null
+++ b/src/http/v3/ngx_http_v3_tables.c
@@ -0,0 +1,385 @@
+
+/*
+ * Copyright (C) Roman Arutyunyan
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_http.h>
+
+
+static ngx_array_t *ngx_http_v3_get_dynamic_table(ngx_connection_t *c);
+static ngx_int_t ngx_http_v3_new_header(ngx_connection_t *c);
+
+
+static ngx_http_v3_header_t  ngx_http_v3_static_table[] = {
+
+    { ngx_string(":authority"),            ngx_string("") },
+    { ngx_string(":path"),                 ngx_string("/") }, 
+    { ngx_string("age"),                   ngx_string("0") },
+    { ngx_string("content-disposition"),   ngx_string("") },
+    { ngx_string("content-length"),        ngx_string("0") },
+    { ngx_string("cookie"),                ngx_string("") },
+    { ngx_string("date"),                  ngx_string("") },
+    { ngx_string("etag"),                  ngx_string("") },
+    { ngx_string("if-modified-since"),     ngx_string("") },
+    { ngx_string("if-none-match"),         ngx_string("") },
+    { ngx_string("last-modified"),         ngx_string("") },
+    { ngx_string("link"),                  ngx_string("") },
+    { ngx_string("location"),              ngx_string("") },
+    { ngx_string("referer"),               ngx_string("") },
+    { ngx_string("set-cookie"),            ngx_string("") },
+    { ngx_string(":method"),               ngx_string("CONNECT") },
+    { ngx_string(":method"),               ngx_string("DELETE") },
+    { ngx_string(":method"),               ngx_string("GET") },
+    { ngx_string(":method"),               ngx_string("HEAD") },
+    { ngx_string(":method"),               ngx_string("OPTIONS") },
+    { ngx_string(":method"),               ngx_string("POST") },
+    { ngx_string(":method"),               ngx_string("PUT") },
+    { ngx_string(":scheme"),               ngx_string("http") },
+    { ngx_string(":scheme"),               ngx_string("https") },
+    { ngx_string(":status"),               ngx_string("103") },
+    { ngx_string(":status"),               ngx_string("200") },
+    { ngx_string(":status"),               ngx_string("304") },
+    { ngx_string(":status"),               ngx_string("404") },
+    { ngx_string(":status"),               ngx_string("503") },
+    { ngx_string("accept"),                ngx_string("*/*") },
+    { ngx_string("accept"),
+          ngx_string("application/dns-message ") },
+    { ngx_string("accept-encoding"),       ngx_string("gzip,") },
+    { ngx_string("accept-ranges"),         ngx_string("bytes") },
+    { ngx_string("access-control-allow-headers"),
+                                           ngx_string("cache-control") },
+    { ngx_string("access-control-allow-headers"),
+                                           ngx_string("content-type") },
+    { ngx_string("access-control-allow-origin"),
+                                           ngx_string("*") },
+    { ngx_string("cache-control"),         ngx_string("max-age=0") },
+    { ngx_string("cache-control"),         ngx_string("max-age=2592000") },
+    { ngx_string("cache-control"),         ngx_string("max-age=604800") },
+    { ngx_string("cache-control"),         ngx_string("no-cache") },
+    { ngx_string("cache-control"),         ngx_string("no-store") },
+    { ngx_string("cache-control"),
+          ngx_string("public, max-age=31536000 ") },
+    { ngx_string("content-encoding"),      ngx_string("br") },
+    { ngx_string("content-encoding"),      ngx_string("gzip") },
+    { ngx_string("content-type"),
+          ngx_string("application/dns-message") },
+    { ngx_string("content-type"),
+          ngx_string("application/javascript") },
+    { ngx_string("content-type"),          ngx_string("application/json") },
+    { ngx_string("content-type"),
+          ngx_string("application/x-www-form-urlencoded") },
+    { ngx_string("content-type"),          ngx_string("image/gif") },
+    { ngx_string("content-type"),          ngx_string("image/jpeg") },
+    { ngx_string("content-type"),          ngx_string("image/png") },
+    { ngx_string("content-type"),          ngx_string("text/css") },
+    { ngx_string("content-type"),
+          ngx_string("text/html;charset=utf-8") },
+    { ngx_string("content-type"),          ngx_string("text/plain") },
+    { ngx_string("content-type"),
+          ngx_string("text/plain;charset=utf-8") },
+    { ngx_string("range"),                 ngx_string("bytes=0-") },
+    { ngx_string("strict-transport-security"),
+                                           ngx_string("max-age=31536000") },
+    { ngx_string("strict-transport-security"),
+          ngx_string("max-age=31536000;includesubdomains") },
+    { ngx_string("strict-transport-security"),
+          ngx_string("max-age=31536000;includesubdomains;preload") },
+    { ngx_string("vary"),                  ngx_string("accept-encoding") },
+    { ngx_string("vary"),                  ngx_string("origin") },
+    { ngx_string("x-content-type-options"),ngx_string("nosniff") },
+    { ngx_string("x-xss-protection"),      ngx_string("1;mode=block") },
+    { ngx_string(":status"),               ngx_string("100") },
+    { ngx_string(":status"),               ngx_string("204") },
+    { ngx_string(":status"),               ngx_string("206") },
+    { ngx_string(":status"),               ngx_string("302") },
+    { ngx_string(":status"),               ngx_string("400") },
+    { ngx_string(":status"),               ngx_string("403") },
+    { ngx_string(":status"),               ngx_string("421") },
+    { ngx_string(":status"),               ngx_string("425") },
+    { ngx_string(":status"),               ngx_string("500") },
+    { ngx_string("accept-language"),       ngx_string("") },
+    { ngx_string("access-control-allow-credentials"),
+                                           ngx_string("FALSE") },
+    { ngx_string("access-control-allow-credentials"),
+                                           ngx_string("TRUE") },
+    { ngx_string("access-control-allow-headers"),
+                                           ngx_string("*") },
+    { ngx_string("access-control-allow-methods"),
+                                           ngx_string("get") },
+    { ngx_string("access-control-allow-methods"),
+                                           ngx_string("get, post, options") },
+    { ngx_string("access-control-allow-methods"),
+                                           ngx_string("options") },
+    { ngx_string("access-control-expose-headers"),
+                                           ngx_string("content-length") },
+    { ngx_string("access-control-request-headers"),
+                                           ngx_string("content-type") },
+    { ngx_string("access-control-request-method"),
+                                           ngx_string("get") },
+    { ngx_string("access-control-request-method"),
+                                           ngx_string("post") },
+    { ngx_string("alt-svc"),               ngx_string("clear") },
+    { ngx_string("horization"),            ngx_string("") },
+    { ngx_string("content-security-policy"),
+                                           ngx_string("script-src") },
+    { ngx_string("early-data"),            ngx_string("1") },
+    { ngx_string("expect-ct"),             ngx_string("") },
+    { ngx_string("forwarded"),             ngx_string("") },
+    { ngx_string("if-range"),              ngx_string("") },
+    { ngx_string("origin"),                ngx_string("") },
+    { ngx_string("purpose"),               ngx_string("prefetch") },
+    { ngx_string("server"),                ngx_string("") },
+    { ngx_string("timing-allow-origin"),   ngx_string("*") },
+    { ngx_string("upgrade-insecure-requests"),
+                                           ngx_string("1") },
+    { ngx_string("user-agent"),            ngx_string("") },
+    { ngx_string("x-forwarded-for"),       ngx_string("") },
+    { ngx_string("x-frame-options"),       ngx_string("deny") },
+    { ngx_string("x-frame-options"),       ngx_string("sameorigin") }
+};
+
+
+ngx_int_t
+ngx_http_v3_ref_insert(ngx_connection_t *c, ngx_uint_t dynamic,
+    ngx_uint_t index, ngx_str_t *value)
+{
+    ngx_array_t           *dt;
+    ngx_http_v3_header_t  *ref, *h;
+
+    ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0,
+                   "http3 ref insert %s[$ui] \"%V\"",
+                   dynamic ? "dynamic" : "static", index, value);
+
+    ref = ngx_http_v3_lookup_table(c, dynamic, index);
+    if (ref == NULL) {
+        return NGX_ERROR;
+    }
+
+    dt = ngx_http_v3_get_dynamic_table(c);
+    if (dt == NULL) {
+        return NGX_ERROR;
+    }
+
+    h = ngx_array_push(dt);
+    if (h == NULL) {
+        return NGX_ERROR;
+    }
+
+    h->name = ref->name;
+    h->value = *value;
+
+    if (ngx_http_v3_new_header(c) != NGX_OK) {
+        return NGX_ERROR;
+    }
+
+    return NGX_OK;
+}
+
+
+ngx_int_t
+ngx_http_v3_insert(ngx_connection_t *c, ngx_str_t *name,
+    ngx_str_t *value)
+{
+    ngx_array_t           *dt;
+    ngx_http_v3_header_t  *h;
+
+    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0,
+                   "http3 insert \"%V\":\"%V\"", name, value);
+
+    dt = ngx_http_v3_get_dynamic_table(c);
+    if (dt == NULL) {
+        return NGX_ERROR;
+    }
+
+    h = ngx_array_push(dt);
+    if (h == NULL) {
+        return NGX_ERROR;
+    }
+
+    h->name = *name;
+    h->value = *value;
+
+    if (ngx_http_v3_new_header(c) != NGX_OK) {
+        return NGX_ERROR;
+    }
+
+    return NGX_OK;
+}
+
+
+ngx_int_t
+ngx_http_v3_set_capacity(ngx_connection_t *c, ngx_uint_t capacity)
+{
+    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
+                   "http3 set capacity %ui", capacity);
+
+    /* XXX ignore capacity */
+
+    return NGX_OK;
+}
+
+
+ngx_int_t
+ngx_http_v3_duplicate(ngx_connection_t *c, ngx_uint_t index)
+{
+    ngx_array_t           *dt;
+    ngx_http_v3_header_t  *ref, *h;
+
+    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 duplicate %ui", index);
+
+    ref = ngx_http_v3_lookup_table(c, 1, index);
+    if (ref == NULL) {
+        return NGX_ERROR;
+    }
+
+    dt = ngx_http_v3_get_dynamic_table(c);
+    if (dt == NULL) {
+        return NGX_ERROR;
+    }
+
+    h = ngx_array_push(dt);
+    if (h == NULL) {
+        return NGX_ERROR;
+    }
+
+    *h = *ref;
+
+    if (ngx_http_v3_new_header(c) != NGX_OK) {
+        return NGX_ERROR;
+    }
+
+    return NGX_OK;
+}
+
+
+ngx_int_t
+ngx_http_v3_ack_header(ngx_connection_t *c, ngx_uint_t stream_id)
+{
+    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
+                   "http3 ack header %ui", stream_id);
+
+    /* XXX */
+
+    return NGX_OK;
+}
+
+
+ngx_int_t
+ngx_http_v3_cancel_stream(ngx_connection_t *c, ngx_uint_t stream_id)
+{
+    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
+                   "http3 cancel stream %ui", stream_id);
+
+    /* XXX */
+
+    return NGX_OK;
+}
+
+
+ngx_int_t
+ngx_http_v3_inc_insert_count(ngx_connection_t *c, ngx_uint_t inc)
+{
+    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
+                   "http3 increment insert count %ui", inc);
+
+    /* XXX */
+
+    return NGX_OK;
+}
+
+
+static ngx_array_t *
+ngx_http_v3_get_dynamic_table(ngx_connection_t *c)
+{
+    ngx_connection_t          *pc;
+    ngx_http_v3_connection_t  *h3c;
+
+    pc = c->qs->parent;
+    h3c = pc->data;
+
+    if (h3c->dynamic) {
+        return h3c->dynamic;
+    }
+
+    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 create dynamic table");
+
+    h3c->dynamic = ngx_array_create(pc->pool, 1, sizeof(ngx_http_v3_header_t));
+
+    return h3c->dynamic;
+}
+
+
+ngx_http_v3_header_t *
+ngx_http_v3_lookup_table(ngx_connection_t *c, ngx_uint_t dynamic,
+    ngx_uint_t index)
+{
+    ngx_uint_t             nelts;
+    ngx_array_t           *dt;
+    ngx_http_v3_header_t  *table;
+
+    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 lookup %s[%ui]",
+                   dynamic ? "dynamic" : "static", index);
+
+    if (dynamic) {
+        dt = ngx_http_v3_get_dynamic_table(c);
+        if (dt == NULL) {
+            return NULL;
+        }
+
+        table = dt->elts;
+        nelts = dt->nelts;
+
+    } else {
+        table = ngx_http_v3_static_table;
+        nelts = sizeof(ngx_http_v3_static_table)
+                / sizeof(ngx_http_v3_static_table[0]);
+    }
+
+    if (index >= nelts) {
+        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
+                       "http3 lookup out of bounds: %ui", nelts);
+        return NULL;
+    }
+
+    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 lookup \"%V\":\"%V\"",
+                   &table[index].name, &table[index].value);
+
+    return &table[index];
+}
+
+
+ngx_int_t
+ngx_http_v3_check_insert_count(ngx_connection_t *c, ngx_uint_t insert_count)
+{
+    size_t                     n;
+    ngx_http_v3_connection_t  *h3c;
+
+    h3c = c->qs->parent->data;
+    n = h3c->dynamic ? h3c->dynamic->nelts : 0;
+
+    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0,
+                   "http3 check insert count %ui/%ui", insert_count, n);
+
+    if (n < insert_count) {
+        /* XXX how to get notified? */
+        /* XXX wake all streams on any arrival to the encoder stream? */
+        return NGX_AGAIN;
+    }
+
+    return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_http_v3_new_header(ngx_connection_t *c)
+{
+    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 new dynamic header");
+
+    /* XXX report all waiting streams of a new header */
+
+    return NGX_OK;
+}