[PATCH 3 of 3] Upstream: add support for trailers in HTTP responses
Piotr Sikora
piotrsikora at google.com
Fri Mar 24 10:47:41 UTC 2017
# HG changeset patch
# User Piotr Sikora <piotrsikora at google.com>
# Date 1490351854 25200
# Fri Mar 24 03:37:34 2017 -0700
# Node ID 94e49d08e3b4de32416f5841e38a2388e092191d
# Parent 6d878f4585b977053a9d00053bbb7aff263eb96c
Upstream: add support for trailers in HTTP responses.
Please note that due to how upstream module terminates processing of
responses that cannot have message body (responses to HEAD requests,
and responses with 1xx, 204 and 304 status codes), trailers of those
responses won't be passed to the downstream.
This change also adds $upstream_trailer_* variables.
Signed-off-by: Piotr Sikora <piotrsikora at google.com>
diff -r 6d878f4585b9 -r 94e49d08e3b4 src/http/modules/ngx_http_fastcgi_module.c
--- a/src/http/modules/ngx_http_fastcgi_module.c
+++ b/src/http/modules/ngx_http_fastcgi_module.c
@@ -2784,10 +2784,10 @@ ngx_http_fastcgi_create_loc_conf(ngx_con
conf->upstream.intercept_errors = NGX_CONF_UNSET;
- /* "fastcgi_cyclic_temp_file" is disabled */
+ /* the hardcoded values */
conf->upstream.cyclic_temp_file = 0;
-
conf->upstream.change_buffering = 1;
+ conf->upstream.pass_trailers = 0;
conf->catch_stderr = NGX_CONF_UNSET_PTR;
diff -r 6d878f4585b9 -r 94e49d08e3b4 src/http/modules/ngx_http_memcached_module.c
--- a/src/http/modules/ngx_http_memcached_module.c
+++ b/src/http/modules/ngx_http_memcached_module.c
@@ -619,6 +619,7 @@ ngx_http_memcached_create_loc_conf(ngx_c
conf->upstream.pass_request_headers = 0;
conf->upstream.pass_request_body = 0;
conf->upstream.force_ranges = 1;
+ conf->upstream.pass_trailers = 0;
conf->index = NGX_CONF_UNSET;
conf->gzip_flag = NGX_CONF_UNSET_UINT;
diff -r 6d878f4585b9 -r 94e49d08e3b4 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
@@ -2886,11 +2886,12 @@ ngx_http_proxy_create_loc_conf(ngx_conf_
conf->ssl_passwords = NGX_CONF_UNSET_PTR;
#endif
- /* "proxy_cyclic_temp_file" is disabled */
+ /* the hardcoded values */
conf->upstream.cyclic_temp_file = 0;
+ conf->upstream.change_buffering = 1;
+ conf->upstream.pass_trailers = 0;
conf->redirect = NGX_CONF_UNSET;
- conf->upstream.change_buffering = 1;
conf->cookie_domains = NGX_CONF_UNSET_PTR;
conf->cookie_paths = NGX_CONF_UNSET_PTR;
diff -r 6d878f4585b9 -r 94e49d08e3b4 src/http/modules/ngx_http_scgi_module.c
--- a/src/http/modules/ngx_http_scgi_module.c
+++ b/src/http/modules/ngx_http_scgi_module.c
@@ -1234,10 +1234,10 @@ ngx_http_scgi_create_loc_conf(ngx_conf_t
conf->upstream.intercept_errors = NGX_CONF_UNSET;
- /* "scgi_cyclic_temp_file" is disabled */
+ /* the hardcoded values */
conf->upstream.cyclic_temp_file = 0;
-
conf->upstream.change_buffering = 1;
+ conf->upstream.pass_trailers = 0;
ngx_str_set(&conf->upstream.module, "scgi");
diff -r 6d878f4585b9 -r 94e49d08e3b4 src/http/modules/ngx_http_uwsgi_module.c
--- a/src/http/modules/ngx_http_uwsgi_module.c
+++ b/src/http/modules/ngx_http_uwsgi_module.c
@@ -1448,10 +1448,10 @@ ngx_http_uwsgi_create_loc_conf(ngx_conf_
conf->ssl_passwords = NGX_CONF_UNSET_PTR;
#endif
- /* "uwsgi_cyclic_temp_file" is disabled */
+ /* the hardcoded values */
conf->upstream.cyclic_temp_file = 0;
-
conf->upstream.change_buffering = 1;
+ conf->upstream.pass_trailers = 0;
ngx_str_set(&conf->upstream.module, "uwsgi");
diff -r 6d878f4585b9 -r 94e49d08e3b4 src/http/ngx_http_upstream.c
--- a/src/http/ngx_http_upstream.c
+++ b/src/http/ngx_http_upstream.c
@@ -55,6 +55,8 @@ static ngx_int_t ngx_http_upstream_inter
static ngx_int_t ngx_http_upstream_test_connect(ngx_connection_t *c);
static ngx_int_t ngx_http_upstream_process_headers(ngx_http_request_t *r,
ngx_http_upstream_t *u);
+static ngx_int_t ngx_http_upstream_process_trailers(ngx_http_request_t *r,
+ ngx_http_upstream_t *u);
static void ngx_http_upstream_process_body_in_memory(ngx_http_request_t *r,
ngx_http_upstream_t *u);
static void ngx_http_upstream_send_response(ngx_http_request_t *r,
@@ -166,6 +168,8 @@ static ngx_int_t ngx_http_upstream_respo
ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data);
static ngx_int_t ngx_http_upstream_header_variable(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data);
+static ngx_int_t ngx_http_upstream_trailer_variable(ngx_http_request_t *r,
+ ngx_http_variable_value_t *v, uintptr_t data);
static ngx_int_t ngx_http_upstream_cookie_variable(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data);
@@ -422,6 +426,9 @@ static ngx_http_variable_t ngx_http_ups
{ ngx_string("upstream_http_"), NULL, ngx_http_upstream_header_variable,
0, NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_PREFIX, 0 },
+ { ngx_string("upstream_trailer_"), NULL, ngx_http_upstream_trailer_variable,
+ 0, NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_PREFIX, 0 },
+
{ ngx_string("upstream_cookie_"), NULL, ngx_http_upstream_cookie_variable,
0, NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_PREFIX, 0 },
@@ -1041,6 +1048,13 @@ ngx_http_upstream_cache_send(ngx_http_re
return NGX_ERROR;
}
+ if (ngx_list_init(&u->headers_in.trailers, r->pool, 2,
+ sizeof(ngx_table_elt_t))
+ != NGX_OK)
+ {
+ return NGX_ERROR;
+ }
+
rc = u->process_header(r);
if (rc == NGX_OK) {
@@ -1861,6 +1875,13 @@ ngx_http_upstream_reinit(ngx_http_reques
return NGX_ERROR;
}
+ if (ngx_list_init(&u->headers_in.trailers, r->pool, 2,
+ sizeof(ngx_table_elt_t))
+ != NGX_OK)
+ {
+ return NGX_ERROR;
+ }
+
/* reinit the request chain */
file_pos = 0;
@@ -2228,6 +2249,15 @@ ngx_http_upstream_process_header(ngx_htt
return;
}
+ if (ngx_list_init(&u->headers_in.trailers, r->pool, 2,
+ sizeof(ngx_table_elt_t))
+ != NGX_OK)
+ {
+ ngx_http_upstream_finalize_request(r, u,
+ NGX_HTTP_INTERNAL_SERVER_ERROR);
+ return;
+ }
+
#if (NGX_HTTP_CACHE)
if (r->cache) {
@@ -2735,6 +2765,44 @@ ngx_http_upstream_process_headers(ngx_ht
}
+static ngx_int_t
+ngx_http_upstream_process_trailers(ngx_http_request_t *r, ngx_http_upstream_t *u)
+{
+ ngx_uint_t i;
+ ngx_list_part_t *part;
+ ngx_table_elt_t *h, *ho;
+
+ if (!u->conf->pass_trailers || !r->allow_trailers || !r->expect_trailers) {
+ return NGX_OK;
+ }
+
+ part = &u->headers_in.trailers.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;
+ }
+
+ ho = ngx_list_push(&r->headers_out.trailers);
+ if (ho == NULL) {
+ return NGX_ERROR;
+ }
+
+ *ho = h[i];
+ }
+
+ return NGX_OK;
+}
+
+
static void
ngx_http_upstream_process_body_in_memory(ngx_http_request_t *r,
ngx_http_upstream_t *u)
@@ -4396,6 +4464,13 @@ ngx_http_upstream_finalize_request(ngx_h
}
if (rc == 0) {
+ if (ngx_http_upstream_process_trailers(r, u) != NGX_OK) {
+ rc = NGX_ERROR;
+ flush = 1;
+ }
+ }
+
+ if (rc == 0) {
rc = ngx_http_send_special(r, NGX_HTTP_LAST);
} else if (flush) {
@@ -5519,6 +5594,21 @@ ngx_http_upstream_header_variable(ngx_ht
static ngx_int_t
+ngx_http_upstream_trailer_variable(ngx_http_request_t *r,
+ ngx_http_variable_value_t *v, uintptr_t data)
+{
+ if (r->upstream == NULL) {
+ v->not_found = 1;
+ return NGX_OK;
+ }
+
+ return ngx_http_variable_unknown_header(v, (ngx_str_t *) data,
+ &r->upstream->headers_in.trailers.part,
+ sizeof("upstream_trailer_") - 1);
+}
+
+
+static ngx_int_t
ngx_http_upstream_cookie_variable(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data)
{
diff -r 6d878f4585b9 -r 94e49d08e3b4 src/http/ngx_http_upstream.h
--- a/src/http/ngx_http_upstream.h
+++ b/src/http/ngx_http_upstream.h
@@ -183,6 +183,7 @@ typedef struct {
ngx_hash_t hide_headers_hash;
ngx_array_t *hide_headers;
ngx_array_t *pass_headers;
+ ngx_flag_t pass_trailers;
ngx_http_upstream_local_t *local;
@@ -248,6 +249,7 @@ typedef struct {
typedef struct {
ngx_list_t headers;
+ ngx_list_t trailers;
ngx_uint_t status_n;
ngx_str_t status_line;
More information about the nginx-devel
mailing list