Welcome! Log In Create A New Profile

Advanced

[PATCH 2 of 2] Headers filter: add "add_trailer" directive

Piotr Sikora
June 26, 2016 07:14PM
# HG changeset patch
# User Piotr Sikora <piotrsikora@google.com>
# Date 1466735587 25200
# Thu Jun 23 19:33:07 2016 -0700
# Node ID e21760ce55fdae50a6723aeb4cb6e0b0bcf73dcb
# Parent a96187a9806536ab2a8bf3fa7f7b659cf5d3ff13
Headers filter: add "add_trailer" directive.

Trailers added using this directive are evaluated after response body
is processed by output filters (but before it's written to the wire),
so it's possible to use variables calculated from the response body
as the trailer value.

Signed-off-by: Piotr Sikora <piotrsikora@google.com>

diff -r a96187a98065 -r e21760ce55fd src/http/modules/ngx_http_chunked_filter_module.c
--- a/src/http/modules/ngx_http_chunked_filter_module.c
+++ b/src/http/modules/ngx_http_chunked_filter_module.c
@@ -254,6 +254,10 @@ ngx_http_chunked_get_trailers(ngx_http_r
ngx_table_elt_t *header;
ngx_http_chunked_filter_ctx_t *ctx;

+ if (ngx_http_eval_trailers(r) != NGX_OK) {
+ return NULL;
+ }
+
len = 0;

part = &r->headers_out.trailers.part;
diff -r a96187a98065 -r e21760ce55fd src/http/modules/ngx_http_headers_filter_module.c
--- a/src/http/modules/ngx_http_headers_filter_module.c
+++ b/src/http/modules/ngx_http_headers_filter_module.c
@@ -48,6 +48,7 @@ typedef struct {
time_t expires_time;
ngx_http_complex_value_t *expires_value;
ngx_array_t *headers;
+ ngx_array_t *trailers;
} ngx_http_headers_conf_t;


@@ -72,6 +73,8 @@ static char *ngx_http_headers_expires(ng
void *conf);
static char *ngx_http_headers_add(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
+static char *ngx_http_headers_add_trailer(ngx_conf_t *cf, ngx_command_t *cmd,
+ void *conf);


static ngx_http_set_header_t ngx_http_set_headers[] = {
@@ -108,6 +111,14 @@ static ngx_command_t ngx_http_headers_f
0,
NULL},

+ { ngx_string("add_trailer"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF
+ |NGX_CONF_TAKE23,
+ ngx_http_headers_add_trailer,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ 0,
+ NULL},
+
ngx_null_command
};

@@ -149,15 +160,23 @@ static ngx_http_output_header_filter_pt
static ngx_int_t
ngx_http_headers_filter(ngx_http_request_t *r)
{
+ u_char *p, *data;
+ size_t len;
ngx_str_t value;
ngx_uint_t i, safe_status;
+ ngx_table_elt_t *t;
ngx_http_header_val_t *h;
ngx_http_headers_conf_t *conf;

+ if (r != r->main) {
+ return ngx_http_next_header_filter(r);
+ }
+
conf = ngx_http_get_module_loc_conf(r, ngx_http_headers_filter_module);

- if ((conf->expires == NGX_HTTP_EXPIRES_OFF && conf->headers == NULL)
- || r != r->main)
+ if (conf->expires == NGX_HTTP_EXPIRES_OFF
+ && conf->headers == NULL
+ && conf->trailers == NULL)
{
return ngx_http_next_header_filter(r);
}
@@ -205,6 +224,64 @@ ngx_http_headers_filter(ngx_http_request
}
}

+ if (conf->trailers && r->trailers_ok) {
+ len = 0;
+
+ h = conf->trailers->elts;
+ for (i = 0; i < conf->trailers->nelts; i++) {
+
+ if (!safe_status && !h[i].always) {
+ continue;
+ }
+
+ if (h[i].value.value.len) {
+ len += h[i].key.len + sizeof(", ") - 1;
+ }
+ }
+
+ if (len == 0) {
+ return ngx_http_next_header_filter(r);
+ }
+
+ len -= sizeof(", ") - 1;
+
+ t = ngx_list_push(&r->headers_out.headers);
+ if (t == NULL) {
+ return NGX_ERROR;
+ }
+
+ data = ngx_pnalloc(r->pool, len);
+ if (data == NULL) {
+ return NGX_ERROR;
+ }
+
+ p = data;
+
+ h = conf->trailers->elts;
+ for (i = 0; i < conf->trailers->nelts; i++) {
+
+ if (!safe_status && !h[i].always) {
+ continue;
+ }
+
+ if (h[i].value.value.len) {
+ p = ngx_copy(p, h[i].key.data, h[i].key.len);
+
+ if (p == data + len) {
+ break;
+ }
+
+ *p++ = ','; *p++ = ' ';
+ }
+ }
+
+ ngx_str_set(&t->key, "Trailer");
+ t->value.data = data;
+ t->value.len = len;
+ t->hash = ngx_hash(ngx_hash(ngx_hash(ngx_hash(ngx_hash(
+ ngx_hash('t', 'r'), 'a'), 'i'), 'l'), 'e'), 'r');
+ }
+
return ngx_http_next_header_filter(r);
}

@@ -541,6 +618,67 @@ ngx_http_set_response_header(ngx_http_re
}


+ngx_int_t
+ngx_http_eval_trailers(ngx_http_request_t *r)
+{
+ ngx_str_t value;
+ ngx_uint_t i, safe_status;
+ ngx_table_elt_t *t;
+ ngx_http_header_val_t *h;
+ ngx_http_headers_conf_t *conf;
+
+ conf = ngx_http_get_module_loc_conf(r, ngx_http_headers_filter_module);
+
+ if (conf->trailers == NULL) {
+ return NGX_OK;
+ }
+
+ switch (r->headers_out.status) {
+
+ case NGX_HTTP_OK:
+ case NGX_HTTP_CREATED:
+ case NGX_HTTP_NO_CONTENT:
+ case NGX_HTTP_PARTIAL_CONTENT:
+ case NGX_HTTP_MOVED_PERMANENTLY:
+ case NGX_HTTP_MOVED_TEMPORARILY:
+ case NGX_HTTP_SEE_OTHER:
+ case NGX_HTTP_NOT_MODIFIED:
+ case NGX_HTTP_TEMPORARY_REDIRECT:
+ safe_status = 1;
+ break;
+
+ default:
+ safe_status = 0;
+ break;
+ }
+
+ h = conf->trailers->elts;
+ for (i = 0; i < conf->trailers->nelts; i++) {
+
+ if (!safe_status && !h[i].always) {
+ continue;
+ }
+
+ if (ngx_http_complex_value(r, &h[i].value, &value) != NGX_OK) {
+ return NGX_ERROR;
+ }
+
+ if (value.len) {
+ t = ngx_list_push(&r->headers_out.trailers);
+ if (t == NULL) {
+ return NGX_ERROR;
+ }
+
+ t->key = h[i].key;
+ t->value = value;
+ t->hash = 1;
+ }
+ }
+
+ return NGX_OK;
+}
+
+
static void *
ngx_http_headers_create_conf(ngx_conf_t *cf)
{
@@ -555,6 +693,7 @@ ngx_http_headers_create_conf(ngx_conf_t
* set by ngx_pcalloc():
*
* conf->headers = NULL;
+ * conf->trailers = NULL;
* conf->expires_time = 0;
* conf->expires_value = NULL;
*/
@@ -585,6 +724,10 @@ ngx_http_headers_merge_conf(ngx_conf_t *
conf->headers = prev->headers;
}

+ if (conf->trailers == NULL) {
+ conf->trailers = prev->trailers;
+ }
+
return NGX_CONF_OK;
}

@@ -739,3 +882,63 @@ ngx_http_headers_add(ngx_conf_t *cf, ngx

return NGX_CONF_OK;
}
+
+
+static char *
+ngx_http_headers_add_trailer(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+ ngx_http_headers_conf_t *hcf = conf;
+
+ ngx_str_t *value;
+ ngx_http_header_val_t *hv;
+ ngx_http_compile_complex_value_t ccv;
+
+ value = cf->args->elts;
+
+ if (hcf->trailers == NULL) {
+ hcf->trailers = ngx_array_create(cf->pool, 1,
+ sizeof(ngx_http_header_val_t));
+ if (hcf->trailers == NULL) {
+ return NGX_CONF_ERROR;
+ }
+ }
+
+ hv = ngx_array_push(hcf->trailers);
+ if (hv == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ hv->key = value[1];
+ hv->handler = NULL;
+ hv->offset = 0;
+ hv->always = 0;
+
+ 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;
+ }
+ }
+
+ if (cf->args->nelts == 3) {
+ return NGX_CONF_OK;
+ }
+
+ if (ngx_strcmp(value[3].data, "always") != 0) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "invalid parameter \"%V\"", &value[3]);
+ return NGX_CONF_ERROR;
+ }
+
+ hv->always = 1;
+
+ return NGX_CONF_OK;
+}
diff -r a96187a98065 -r e21760ce55fd src/http/ngx_http.h
--- a/src/http/ngx_http.h
+++ b/src/http/ngx_http.h
@@ -146,6 +146,7 @@ ngx_int_t ngx_http_special_response_hand
ngx_int_t ngx_http_filter_finalize_request(ngx_http_request_t *r,
ngx_module_t *m, ngx_int_t error);
void ngx_http_clean_header(ngx_http_request_t *r);
+ngx_int_t ngx_http_eval_trailers(ngx_http_request_t *r);


