[PATCH] HTTP/2: added support for setting custom push request headers
Ruslan Ermilov
ru at nginx.com
Mon Feb 12 14:11:55 UTC 2018
On Mon, Feb 12, 2018 at 12:35:13PM +0000, Alessandro Ghedini wrote:
> # 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;
If I'm not mistaken, both the original patch and this one
do not send the copied headers in the PUSH_PROMISE frame.
Given the https://trac.nginx.org/nginx/ticket/1478, and some
research of how different implementations behave, I prepared
the following patch:
# HG changeset patch
# User Ruslan Ermilov <ru at nginx.com>
# Date 1518444403 -10800
# Mon Feb 12 17:06:43 2018 +0300
# Node ID 4e72b3bfdeaa9917bbdc89a7fa75580c6bec41a7
# Parent 8b0553239592f5d0fd419e5116b9d343838685cf
HTTP/2: push additional headers (ticket #1478).
When pushing requests, copy and push Accept-Encoding, Accept-Language,
and User-Agent header fields from the original request.
diff --git a/src/http/v2/ngx_http_v2_filter_module.c b/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
@@ -50,20 +50,37 @@
#define NGX_HTTP_V2_STATUS_404_INDEX 13
#define NGX_HTTP_V2_STATUS_500_INDEX 14
+#define NGX_HTTP_V2_ACCEPT_ENCODING_INDEX 16
+#define NGX_HTTP_V2_ACCEPT_LANGUAGE_INDEX 17
#define NGX_HTTP_V2_CONTENT_LENGTH_INDEX 28
#define NGX_HTTP_V2_CONTENT_TYPE_INDEX 31
#define NGX_HTTP_V2_DATE_INDEX 33
#define NGX_HTTP_V2_LAST_MODIFIED_INDEX 44
#define NGX_HTTP_V2_LOCATION_INDEX 46
#define NGX_HTTP_V2_SERVER_INDEX 54
+#define NGX_HTTP_V2_USER_AGENT_INDEX 58
#define NGX_HTTP_V2_VARY_INDEX 59
#define NGX_HTTP_V2_NO_TRAILERS (ngx_http_v2_out_frame_t *) -1
+typedef struct {
+ ngx_str_t authority;
+#if (NGX_HTTP_GZIP)
+ ngx_str_t accept_encoding;
+#endif
+#if (NGX_HTTP_HEADERS)
+ ngx_str_t accept_language;
+#endif
+ ngx_str_t user_agent;
+} ngx_http_v2_push_ctx_t;
+
+
static ngx_int_t ngx_http_v2_push_resources(ngx_http_request_t *r);
static ngx_int_t ngx_http_v2_push_resource(ngx_http_request_t *r,
- ngx_str_t *path, ngx_str_t *authority);
+ ngx_str_t *path, ngx_http_v2_push_ctx_t *ctx);
+static ngx_int_t ngx_http_v2_indexed_header_encode(ngx_http_request_t *r,
+ u_char index, ngx_str_t *value, ngx_str_t *header);
static u_char *ngx_http_v2_string_encode(u_char *dst, u_char *src, size_t len,
u_char *tmp, ngx_uint_t lower);
@@ -685,16 +702,17 @@ ngx_http_v2_push_resources(ngx_http_requ
{
u_char *start, *end, *last;
ngx_int_t rc;
- ngx_str_t path, authority;
+ ngx_str_t path;
ngx_uint_t i, push;
ngx_table_elt_t **h;
ngx_http_v2_loc_conf_t *h2lcf;
+ ngx_http_v2_push_ctx_t ctx;
ngx_http_complex_value_t *pushes;
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"http2 push resources");
- ngx_str_null(&authority);
+ ngx_memzero(&ctx, sizeof(ngx_http_v2_push_ctx_t));
h2lcf = ngx_http_get_module_loc_conf(r, ngx_http_v2_module);
@@ -715,7 +733,7 @@ ngx_http_v2_push_resources(ngx_http_requ
continue;
}
- rc = ngx_http_v2_push_resource(r, &path, &authority);
+ rc = ngx_http_v2_push_resource(r, &path, &ctx);
if (rc == NGX_ERROR) {
return NGX_ERROR;
@@ -880,7 +898,7 @@ ngx_http_v2_push_resources(ngx_http_requ
if (push && path.len
&& !(path.len > 1 && path.data[0] == '/' && path.data[1] == '/'))
{
- rc = ngx_http_v2_push_resource(r, &path, &authority);
+ rc = ngx_http_v2_push_resource(r, &path, &ctx);
if (rc == NGX_ERROR) {
return NGX_ERROR;
@@ -905,11 +923,17 @@ ngx_http_v2_push_resources(ngx_http_requ
static ngx_int_t
ngx_http_v2_push_resource(ngx_http_request_t *r, ngx_str_t *path,
- ngx_str_t *authority)
+ ngx_http_v2_push_ctx_t *ctx)
{
u_char *start, *pos, *tmp;
size_t len;
- ngx_table_elt_t *host;
+ ngx_table_elt_t *host, *user_agent;
+#if (NGX_HTTP_GZIP)
+ ngx_table_elt_t *accept_encoding;
+#endif
+#if (NGX_HTTP_HEADERS)
+ ngx_table_elt_t *accept_language;
+#endif
ngx_connection_t *fc;
ngx_http_v2_stream_t *stream;
ngx_http_v2_out_frame_t *frame;
@@ -950,31 +974,69 @@ ngx_http_v2_push_resource(ngx_http_reque
return NGX_ABORT;
}
- if (authority->len == 0) {
-
- len = 1 + NGX_HTTP_V2_INT_OCTETS + host->value.len;
-
- tmp = ngx_palloc(r->pool, len);
- pos = ngx_pnalloc(r->pool, len);
-
- if (pos == NULL || tmp == NULL) {
+#if (NGX_HTTP_GZIP)
+ accept_encoding = r->headers_in.accept_encoding;
+#endif
+
+#if (NGX_HTTP_HEADERS)
+ accept_language = r->headers_in.accept_language;
+#endif
+
+ user_agent = r->headers_in.user_agent;
+
+ if (ctx->authority.len == 0) {
+
+ if (ngx_http_v2_indexed_header_encode(r, NGX_HTTP_V2_AUTHORITY_INDEX,
+ &host->value, &ctx->authority)
+ != NGX_OK)
+ {
return NGX_ERROR;
}
- authority->data = pos;
-
- *pos++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_AUTHORITY_INDEX);
- pos = ngx_http_v2_write_value(pos, host->value.data, host->value.len,
- tmp);
-
- authority->len = pos - authority->data;
+#if (NGX_HTTP_GZIP)
+ if (accept_encoding
+ && ngx_http_v2_indexed_header_encode(r,
+ NGX_HTTP_V2_ACCEPT_ENCODING_INDEX,
+ &accept_encoding->value, &ctx->accept_encoding)
+ != NGX_OK)
+ {
+ return NGX_ERROR;
+ }
+#endif
+
+#if (NGX_HTTP_HEADERS)
+ if (accept_language
+ && ngx_http_v2_indexed_header_encode(r,
+ NGX_HTTP_V2_ACCEPT_LANGUAGE_INDEX,
+ &accept_language->value, &ctx->accept_language)
+ != NGX_OK)
+ {
+ return NGX_ERROR;
+ }
+#endif
+
+ if (user_agent
+ && ngx_http_v2_indexed_header_encode(r,
+ NGX_HTTP_V2_USER_AGENT_INDEX,
+ &user_agent->value, &ctx->user_agent)
+ != NGX_OK)
+ {
+ return NGX_ERROR;
+ }
}
len = (h2c->table_update ? 1 : 0)
+ 1
+ 1 + NGX_HTTP_V2_INT_OCTETS + path->len
- + authority->len
- + 1;
+ + ctx->authority.len
+ + 1
+#if (NGX_HTTP_GZIP)
+ + ctx->accept_encoding.len
+#endif
+#if (NGX_HTTP_HEADERS)
+ + ctx->accept_language.len
+#endif
+ + ctx->user_agent.len;
tmp = ngx_palloc(r->pool, len);
pos = ngx_pnalloc(r->pool, len);
@@ -1006,7 +1068,7 @@ ngx_http_v2_push_resource(ngx_http_reque
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, fc->log, 0,
"http2 push header: \":authority: %V\"", &host->value);
- pos = ngx_cpymem(pos, authority->data, authority->len);
+ pos = ngx_cpymem(pos, ctx->authority.data, ctx->authority.len);
#if (NGX_HTTP_SSL)
if (fc->ssl) {
@@ -1022,6 +1084,36 @@ ngx_http_v2_push_resource(ngx_http_reque
*pos++ = ngx_http_v2_indexed(NGX_HTTP_V2_SCHEME_HTTP_INDEX);
}
+#if (NGX_HTTP_GZIP)
+ if (accept_encoding) {
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, fc->log, 0,
+ "http2 push header: \"accept-encoding: %V\"",
+ &accept_encoding->value);
+
+ pos = ngx_cpymem(pos, ctx->accept_encoding.data,
+ ctx->accept_encoding.len);
+ }
+#endif
+
+#if (NGX_HTTP_HEADERS)
+ if (accept_language) {
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, fc->log, 0,
+ "http2 push header: \"accept-language: %V\"",
+ &accept_language->value);
+
+ pos = ngx_cpymem(pos, ctx->accept_language.data,
+ ctx->accept_language.len);
+ }
+#endif
+
+ if (user_agent) {
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, fc->log, 0,
+ "http2 push header: \"user-agent: %V\"",
+ &user_agent->value);
+
+ pos = ngx_cpymem(pos, ctx->user_agent.data, ctx->user_agent.len);
+ }
+
frame = ngx_http_v2_create_push_frame(r, start, pos);
if (frame == NULL) {
return NGX_ERROR;
@@ -1036,6 +1128,33 @@ ngx_http_v2_push_resource(ngx_http_reque
}
+static ngx_int_t
+ngx_http_v2_indexed_header_encode(ngx_http_request_t *r, u_char index,
+ ngx_str_t *value, ngx_str_t *header)
+{
+ size_t len;
+ u_char *pos, *tmp;
+
+ len = 1 + NGX_HTTP_V2_INT_OCTETS + value->len;
+
+ tmp = ngx_palloc(r->pool, len);
+ pos = ngx_pnalloc(r->pool, len);
+
+ if (pos == NULL || tmp == NULL) {
+ return NGX_ERROR;
+ }
+
+ header->data = pos;
+
+ *pos++ = ngx_http_v2_inc_indexed(index);
+ pos = ngx_http_v2_write_value(pos, value->data, value->len, tmp);
+
+ header->len = pos - header->data;
+
+ return NGX_OK;
+}
+
+
static 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