[PATCH] HTTP/2: copy additional headers in the pushed requests

Alessandro Ghedini alessandro at ghedini.me
Thu Feb 8 17:04:58 UTC 2018


# HG changeset patch
# User Alessandro Ghedini <alessandro at cloudflare.com>
# Date 1518109032 0
#      Thu Feb 08 16:57:12 2018 +0000
# Branch push-copy-headers
# Node ID 4f7f42e6d13add2ab0c7a9654472bb74085181d1
# Parent  a49af443656f2b65ca5de9d8cad5594f44e18ff7
HTTP/2: copy additional headers in the pushed requests.

To ensure pushed requests are processed consistently with the original
client request, some headers need to be copied from the original request
into the pushed one.

The headers currently copied are User-Agent, Accept, Accept-Language and
Accept-Encoding.

diff -r a49af443656f -r 4f7f42e6d13a src/http/v2/ngx_http_v2.c
--- a/src/http/v2/ngx_http_v2.c	Thu Feb 08 12:11:30 2018 +0300
+++ b/src/http/v2/ngx_http_v2.c	Thu Feb 08 16:57:12 2018 +0000
@@ -156,6 +156,8 @@
     ngx_str_t *value);
 static ngx_int_t ngx_http_v2_parse_authority(ngx_http_request_t *r,
     ngx_str_t *value);
+static ngx_int_t ngx_http_v2_copy_header(ngx_http_request_t *r,
+    ngx_table_elt_t *hdr);
 static ngx_int_t ngx_http_v2_construct_request_line(ngx_http_request_t *r);
 static ngx_int_t ngx_http_v2_cookie(ngx_http_request_t *r,
     ngx_http_v2_header_t *header);
@@ -2516,7 +2518,8 @@
 
 ngx_int_t
 ngx_http_v2_push_stream(ngx_http_v2_connection_t *h2c, ngx_uint_t depend,
-    size_t request_length, ngx_str_t *path, ngx_str_t *authority)
+    size_t request_length, ngx_str_t *path, ngx_str_t *authority,
+    ngx_http_headers_in_t *headers_in)
 {
     ngx_int_t              rc;
     ngx_str_t              value;
@@ -2605,6 +2608,34 @@
         goto error;
     }
 
+    rc = ngx_http_v2_copy_header(r, headers_in->user_agent);
+
+    if (rc != NGX_OK) {
+        goto error;
+    }
+
+#if (NGX_HTTP_HEADERS)
+    rc = ngx_http_v2_copy_header(r, headers_in->accept);
+
+    if (rc != NGX_OK) {
+        goto error;
+    }
+
+    rc = ngx_http_v2_copy_header(r, headers_in->accept_language);
+
+    if (rc != NGX_OK) {
+        goto error;
+    }
+#endif
+
+#if (NGX_HTTP_GZIP)
+    rc = ngx_http_v2_copy_header(r, headers_in->accept_encoding);
+
+    if (rc != NGX_OK) {
+        goto error;
+    }
+#endif
+
     fc->write->handler = ngx_http_v2_run_request_handler;
     ngx_post_event(fc->write, &ngx_posted_events);
 
@@ -3479,6 +3510,63 @@
 
 
 static ngx_int_t
+ngx_http_v2_copy_header(ngx_http_request_t *r, ngx_table_elt_t *hdr)
+{
+    ngx_table_elt_t            *h;
+    ngx_http_header_t          *hh;
+    ngx_http_core_main_conf_t  *cmcf;
+
+    if (hdr == NULL) {
+        return NGX_OK;
+    }
+
+    h = ngx_list_push(&r->headers_in.headers);
+    if (h == NULL) {
+        return NGX_ERROR;
+    }
+
+    h->hash = hdr->hash;
+
+    h->key.len = hdr->key.len;
+
+    h->key.data = ngx_pnalloc(r->stream->pool, h->key.len + 1);
+    if (h->key.data == NULL) {
+        h->hash = 0;
+        return NGX_ERROR;
+    }
+
+    (void) ngx_cpystrn(h->key.data, hdr->key.data, h->key.len + 1);
+
+    h->value.len = hdr->value.len;
+
+    h->value.data = ngx_pnalloc(r->stream->pool, h->value.len + 1);
+    if (h->key.data == NULL) {
+        h->hash = 0;
+        return NGX_ERROR;
+    }
+
+    (void) ngx_cpystrn(h->value.data, hdr->value.data, h->value.len + 1);
+
+    h->lowcase_key = h->key.data;
+
+    cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
+
+    hh = ngx_hash_find(&cmcf->headers_in_hash, h->hash,
+                       h->lowcase_key, h->key.len);
+
+    if (hh == NULL) {
+        return NGX_ERROR;
+    }
+
+    if (hh->handler(r, h, hh->offset) != NGX_OK) {
+        return NGX_ERROR;
+    }
+
+    return NGX_OK;
+}
+
+
+static ngx_int_t
 ngx_http_v2_construct_request_line(ngx_http_request_t *r)
 {
     u_char  *p;
diff -r a49af443656f -r 4f7f42e6d13a src/http/v2/ngx_http_v2.h
--- a/src/http/v2/ngx_http_v2.h	Thu Feb 08 12:11:30 2018 +0300
+++ b/src/http/v2/ngx_http_v2.h	Thu Feb 08 16:57:12 2018 +0000
@@ -285,7 +285,7 @@
 
 ngx_int_t ngx_http_v2_push_stream(ngx_http_v2_connection_t *h2c,
     ngx_uint_t depend, size_t request_length, ngx_str_t *path,
-    ngx_str_t *authority);
+    ngx_str_t *authority, ngx_http_headers_in_t *headers_in);
 
 void ngx_http_v2_close_stream(ngx_http_v2_stream_t *stream, ngx_int_t rc);
 