ngx_int_t ngx_http_discard_request_body(ngx_http_request_t *r);
diff -r a96187a98065 -r e21760ce55fd 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
@@ -606,6 +606,10 @@ ngx_http_v2_create_trailers_frame(ngx_ht
ngx_list_part_t *part;
ngx_table_elt_t *header;

+ if (ngx_http_eval_trailers(r) != NGX_OK) {
+ return NULL;
+ }
+
len = 0;
tmp_len = 0;


_______________________________________________
nginx-devel mailing list
nginx-devel@nginx.org
http://mailman.nginx.org/mailman/listinfo/nginx-devel
Subject Author Views Posted

[PATCH 1 of 2] HTTP: add support for trailers in HTTP responses

Piotr Sikora 924 June 26, 2016 07:14PM

[PATCH 2 of 2] Headers filter: add "add_trailer" directive

Piotr Sikora 422 June 26, 2016 07:14PM

Re: [PATCH 1 of 2] HTTP: add support for trailers in HTTP responses

Maxim Dounin 379 June 27, 2016 09:46AM

Re: [PATCH 1 of 2] HTTP: add support for trailers in HTTP responses

Piotr Sikora 387 June 27, 2016 10:38AM

Re: [PATCH 1 of 2] HTTP: add support for trailers in HTTP responses

shuxinyang 455 June 27, 2016 01:06PM

Re: [PATCH 1 of 2] HTTP: add support for trailers in HTTP responses

Piotr Sikora 361 June 27, 2016 01:14PM

Re: [PATCH 1 of 2] HTTP: add support for trailers in HTTP responses

shuxinyang 381 June 27, 2016 02:56PM

Re: [PATCH 1 of 2] HTTP: add support for trailers in HTTP responses

Piotr Sikora 476 June 27, 2016 03:16PM

Re: [PATCH 1 of 2] HTTP: add support for trailers in HTTP responses

shuxinyang 390 June 27, 2016 06:04PM

Re: [PATCH 1 of 2] HTTP: add support for trailers in HTTP responses

Piotr Sikora 356 June 27, 2016 07:18PM

Re: [PATCH 1 of 2] HTTP: add support for trailers in HTTP responses

shuxinyang 362 June 27, 2016 09:00PM

Re: [PATCH 1 of 2] HTTP: add support for trailers in HTTP responses

Piotr Sikora 326 June 27, 2016 09:46PM

Re: [PATCH 1 of 2] HTTP: add support for trailers in HTTP responses

Maxim Dounin 364 June 27, 2016 01:54PM

Re: [PATCH 1 of 2] HTTP: add support for trailers in HTTP responses

Piotr Sikora 365 June 27, 2016 03:06PM

Re: [PATCH 1 of 2] HTTP: add support for trailers in HTTP responses

Piotr Sikora 335 June 30, 2016 03:58PM

Re: [PATCH 1 of 2] HTTP: add support for trailers in HTTP responses

Maxim Dounin 373 July 04, 2016 10:22AM

Re: [PATCH 1 of 2] HTTP: add support for trailers in HTTP responses

Piotr Sikora 368 July 06, 2016 05:04PM

Re: [PATCH 1 of 2] HTTP: add support for trailers in HTTP responses

Maxim Dounin 354 July 07, 2016 11:02AM

Re: [PATCH 1 of 2] HTTP: add support for trailers in HTTP responses

Piotr Sikora 335 July 07, 2016 04:10PM

Re: [PATCH 1 of 2] HTTP: add support for trailers in HTTP responses

Maxim Dounin 341 July 07, 2016 07:22PM

Re: [PATCH 1 of 2] HTTP: add support for trailers in HTTP responses

Piotr Sikora 392 July 13, 2016 01:28PM

Re: [PATCH 1 of 2] HTTP: add support for trailers in HTTP responses

Maxim Dounin 405 July 13, 2016 02:44PM

Re: [PATCH 1 of 2] HTTP: add support for trailers in HTTP responses

Piotr Sikora 313 July 13, 2016 08:36PM

Re: [PATCH 1 of 2] HTTP: add support for trailers in HTTP responses

Alexey Ivanov 337 July 20, 2016 06:36PM

Re: [PATCH 1 of 2] HTTP: add support for trailers in HTTP responses

Maxim Dounin 317 July 20, 2016 09:24PM

Re: [PATCH 1 of 2] HTTP: add support for trailers in HTTP responses

Alexey Ivanov 346 July 20, 2016 09:34PM

Re: [PATCH 1 of 2] HTTP: add support for trailers in HTTP responses

Maxim Dounin 420 July 21, 2016 09:46AM

[PATCH] HTTP: add support for trailers in HTTP responses

Piotr Sikora 324 August 01, 2016 01:00AM

Re: [PATCH] HTTP: add support for trailers in HTTP responses

Piotr Sikora 310 August 01, 2016 03:36AM

Re: [PATCH] HTTP: add support for trailers in HTTP responses

Maxim Dounin 283 August 01, 2016 09:24AM

Re: [PATCH] HTTP: add support for trailers in HTTP responses

Piotr Sikora 442 August 01, 2016 01:58PM

Re: [PATCH] HTTP: add support for trailers in HTTP responses

Maxim Dounin 341 August 03, 2016 10:26PM

Re: [PATCH] HTTP: add support for trailers in HTTP responses

Piotr Sikora 297 August 18, 2016 09:14PM

Re: [PATCH] HTTP: add support for trailers in HTTP responses

Valentin V. Bartenev 292 August 19, 2016 07:16AM

Re: [PATCH] HTTP: add support for trailers in HTTP responses

Maxim Dounin 295 August 23, 2016 11:00AM

Re: [PATCH] HTTP: add support for trailers in HTTP responses

Maxim Dounin 509 August 23, 2016 10:24AM

Re: [PATCH] HTTP: add support for trailers in HTTP responses

Piotr Sikora 963 August 31, 2016 09:32PM



Sorry, you do not have permission to post/reply in this forum.

Online Users

Guests: 169
Record Number of Users: 8 on April 13, 2023
Record Number of Guests: 421 on December 02, 2018
Powered by nginx      Powered by FreeBSD      PHP Powered      Powered by MariaDB      ipv6 ready