[nginx] Upstream: trailers support, u->conf->pass_trailers flag.
Maxim Dounin
mdounin at mdounin.ru
Sat Mar 17 20:08:23 UTC 2018
details: http://hg.nginx.org/nginx/rev/098bbd076a2d
branches:
changeset: 7230:098bbd076a2d
user: Maxim Dounin <mdounin at mdounin.ru>
date: Sat Mar 17 23:04:21 2018 +0300
description:
Upstream: trailers support, u->conf->pass_trailers flag.
Basic trailer headers support allows one to access response trailers
via the $upstream_trailer_* variables.
Additionally, the u->conf->pass_trailers flag was introduced. When the
flag is set, trailer headers from the upstream response are passed to
the client. Like normal headers, trailer headers will be hidden
if present in u->conf->hide_headers_hash.
diffstat:
src/http/ngx_http_upstream.c | 96 ++++++++++++++++++++++++++++++++++++++++++++
src/http/ngx_http_upstream.h | 2 +
2 files changed, 98 insertions(+), 0 deletions(-)
diffs (181 lines):
diff --git a/src/http/ngx_http_upstream.c b/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_send_response(ngx_http_request_t *r,
ngx_http_upstream_t *u);
static void ngx_http_upstream_upgrade(ngx_http_request_t *r,
@@ -164,6 +166,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);
@@ -423,6 +427,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 },
@@ -1046,6 +1053,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) {
@@ -1883,6 +1897,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;
@@ -2237,6 +2258,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,51 @@ 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) {
+ 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;
+ }
+
+ if (ngx_hash_find(&u->conf->hide_headers_hash, h[i].hash,
+ h[i].lowcase_key, h[i].key.len))
+ {
+ continue;
+ }
+
+ 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_send_response(ngx_http_request_t *r, ngx_http_upstream_t *u)
{
@@ -4272,6 +4347,12 @@ ngx_http_upstream_finalize_request(ngx_h
}
if (rc == 0) {
+
+ if (ngx_http_upstream_process_trailers(r, u) != NGX_OK) {
+ ngx_http_finalize_request(r, NGX_ERROR);
+ return;
+ }
+
rc = ngx_http_send_special(r, NGX_HTTP_LAST);
} else if (flush) {
@@ -5382,6 +5463,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 --git a/src/http/ngx_http_upstream.h b/src/http/ngx_http_upstream.h
--- a/src/http/ngx_http_upstream.h
+++ b/src/http/ngx_http_upstream.h
@@ -222,6 +222,7 @@ typedef struct {
signed store:2;
unsigned intercept_404:1;
unsigned change_buffering:1;
+ unsigned pass_trailers:1;
#if (NGX_HTTP_SSL || NGX_COMPAT)
ngx_ssl_t *ssl;
@@ -251,6 +252,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