diff -r a49af443656f -r 4f7f42e6d13a src/http/v2/ngx_http_v2_filter_module.c
--- a/src/http/v2/ngx_http_v2_filter_module.c	Thu Feb 08 12:11:30 2018 +0300
+++ b/src/http/v2/ngx_http_v2_filter_module.c	Thu Feb 08 16:57:12 2018 +0000
@@ -972,6 +972,34 @@
           + authority->len
           + 1;
 
+    if (r->headers_in.user_agent) {
+        len += 1 + NGX_HTTP_V2_INT_OCTETS + r->headers_in.user_agent->key.len
+                 + NGX_HTTP_V2_INT_OCTETS + r->headers_in.user_agent->value.len;
+    }
+
+#if (NGX_HTTP_HEADERS)
+    if (r->headers_in.accept) {
+        len += 1 + NGX_HTTP_V2_INT_OCTETS + r->headers_in.accept->key.len
+                 + NGX_HTTP_V2_INT_OCTETS + r->headers_in.accept->value.len;
+    }
+
+    if (r->headers_in.accept_language) {
+        len += 1 + NGX_HTTP_V2_INT_OCTETS
+                 + r->headers_in.accept_language->key.len
+                 + NGX_HTTP_V2_INT_OCTETS
+                 + r->headers_in.accept_language->value.len;
+    }
+#endif
+
+#if (NGX_HTTP_GZIP)
+    if (r->headers_in.accept_encoding) {
+        len += 1 + NGX_HTTP_V2_INT_OCTETS
+                 + r->headers_in.accept_encoding->key.len
+                 + NGX_HTTP_V2_INT_OCTETS
+                 + r->headers_in.accept_encoding->value.len;
+    }
+#endif
+
     tmp = ngx_palloc(r->pool, len);
     pos = ngx_pnalloc(r->pool, len);
 
@@ -1018,6 +1046,66 @@
         *pos++ = ngx_http_v2_indexed(NGX_HTTP_V2_SCHEME_HTTP_INDEX);
     }
 
+    if (r->headers_in.user_agent) {
+        *pos++ = 0;
+
+        pos = ngx_http_v2_write_name(pos,
+                                     r->headers_in.user_agent->key.data,
+                                     r->headers_in.user_agent->key.len,
+                                     tmp);
+
+        pos = ngx_http_v2_write_value(pos,
+                                      r->headers_in.user_agent->value.data,
+                                      r->headers_in.user_agent->value.len,
+                                      tmp);
+    }
+
+#if (NGX_HTTP_HEADERS)
+    if (r->headers_in.accept) {
+        *pos++ = 0;
+
+        pos = ngx_http_v2_write_name(pos,
+                                     r->headers_in.accept->key.data,
+                                     r->headers_in.accept->key.len,
+                                     tmp);
+
+        pos = ngx_http_v2_write_value(pos,
+                                      r->headers_in.accept->value.data,
+                                      r->headers_in.accept->value.len,
+                                      tmp);
+    }
+
+    if (r->headers_in.accept_language) {
+        *pos++ = 0;
+
+        pos = ngx_http_v2_write_name(pos,
+                                     r->headers_in.accept_language->key.data,
+                                     r->headers_in.accept_language->key.len,
+                                     tmp);
+
+        pos = ngx_http_v2_write_value(pos,
+                                      r->headers_in.accept_language->value.data,
+                                      r->headers_in.accept_language->value.len,
+                                      tmp);
+    }
+#endif
+
+#if (NGX_HTTP_GZIP)
+    if (r->headers_in.accept_encoding) {
+        *pos++ = 0;
+
+        pos = ngx_http_v2_write_name(pos,
+                                     r->headers_in.accept_encoding->key.data,
+                                     r->headers_in.accept_encoding->key.len,
+                                     tmp);
+
+        pos = ngx_http_v2_write_value(pos,
+                                      r->headers_in.accept_encoding->value.data,
+                                      r->headers_in.accept_encoding->value.len,
+                                      tmp);
+    }
+#endif
+
     frame = ngx_http_v2_create_push_frame(r, start, pos);
     if (frame == NULL) {
         return NGX_ERROR;
@@ -1028,7 +1116,7 @@
     stream->queued++;
 
     return ngx_http_v2_push_stream(h2c, stream->node->id, pos - start,
-                                   path, &host->value);
+                                   path, &host->value, &r->headers_in);
 }
 
 


More information about the nginx-devel mailing list