diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c index fd00ba50a..6d91c7cf5 100644 --- 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_intercept_errors(ngx_http_request_t *r, 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_response_length_variable( 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_upstream_vars[] = { { 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_request_t *r, ngx_http_upstream_t *u) 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_request_t *r, ngx_http_upstream_t *u) 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_http_request_t *r, ngx_http_upstream_t *u) 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_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) +{ + 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_http_request_t *r, } 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) { @@ -5381,6 +5462,21 @@ ngx_http_upstream_header_variable(ngx_http_request_t *r, } +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 index 56b54d13b..a56238d37 100644 --- 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;