[PATCH 12 of 14] Proxy: add HTTP/2 support

Piotr Sikora piotrsikora at google.com
Thu Jun 22 20:33:16 UTC 2017


# HG changeset patch
# User Piotr Sikora <piotrsikora at google.com>
# Date 1490769087 25200
#      Tue Mar 28 23:31:27 2017 -0700
# Node ID 7eb807b056da7abe9c679b59e94595d59a1406e6
# Parent  0637acdb51e29e1f68f5f3e762115c702cab4e72
Proxy: add HTTP/2 support.

Signed-off-by: Piotr Sikora <piotrsikora at google.com>

diff -r 0637acdb51e2 -r 7eb807b056da src/http/modules/ngx_http_proxy_module.c
--- a/src/http/modules/ngx_http_proxy_module.c
+++ b/src/http/modules/ngx_http_proxy_module.c
@@ -125,6 +125,9 @@ static ngx_int_t ngx_http_proxy_eval(ngx
 static ngx_int_t ngx_http_proxy_create_key(ngx_http_request_t *r);
 #endif
 static ngx_int_t ngx_http_proxy_create_request(ngx_http_request_t *r);
+#if (NGX_HTTP_V2)
+static ngx_int_t ngx_http_proxy_create_v2_request(ngx_http_request_t *r);
+#endif
 static ngx_int_t ngx_http_proxy_reinit_request(ngx_http_request_t *r);
 static ngx_int_t ngx_http_proxy_body_output_filter(void *data, ngx_chain_t *in);
 static ngx_int_t ngx_http_proxy_process_status_line(ngx_http_request_t *r);
@@ -149,6 +152,8 @@ static ngx_int_t ngx_http_proxy_port_var
 static ngx_int_t
     ngx_http_proxy_add_x_forwarded_for_variable(ngx_http_request_t *r,
     ngx_http_variable_value_t *v, uintptr_t data);
+static ngx_int_t ngx_http_proxy_internal_connection_variable(
+    ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data);
 static ngx_int_t
     ngx_http_proxy_internal_body_length_variable(ngx_http_request_t *r,
     ngx_http_variable_value_t *v, uintptr_t data);
@@ -245,6 +250,9 @@ static ngx_conf_bitmask_t  ngx_http_prox
 static ngx_conf_enum_t  ngx_http_proxy_http_version[] = {
     { ngx_string("1.0"), NGX_HTTP_VERSION_10 },
     { ngx_string("1.1"), NGX_HTTP_VERSION_11 },
+#if (NGX_HTTP_V2)
+    { ngx_string("2.0"), NGX_HTTP_VERSION_20 },
+#endif
     { ngx_null_string, 0 }
 };
 
@@ -765,7 +773,7 @@ static char  ngx_http_proxy_version_11[]
 
 static ngx_keyval_t  ngx_http_proxy_headers[] = {
     { ngx_string("Host"), ngx_string("$proxy_host") },
-    { ngx_string("Connection"), ngx_string("close") },
+    { ngx_string("Connection"), ngx_string("$proxy_internal_connection") },
     { ngx_string("Content-Length"), ngx_string("$proxy_internal_body_length") },
     { ngx_string("Transfer-Encoding"), ngx_string("$proxy_internal_chunked") },
     { ngx_string("TE"), ngx_string("") },
@@ -793,7 +801,7 @@ static ngx_str_t  ngx_http_proxy_hide_he
 
 static ngx_keyval_t  ngx_http_proxy_cache_headers[] = {
     { ngx_string("Host"), ngx_string("$proxy_host") },
-    { ngx_string("Connection"), ngx_string("close") },
+    { ngx_string("Connection"), ngx_string("$proxy_internal_connection") },
     { ngx_string("Content-Length"), ngx_string("$proxy_internal_body_length") },
     { ngx_string("Transfer-Encoding"), ngx_string("$proxy_internal_chunked") },
     { ngx_string("TE"), ngx_string("") },
@@ -828,6 +836,10 @@ static ngx_http_variable_t  ngx_http_pro
     { ngx_string("proxy_add_via"), NULL, NULL, 0, NGX_HTTP_VAR_NOHASH, 0 },
 #endif
 
+    { ngx_string("proxy_internal_connection"), NULL,
+      ngx_http_proxy_internal_connection_variable, 0,
+      NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 },
+
     { ngx_string("proxy_internal_body_length"), NULL,
       ngx_http_proxy_internal_body_length_variable, 0,
       NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 },
@@ -902,6 +914,18 @@ ngx_http_proxy_handler(ngx_http_request_
     u->finalize_request = ngx_http_proxy_finalize_request;
     r->state = 0;
 
+#if (NGX_HTTP_V2)
+
+    if (plcf->http_version == NGX_HTTP_VERSION_20) {
+        u->http2 = 1;
+
+        u->create_request = ngx_http_proxy_create_v2_request;
+        u->output.output_filter = ngx_http_v2_upstream_output_filter;
+        u->output.filter_ctx = r;
+    }
+
+#endif
+
     if (plcf->redirects) {
         u->rewrite_redirect = ngx_http_proxy_rewrite_redirect;
     }
@@ -929,7 +953,7 @@ ngx_http_proxy_handler(ngx_http_request_
     if (!plcf->upstream.request_buffering
         && plcf->body_values == NULL && plcf->upstream.pass_request_body
         && (!r->headers_in.chunked
-            || plcf->http_version == NGX_HTTP_VERSION_11))
+            || plcf->http_version >= NGX_HTTP_VERSION_11))
     {
         r->request_body_no_buffering = 1;
     }
@@ -1521,6 +1545,509 @@ ngx_http_proxy_create_request(ngx_http_r
 }
 
 
+#if (NGX_HTTP_V2)
+
+static ngx_int_t
+ngx_http_proxy_create_v2_request(ngx_http_request_t *r)
+{
+    size_t                        len, uri_len, loc_len, body_len;
+    size_t                        key_len, val_len, tmp_len;
+    u_char                       *p, *code_tmp, *huff_tmp;
+    uintptr_t                     escape;
+    ngx_buf_t                    *b;
+    ngx_str_t                     method;
+    ngx_uint_t                    i, unparsed_uri;
+    ngx_chain_t                  *cl, *body;
+    ngx_list_part_t              *part;
+    ngx_table_elt_t              *header;
+    ngx_http_upstream_t          *u;
+    ngx_http_proxy_ctx_t         *ctx;
+    ngx_http_script_code_pt       code;
+    ngx_http_proxy_headers_t     *headers;
+    ngx_http_script_engine_t      e, le;
+    ngx_http_proxy_loc_conf_t    *plcf;
+    ngx_http_script_len_code_pt   lcode;
+
+    u = r->upstream;
+
+    plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module);
+
+#if (NGX_HTTP_CACHE)
+    headers = u->cacheable ? &plcf->headers_cache : &plcf->headers;
+#else
+    headers = &plcf->headers;
+#endif
+
+    if (u->method.len) {
+        /* HEAD was changed to GET to cache response */
+        method = u->method;
+
+    } else if (plcf->method) {
+        if (ngx_http_complex_value(r, plcf->method, &method) != NGX_OK) {
+            return NGX_ERROR;
+        }
+
+    } else {
+        method = r->method_name;
+    }
+
+    tmp_len = 0;
+
+    if (method.len == 3
+        && ngx_strncasecmp(method.data, (u_char *) "GET", 3) == 0)
+    {
+        len = 1;
+
+    } else if (method.len == 4
+               && ngx_strncasecmp(method.data, (u_char *) "POST", 4) == 0)
+    {
+        len = 1;
+
+    } else {
+        len = 1 + NGX_HTTP_V2_INT_OCTETS + method.len;
+        tmp_len = method.len;
+    }
+
+    escape = 0;
+    loc_len = 0;
+    unparsed_uri = 0;
+
+    ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
+
+    if (plcf->proxy_lengths && ctx->vars.uri.len) {
+        uri_len = ctx->vars.uri.len;
+
+    } else if (ctx->vars.uri.len == 0 && r->valid_unparsed_uri && r == r->main)
+    {
+        unparsed_uri = 1;
+        uri_len = r->unparsed_uri.len;
+
+    } else {
+        loc_len = (r->valid_location && ctx->vars.uri.len)
+                  ? plcf->location.len : 0;
+
+        if (r->quoted_uri || r->space_in_uri || r->internal) {
+            escape = 2 * ngx_escape_uri(NULL, r->uri.data + loc_len,
+                                        r->uri.len - loc_len, NGX_ESCAPE_URI);
+        }
+
+        uri_len = ctx->vars.uri.len + r->uri.len - loc_len + escape
+                  + sizeof("?") - 1 + r->args.len;
+    }
+
+    if (uri_len == 0) {
+        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+                      "zero length URI to proxy");
+        return NGX_ERROR;
+    }
+
+    len += 1 + NGX_HTTP_V2_INT_OCTETS + uri_len;
+
+    if (uri_len > tmp_len) {
+        tmp_len = uri_len;
+    }
+
+
+    ngx_memzero(&le, sizeof(ngx_http_script_engine_t));
+
+    ngx_http_script_flush_no_cacheable_variables(r, plcf->body_flushes);
+    ngx_http_script_flush_no_cacheable_variables(r, headers->flushes);
+
+    body_len = 0;
+
+    if (plcf->body_lengths) {
+        le.ip = plcf->body_lengths->elts;
+        le.request = r;
+        le.flushed = 1;
+
+        while (*(uintptr_t *) le.ip) {
+            lcode = *(ngx_http_script_len_code_pt *) le.ip;
+            body_len += lcode(&le);
+        }
+
+        ctx->internal_body_length = body_len;
+
+    } else if (r->headers_in.chunked && r->reading_body) {
+        ctx->internal_body_length = -1;
+        ctx->internal_chunked = 1;
+
+    } else {
+        ctx->internal_body_length = r->headers_in.content_length_n;
+    }
+
+    le.ip = headers->lengths->elts;
+    le.request = r;
+    le.flushed = 1;
+
+    while (*(uintptr_t *) le.ip) {
+
+        lcode = *(ngx_http_script_len_code_pt *) le.ip;
+        key_len = lcode(&le);
+
+        for (val_len = 0; *(uintptr_t *) le.ip; val_len += lcode(&le)) {
+            lcode = *(ngx_http_script_len_code_pt *) le.ip;
+        }
+        le.ip += sizeof(uintptr_t);
+
+        if (val_len == 0) {
+            continue;
+        }
+
+        len += 1 + NGX_HTTP_V2_INT_OCTETS + key_len
+                 + NGX_HTTP_V2_INT_OCTETS + val_len;
+
+        if (key_len > tmp_len) {
+            tmp_len = key_len;
+        }
+
+        if (val_len > tmp_len) {
+            tmp_len = val_len;
+        }
+    }
+
+
+    if (plcf->upstream.pass_request_headers) {
+        part = &r->headers_in.headers.part;
+        header = part->elts;
+
+        for (i = 0; /* void */; i++) {
+
+            if (i >= part->nelts) {
+                if (part->next == NULL) {
+                    break;
+                }
+
+                part = part->next;
+                header = part->elts;
+                i = 0;
+            }
+
+            if (ngx_hash_find(&headers->hash, header[i].hash,
+                              header[i].lowcase_key, header[i].key.len))
+            {
+                continue;
+            }
+
+            if (header[i].key.len > NGX_HTTP_V2_MAX_FIELD) {
+                ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+                              "too long request header name: \"%V\"",
+                              &header[i].key);
+                return NGX_ERROR;
+            }
+
+            if (header[i].value.len > NGX_HTTP_V2_MAX_FIELD) {
+                ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+                              "too long request header value: \"%V: %V\"",
+                              &header[i].key, &header[i].value);
+                return NGX_ERROR;
+            }
+
+            len += 1 + NGX_HTTP_V2_INT_OCTETS + header[i].key.len
+                     + NGX_HTTP_V2_INT_OCTETS + header[i].value.len;
+
+            if (header[i].key.len > tmp_len) {
+                tmp_len = header[i].key.len;
+            }
+
+            if (header[i].value.len > tmp_len) {
+                tmp_len = header[i].value.len;
+            }
+        }
+    }
+
+    code_tmp = ngx_pnalloc(r->pool, tmp_len);
+    if (code_tmp == NULL) {
+        return NGX_ERROR;
+    }
+
+    huff_tmp = ngx_palloc(r->pool, tmp_len);
+    if (huff_tmp == NULL) {
+        return NGX_ERROR;
+    }
+
+    b = ngx_create_temp_buf(r->pool, len);
+    if (b == NULL) {
+        return NGX_ERROR;
+    }
+
+    cl = ngx_alloc_chain_link(r->pool);
+    if (cl == NULL) {
+        return NGX_ERROR;
+    }
+
+    cl->buf = b;
+    cl->next = NULL;
+
+    /* :method header */
+
+    if (method.len == 3
+        && ngx_strncasecmp(method.data, (u_char *) "GET", 3) == 0)
+    {
+        *b->last++ = ngx_http_v2_indexed(NGX_HTTP_V2_METHOD_GET_INDEX);
+
+    } else if (method.len == 4
+               && ngx_strncasecmp(method.data, (u_char *) "POST", 4) == 0)
+    {
+        *b->last++ = ngx_http_v2_indexed(NGX_HTTP_V2_METHOD_POST_INDEX);
+
+    } else {
+        *b->last++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_METHOD_INDEX);
+        b->last = ngx_http_v2_write_value(b->last, method.data, method.len,
+                                          huff_tmp);
+    }
+
+    /* :scheme header */
+
+    if (u->schema.len == 8
+        && ngx_strncasecmp(u->schema.data, (u_char *) "https://", 8) == 0)
+    {
+        *b->last++ = ngx_http_v2_indexed(NGX_HTTP_V2_SCHEME_HTTPS_INDEX);
+
+    } else {
+        *b->last++ = ngx_http_v2_indexed(NGX_HTTP_V2_SCHEME_HTTP_INDEX);
+    }
+
+    /* :authority header */
+
+    le.ip = headers->lengths->elts;
+
+    lcode = *(ngx_http_script_len_code_pt *) le.ip;
+    (void) lcode(&le);
+
+    for (val_len = 0; *(uintptr_t *) le.ip; val_len += lcode(&le)) {
+        lcode = *(ngx_http_script_len_code_pt *) le.ip;
+    }
+    le.ip += sizeof(uintptr_t);
+
+    if (val_len == 0) {
+        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+                      "missing or empty \"Host\" header");
+        return NGX_ERROR;
+    }
+
+    ngx_memzero(&e, sizeof(ngx_http_script_engine_t));
+
+    e.ip = headers->values->elts;
+    e.request = r;
+    e.flushed = 1;
+    e.skip = 1;
+
+    code = *(ngx_http_script_code_pt *) e.ip;
+    code((ngx_http_script_engine_t *) &e);
+
+    e.skip = 0;
+    e.pos = code_tmp;
+
+    while (*(uintptr_t *) e.ip) {
+        code = *(ngx_http_script_code_pt *) e.ip;
+        code((ngx_http_script_engine_t *) &e);
+    }
+    e.ip += sizeof(uintptr_t);
+
+    *b->last++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_AUTHORITY_INDEX);
+    b->last = ngx_http_v2_write_value(b->last, code_tmp, e.pos - code_tmp,
+                                      huff_tmp);
+
+    /* :path header */
+
+    if (plcf->proxy_lengths && ctx->vars.uri.len) {
+        u->uri = ctx->vars.uri;
+
+    } else if (unparsed_uri) {
+        u->uri = r->unparsed_uri;
+
+    } else {
+        p = ngx_pnalloc(r->pool, uri_len);
+        if (p == NULL) {
+            return NGX_ERROR;
+        }
+
+        u->uri.data = p;
+
+        if (r->valid_location) {
+            p = ngx_copy(p, ctx->vars.uri.data, ctx->vars.uri.len);
+        }
+
+        if (escape) {
+            ngx_escape_uri(p, r->uri.data + loc_len, r->uri.len - loc_len,
+                           NGX_ESCAPE_URI);
+            p += r->uri.len - loc_len + escape;
+
+        } else {
+            p = ngx_copy(p, r->uri.data + loc_len, r->uri.len - loc_len);
+        }
+
+        if (r->args.len > 0) {
+            *p++ = '?';
+            p = ngx_copy(p, r->args.data, r->args.len);
+        }
+
+        u->uri.len = p - u->uri.data;
+    }
+
+    if (uri_len == 1) {
+        *b->last++ = ngx_http_v2_indexed(NGX_HTTP_V2_PATH_ROOT_INDEX);
+
+    } else {
+        *b->last++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_PATH_INDEX);
+        b->last = ngx_http_v2_write_value(b->last, u->uri.data, u->uri.len,
+                                          huff_tmp);
+    }
+
+
+    while (*(uintptr_t *) le.ip) {
+
+        lcode = *(ngx_http_script_len_code_pt *) le.ip;
+        (void) lcode(&le);
+
+        for (val_len = 0; *(uintptr_t *) le.ip; val_len += lcode(&le)) {
+            lcode = *(ngx_http_script_len_code_pt *) le.ip;
+        }
+        le.ip += sizeof(uintptr_t);
+
+        if (val_len == 0) {
+            e.skip = 1;
+
+            while (*(uintptr_t *) e.ip) {
+                code = *(ngx_http_script_code_pt *) e.ip;
+                code((ngx_http_script_engine_t *) &e);
+            }
+            e.ip += sizeof(uintptr_t);
+
+            e.skip = 0;
+
+            continue;
+        }
+
+        e.pos = code_tmp;
+
+        code = *(ngx_http_script_code_pt *) e.ip;
+        code((ngx_http_script_engine_t *) &e);
+
+        *b->last++ = '\0';
+        b->last = ngx_http_v2_write_name(b->last, code_tmp, e.pos - code_tmp,
+                                         huff_tmp);
+
+        e.pos = code_tmp;
+
+        while (*(uintptr_t *) e.ip) {
+            code = *(ngx_http_script_code_pt *) e.ip;
+            code((ngx_http_script_engine_t *) &e);
+        }
+        e.ip += sizeof(uintptr_t);
+
+        b->last = ngx_http_v2_write_value(b->last, code_tmp, e.pos - code_tmp,
+                                          huff_tmp);
+    }
+
+
+    if (plcf->upstream.pass_request_headers) {
+        part = &r->headers_in.headers.part;
+        header = part->elts;
+
+        for (i = 0; /* void */; i++) {
+
+            if (i >= part->nelts) {
+                if (part->next == NULL) {
+                    break;
+                }
+
+                part = part->next;
+                header = part->elts;
+                i = 0;
+            }
+
+            if (ngx_hash_find(&headers->hash, header[i].hash,
+                              header[i].lowcase_key, header[i].key.len))
+            {
+                continue;
+            }
+
+            *b->last++ = '\0';
+
+            b->last = ngx_http_v2_write_name(b->last, header[i].key.data,
+                                             header[i].key.len, huff_tmp);
+
+            b->last = ngx_http_v2_write_value(b->last, header[i].value.data,
+                                              header[i].value.len, huff_tmp);
+
+            ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                           "proxy http2 header: \"%*s: %V\"",
+                           header[i].key.len, header[i].lowcase_key,
+                           &header[i].value);
+        }
+    }
+
+
+    if (plcf->body_values && body_len) {
+        b = ngx_create_temp_buf(r->pool, body_len);
+        if (b == NULL) {
+            return NGX_ERROR;
+        }
+
+        e.ip = plcf->body_values->elts;
+        e.pos = b->last;
+        e.skip = 0;
+
+        while (*(uintptr_t *) e.ip) {
+            code = *(ngx_http_script_code_pt *) e.ip;
+            code((ngx_http_script_engine_t *) &e);
+        }
+
+        b->last = e.pos;
+
+        cl->next = ngx_alloc_chain_link(r->pool);
+        if (cl->next == NULL) {
+            return NGX_ERROR;
+        }
+
+        cl->next->buf = b;
+        cl->next->next = NULL;
+    }
+
+
+    if (r->request_body_no_buffering) {
+        u->request_bufs = cl;
+        b->flush = 1;
+
+    } else if (plcf->body_values == NULL && plcf->upstream.pass_request_body) {
+
+        body = u->request_bufs;
+        u->request_bufs = cl;
+
+        while (body) {
+            b = ngx_alloc_buf(r->pool);
+            if (b == NULL) {
+                return NGX_ERROR;
+            }
+
+            ngx_memcpy(b, body->buf, sizeof(ngx_buf_t));
+
+            cl->next = ngx_alloc_chain_link(r->pool);
+            if (cl->next == NULL) {
+                return NGX_ERROR;
+            }
+
+            cl = cl->next;
+            cl->buf = b;
+
+            body = body->next;
+        }
+
+        cl->next = NULL;
+        b->last_buf = 1;
+
+    } else {
+        u->request_bufs = cl;
+        b->last_buf = 1;
+    }
+
+    return NGX_OK;
+}
+
+#endif
+
+
 static ngx_int_t
 ngx_http_proxy_reinit_request(ngx_http_request_t *r)
 {
@@ -1966,6 +2493,14 @@ ngx_http_proxy_input_filter_init(void *d
                    u->headers_in.status_n, ctx->head, u->headers_in.chunked,
                    u->headers_in.content_length_n);
 
+#if (NGX_HTTP_V2)
+
+    if (u->stream) {
+        return NGX_OK;
+    }
+
+#endif
+
     /* as per RFC2616, 4.4 Message Length */
 
     if (u->headers_in.status_n == NGX_HTTP_NO_CONTENT
@@ -2480,6 +3015,34 @@ ngx_http_proxy_add_x_forwarded_for_varia
 
 
 static ngx_int_t
+ngx_http_proxy_internal_connection_variable(ngx_http_request_t *r,
+    ngx_http_variable_value_t *v, uintptr_t data)
+{
+#if (NGX_HTTP_V2)
+
+    ngx_http_proxy_loc_conf_t  *plcf;
+
+    plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module);
+
+    if (plcf->http_version == NGX_HTTP_VERSION_20) {
+        v->not_found = 1;
+        return NGX_OK;
+    }
+
+#endif
+
+    v->valid = 1;
+    v->no_cacheable = 0;
+    v->not_found = 0;
+
+    v->data = (u_char *) "close";
+    v->len = sizeof("close") - 1;
+
+    return NGX_OK;
+}
+
+
+static ngx_int_t
 ngx_http_proxy_internal_body_length_variable(ngx_http_request_t *r,
     ngx_http_variable_value_t *v, uintptr_t data)
 {
@@ -2512,7 +3075,20 @@ static ngx_int_t
 ngx_http_proxy_internal_chunked_variable(ngx_http_request_t *r,
     ngx_http_variable_value_t *v, uintptr_t data)
 {
-    ngx_http_proxy_ctx_t  *ctx;
+    ngx_http_proxy_ctx_t       *ctx;
+
+#if (NGX_HTTP_V2)
+
+    ngx_http_proxy_loc_conf_t  *plcf;
+
+    plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module);
+
+    if (plcf->http_version == NGX_HTTP_VERSION_20) {
+        v->not_found = 1;
+        return NGX_OK;
+    }
+
+#endif
 
     ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
 
@@ -3407,6 +3983,18 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t
 #if (NGX_HTTP_CACHE)
 
     if (conf->upstream.cache) {
+
+#if (NGX_HTTP_V2)
+
+        if (conf->http_version == NGX_HTTP_VERSION_20) {
+            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                               "\"proxy_cache\" doesn't work with "
+                               "\"proxy_http_version 2.0\"");
+            return NGX_CONF_ERROR;
+        }
+
+#endif
+
         rc = ngx_http_proxy_init_headers(cf, conf, &conf->headers_cache,
                                          ngx_http_proxy_cache_headers);
         if (rc != NGX_OK) {
@@ -4361,6 +4949,15 @@ ngx_http_proxy_set_ssl(ngx_conf_t *cf, n
         case NGX_HTTP_VERSION_11:
             ngx_str_set(&alpn, NGX_HTTP_11_ALPN_ADVERTISE);
             break;
+
+#if (NGX_HTTP_V2)
+
+        case NGX_HTTP_VERSION_20:
+            ngx_str_set(&alpn, NGX_HTTP_V2_ALPN_ADVERTISE);
+            break;
+
+#endif
+
         }
 
         if (ngx_ssl_alpn_protos(cf, plcf->upstream.ssl, &alpn) != NGX_OK) {
diff -r 0637acdb51e2 -r 7eb807b056da src/http/v2/ngx_http_v2.h
--- a/src/http/v2/ngx_http_v2.h
+++ b/src/http/v2/ngx_http_v2.h
@@ -13,6 +13,28 @@
 #include <ngx_http.h>
 
 
+#define ngx_http_v2_indexed(i)           (128 + (i))
+#define ngx_http_v2_inc_indexed(i)       (64 + (i))
+
+
+// :authority
+#define NGX_HTTP_V2_AUTHORITY_INDEX      1
+
+// :method
+#define NGX_HTTP_V2_METHOD_INDEX         2
+#define NGX_HTTP_V2_METHOD_GET_INDEX     2
+#define NGX_HTTP_V2_METHOD_POST_INDEX    3
+
+// :path
+#define NGX_HTTP_V2_PATH_INDEX           4
+#define NGX_HTTP_V2_PATH_ROOT_INDEX      4
+
+// :scheme
+#define NGX_HTTP_V2_SCHEME_INDEX         6
+#define NGX_HTTP_V2_SCHEME_HTTP_INDEX    6
+#define NGX_HTTP_V2_SCHEME_HTTPS_INDEX   7
+
+
 #define NGX_HTTP_V2_ALPN_ADVERTISE       "\x02h2"
 #define NGX_HTTP_V2_NPN_ADVERTISE        NGX_HTTP_V2_ALPN_ADVERTISE
 
@@ -325,6 +347,9 @@ void ngx_http_v2_finalize_connection(ngx
     ngx_uint_t status);
 
 
+u_char *ngx_http_v2_string_encode(u_char *dst, u_char *src, size_t len,
+    u_char *tmp, ngx_uint_t lower);
+
 ngx_http_v2_out_frame_t *ngx_http_v2_create_headers_frame(
     ngx_http_v2_stream_t *stream, u_char *pos, u_char *end, ngx_uint_t fin);
 
@@ -415,4 +440,11 @@ size_t ngx_http_v2_huff_encode(u_char *s
 
 #define ngx_http_v2_write_sid  ngx_http_v2_write_uint32
 
+
+#define ngx_http_v2_write_name(dst, src, len, tmp)                            \
+    ngx_http_v2_string_encode(dst, src, len, tmp, 1)
+#define ngx_http_v2_write_value(dst, src, len, tmp)                           \
+    ngx_http_v2_string_encode(dst, src, len, tmp, 0)
+
+
 #endif /* _NGX_HTTP_V2_H_INCLUDED_ */
diff -r 0637acdb51e2 -r 7eb807b056da src/http/v2/ngx_http_v2_filter_module.c
--- a/src/http/v2/ngx_http_v2_filter_module.c
+++ b/src/http/v2/ngx_http_v2_filter_module.c
@@ -22,14 +22,6 @@
 #define ngx_http_v2_literal_size(h)                                           \
     (ngx_http_v2_integer_octets(sizeof(h) - 1) + sizeof(h) - 1)
 
-#define ngx_http_v2_indexed(i)      (128 + (i))
-#define ngx_http_v2_inc_indexed(i)  (64 + (i))
-
-#define ngx_http_v2_write_name(dst, src, len, tmp)                            \
-    ngx_http_v2_string_encode(dst, src, len, tmp, 1)
-#define ngx_http_v2_write_value(dst, src, len, tmp)                           \
-    ngx_http_v2_string_encode(dst, src, len, tmp, 0)
-
 #define NGX_HTTP_V2_ENCODE_RAW            0
 #define NGX_HTTP_V2_ENCODE_HUFF           0x80
 
@@ -53,8 +45,6 @@
 #define NGX_HTTP_V2_NO_TRAILERS           (ngx_http_v2_out_frame_t *) -1
 
 
-static u_char *ngx_http_v2_string_encode(u_char *dst, u_char *src, size_t len,
-    u_char *tmp, ngx_uint_t lower);
 static u_char *ngx_http_v2_write_int(u_char *pos, ngx_uint_t prefix,
     ngx_uint_t value);
 static ngx_http_v2_out_frame_t *ngx_http_v2_create_trailers_frame(
@@ -740,7 +730,7 @@ ngx_http_v2_create_trailers_frame(ngx_ht
 }
 
 
-static u_char *
+u_char *
 ngx_http_v2_string_encode(u_char *dst, u_char *src, size_t len, u_char *tmp,
     ngx_uint_t lower)
 {


More information about the nginx-devel mailing list