[PATCH] HTTP/2: added support for setting custom push request headers
Alessandro Ghedini
alessandro at ghedini.me
Mon Feb 12 12:35:13 UTC 2018
# HG changeset patch
# User Alessandro Ghedini <alessandro at ghedini.me>
# Date 1518438578 0
# Mon Feb 12 12:29:38 2018 +0000
# Branch http2-push-header
# Node ID 4eb0c9e8da0bc52065578e4ee78df1833617ac35
# Parent a49af443656f2b65ca5de9d8cad5594f44e18ff7
HTTP/2: added support for setting custom push request headers.
This implementa the http2_push_header configuration directive that makes
it possible to set custom request headers for pushed requests.
Complex values are evaluated in the context of the original request,
so it's possible to copy its headers into pushed requests.
Example usage:
http2_push_header User-Agent $http_user_agent;
diff -r a49af443656f -r 4eb0c9e8da0b 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 Mon Feb 12 12:29:38 2018 +0000
@@ -2516,15 +2516,22 @@
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;
+ ngx_uint_t i;
+ ngx_list_part_t *part;
+ ngx_table_elt_t *hdr, *h;
ngx_connection_t *fc;
+ ngx_http_header_t *hh;
ngx_http_request_t *r;
ngx_http_v2_node_t *node;
ngx_http_v2_stream_t *stream;
+ ngx_http_core_main_conf_t *cmcf;
+
node = ngx_http_v2_get_node_by_id(h2c, h2c->last_push, 1);
if (node == NULL) {
@@ -2605,6 +2612,57 @@
goto error;
}
+ cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
+
+ part = &headers_in->headers.part;
+ hdr = part->elts;
+
+ for (i = 0; /* void */; i++) {
+
+ if (i >= part->nelts) {
+ if (part->next == NULL) {
+ break;
+ }
+
+ part = part->next;
+ hdr = part->elts;
+ i = 0;
+ }
+
+ h = ngx_list_push(&r->headers_in.headers);
+ if (h == NULL) {
+ goto error;
+ }
+
+ h->key = hdr[i].key;
+
+ h->hash = hdr[i].hash;
+
+ h->value.len = hdr[i].value.len;
+
+ h->value.data = ngx_pnalloc(r->stream->pool, h->value.len + 1);
+ if (h->key.data == NULL) {
+ h->hash = 0;
+ goto error;
+ }
+
+ (void) ngx_cpystrn(h->value.data, hdr[i].value.data, h->value.len + 1);
+
+ h->lowcase_key = h->key.data;
+
+ hh = ngx_hash_find(&cmcf->headers_in_hash, h->hash,
+ h->lowcase_key, h->key.len);
+
+ if (hh == NULL) {
+ continue;
+ }
+
+ rc = hh->handler(r, h, hh->offset);
+ if (rc != NGX_OK) {
+ goto error;
+ }
+ }
+
fc->write->handler = ngx_http_v2_run_request_handler;
ngx_post_event(fc->write, &ngx_posted_events);
diff -r a49af443656f -r 4eb0c9e8da0b 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 Mon Feb 12 12:29:38 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 4eb0c9e8da0b 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 Mon Feb 12 12:29:38 2018 +0000
@@ -907,13 +907,19 @@
ngx_http_v2_push_resource(ngx_http_request_t *r, ngx_str_t *path,
ngx_str_t *authority)
{
- u_char *start, *pos, *tmp;
- size_t len;
- ngx_table_elt_t *host;
- ngx_connection_t *fc;
- ngx_http_v2_stream_t *stream;
- ngx_http_v2_out_frame_t *frame;
- ngx_http_v2_connection_t *h2c;
+ u_char *start, *pos, *tmp;
+ size_t len;
+ ngx_str_t value;
+ ngx_uint_t i;
+ ngx_list_part_t *part;
+ ngx_table_elt_t *host, *h;
+ ngx_connection_t *fc;
+ ngx_http_headers_in_t headers_in;
+ ngx_http_v2_stream_t *stream;
+ ngx_http_v2_loc_conf_t *h2lcf;
+ ngx_http_v2_out_frame_t *frame;
+ ngx_http_v2_connection_t *h2c;
+ ngx_http_v2_push_header_val_t *hv;
fc = r->connection;
@@ -972,6 +978,43 @@
+ authority->len
+ 1;
+ h2lcf = ngx_http_get_module_loc_conf(r, ngx_http_v2_module);
+
+ if ((h2lcf->push_headers != NULL) && (h2lcf->push_headers->nelts > 0)) {
+
+ if (ngx_list_init(&headers_in.headers, r->pool,
+ h2lcf->push_headers->nelts,
+ sizeof(ngx_table_elt_t))
+ != NGX_OK)
+ {
+ return NGX_ERROR;
+ }
+
+ hv = h2lcf->push_headers->elts;
+ for (i = 0; i < h2lcf->push_headers->nelts; i++) {
+
+ if (ngx_http_complex_value(r, &hv[i].value, &value) != NGX_OK) {
+ return NGX_ERROR;
+ }
+
+ if (value.len) {
+ h = ngx_list_push(&headers_in.headers);
+ if (h == NULL) {
+ return NGX_ERROR;
+ }
+
+ h->key = hv[i].key;
+
+ h->hash = hv[i].hash;
+
+ h->value = value;
+
+ len += 1 + NGX_HTTP_V2_INT_OCTETS + h->key.len
+ + NGX_HTTP_V2_INT_OCTETS + h->value.len;
+ }
+ }
+ }
+
tmp = ngx_palloc(r->pool, len);
pos = ngx_pnalloc(r->pool, len);
@@ -1018,6 +1061,26 @@
*pos++ = ngx_http_v2_indexed(NGX_HTTP_V2_SCHEME_HTTP_INDEX);
}
+ part = &headers_in.headers.part;
+ h = part->elts;
+
+ for (i = 0; /* void */; i++) {
+
+ if (i >= part->nelts) {
+ if (part->next == NULL) {
+ break;
+ }
+
+ part = part->next;
+ h = part->elts;
+ i = 0;
+ }
+
+ *pos++ = 0;
+ pos = ngx_http_v2_write_name(pos, h[i].key.data, h[i].key.len, tmp);
+ pos = ngx_http_v2_write_value(pos, h[i].value.data, h[i].value.len, tmp);
+ }
+
frame = ngx_http_v2_create_push_frame(r, start, pos);
if (frame == NULL) {
return NGX_ERROR;
@@ -1028,7 +1091,7 @@
stream->queued++;
return ngx_http_v2_push_stream(h2c, stream->node->id, pos - start,
- path, &host->value);
+ path, &host->value, &headers_in);
}
diff -r a49af443656f -r 4eb0c9e8da0b src/http/v2/ngx_http_v2_module.c
--- a/src/http/v2/ngx_http_v2_module.c Thu Feb 08 12:11:30 2018 +0300
+++ b/src/http/v2/ngx_http_v2_module.c Mon Feb 12 12:29:38 2018 +0000
@@ -28,6 +28,8 @@
void *child);
static char *ngx_http_v2_push(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
+static char *ngx_http_v2_push_header(ngx_conf_t *cf, ngx_command_t *cmd,
+ void *conf);
static char *ngx_http_v2_recv_buffer_size(ngx_conf_t *cf, void *post,
void *data);
@@ -152,6 +154,13 @@
0,
NULL },
+ { ngx_string("http2_push_header"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
+ ngx_http_v2_push_header,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ 0,
+ NULL },
+
{ ngx_string("spdy_recv_buffer_size"),
NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1,
ngx_http_v2_spdy_deprecated,
@@ -416,6 +425,7 @@
* set by ngx_pcalloc():
*
* h2lcf->pushes = NULL;
+ * h2lcf->push_headers = NULL;
*/
h2lcf->chunk_size = NGX_CONF_UNSET_SIZE;
@@ -441,6 +451,10 @@
conf->pushes = prev->pushes;
}
+ if (conf->push && conf->push_headers == NULL) {
+ conf->push_headers = prev->push_headers;
+ }
+
ngx_conf_merge_value(conf->push_preload, prev->push_preload, 0);
return NGX_CONF_OK;
@@ -506,6 +520,55 @@
static char *
+ngx_http_v2_push_header(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+ ngx_http_v2_loc_conf_t *h2lcf = conf;
+
+ ngx_str_t *value;
+ ngx_http_v2_push_header_val_t *hv;
+ ngx_http_compile_complex_value_t ccv;
+
+ value = cf->args->elts;
+
+ if (h2lcf->push_headers == NULL) {
+ h2lcf->push_headers = ngx_array_create(cf->pool, 1,
+ sizeof(ngx_http_v2_push_header_val_t));
+ if (h2lcf->push_headers == NULL) {
+ return NGX_CONF_ERROR;
+ }
+ }
+
+ hv = ngx_array_push(h2lcf->push_headers);
+ if (hv == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ hv->key = value[1];
+
+ ngx_strlow(hv->key.data, hv->key.data, hv->key.len);
+
+ hv->hash = ngx_hash_key(hv->key.data, hv->key.len);
+
+ if (value[2].len == 0) {
+ ngx_memzero(&hv->value, sizeof(ngx_http_complex_value_t));
+
+ } else {
+ ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
+
+ ccv.cf = cf;
+ ccv.value = &value[2];
+ ccv.complex_value = &hv->value;
+
+ if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
+ return NGX_CONF_ERROR;
+ }
+ }
+
+ return NGX_CONF_OK;
+}
+
+
+static char *
ngx_http_v2_recv_buffer_size(ngx_conf_t *cf, void *post, void *data)
{
size_t *sp = data;
diff -r a49af443656f -r 4eb0c9e8da0b src/http/v2/ngx_http_v2_module.h
--- a/src/http/v2/ngx_http_v2_module.h Thu Feb 08 12:11:30 2018 +0300
+++ b/src/http/v2/ngx_http_v2_module.h Mon Feb 12 12:29:38 2018 +0000
@@ -41,9 +41,17 @@
ngx_flag_t push;
ngx_array_t *pushes;
+ ngx_array_t *push_headers;
} ngx_http_v2_loc_conf_t;
+typedef struct {
+ ngx_http_complex_value_t value;
+ ngx_str_t key;
+ ngx_uint_t hash;
+} ngx_http_v2_push_header_val_t;
+
+
extern ngx_module_t ngx_http_v2_module;
More information about the nginx-devel
mailing list