From c93a0c48af87bbae1568eaf110e207e435bbe0bd Mon Sep 17 00:00:00 2001 From: Roman Arutyunyan Date: Mon, 14 Jul 2025 21:44:05 +0400 Subject: [PATCH] Headers filter: inheritance control for add_header and add_trailer. The new directives add_header_inherit and add_trailer_inherit allow to alter inheritance rules for the values specified in the add_header and add_trailer directives in a convenient way. The "merge" parameter enables appending the values from the previous level to the current level values. The "off" parameter cancels inheritance of the values from the previous configuration level, similar to add_header "" (2194e75bb). The "on" parameter (default) enables the standard inheritance behaviour, which is to inherit values from the previous level only if there are no directives on the current level. The inheritance rules themselves are inherited in a standard way. Thus, for example, "add_header_inherit merge;" specified at the top level will be inherited in all nested levels recursively unless redefined below. --- .../modules/ngx_http_headers_filter_module.c | 74 ++++++++++++++++++- 1 file changed, 70 insertions(+), 4 deletions(-) diff --git a/src/http/modules/ngx_http_headers_filter_module.c b/src/http/modules/ngx_http_headers_filter_module.c index 90e6da8b3..93177c748 100644 --- a/src/http/modules/ngx_http_headers_filter_module.c +++ b/src/http/modules/ngx_http_headers_filter_module.c @@ -10,6 +10,11 @@ #include +#define NGX_HTTP_HEADERS_INHERIT_OFF 0 +#define NGX_HTTP_HEADERS_INHERIT_ON 1 +#define NGX_HTTP_HEADERS_INHERIT_MERGE 2 + + typedef struct ngx_http_header_val_s ngx_http_header_val_t; typedef ngx_int_t (*ngx_http_set_header_pt)(ngx_http_request_t *r, @@ -49,6 +54,8 @@ typedef struct { ngx_http_complex_value_t *expires_value; ngx_array_t *headers; ngx_array_t *trailers; + ngx_uint_t headers_inherit; + ngx_uint_t trailers_inherit; } ngx_http_headers_conf_t; @@ -97,6 +104,14 @@ static ngx_http_set_header_t ngx_http_set_headers[] = { }; +static ngx_conf_enum_t ngx_http_headers_inherit[] = { + { ngx_string("off"), NGX_HTTP_HEADERS_INHERIT_OFF }, + { ngx_string("on"), NGX_HTTP_HEADERS_INHERIT_ON }, + { ngx_string("merge"), NGX_HTTP_HEADERS_INHERIT_MERGE }, + { ngx_null_string, 0 } +}; + + static ngx_command_t ngx_http_headers_filter_commands[] = { { ngx_string("expires"), @@ -123,6 +138,22 @@ static ngx_command_t ngx_http_headers_filter_commands[] = { offsetof(ngx_http_headers_conf_t, trailers), NULL }, + { ngx_string("add_header_inherit"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF + |NGX_CONF_TAKE1, + ngx_conf_set_enum_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_headers_conf_t, headers_inherit), + &ngx_http_headers_inherit }, + + { ngx_string("add_trailer_inherit"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF + |NGX_CONF_TAKE1, + ngx_conf_set_enum_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_headers_conf_t, trailers_inherit), + &ngx_http_headers_inherit }, + ngx_null_command }; @@ -657,6 +688,8 @@ ngx_http_headers_create_conf(ngx_conf_t *cf) */ conf->expires = NGX_HTTP_EXPIRES_UNSET; + conf->headers_inherit = NGX_CONF_UNSET; + conf->trailers_inherit = NGX_CONF_UNSET; return conf; } @@ -668,6 +701,8 @@ ngx_http_headers_merge_conf(ngx_conf_t *cf, void *parent, void *child) ngx_http_headers_conf_t *prev = parent; ngx_http_headers_conf_t *conf = child; + ngx_http_header_val_t *hv; + if (conf->expires == NGX_HTTP_EXPIRES_UNSET) { conf->expires = prev->expires; conf->expires_time = prev->expires_time; @@ -678,12 +713,43 @@ ngx_http_headers_merge_conf(ngx_conf_t *cf, void *parent, void *child) } } - if (conf->headers == NULL) { - conf->headers = prev->headers; + ngx_conf_merge_uint_value(conf->headers_inherit, prev->headers_inherit, + NGX_HTTP_HEADERS_INHERIT_ON); + ngx_conf_merge_uint_value(conf->trailers_inherit, prev->trailers_inherit, + NGX_HTTP_HEADERS_INHERIT_ON); + + if (conf->headers_inherit != NGX_HTTP_HEADERS_INHERIT_OFF + && prev->headers) + { + if (conf->headers == NULL) { + conf->headers = prev->headers; + + } else if (conf->headers_inherit == NGX_HTTP_HEADERS_INHERIT_MERGE) { + hv = ngx_array_push_n(conf->headers, prev->headers->nelts); + if (hv == NULL) { + return NGX_CONF_ERROR; + } + + ngx_memcpy(hv, prev->headers->elts, + sizeof(ngx_http_header_val_t) * prev->headers->nelts); + } } - if (conf->trailers == NULL) { - conf->trailers = prev->trailers; + if (conf->trailers_inherit != NGX_HTTP_HEADERS_INHERIT_OFF + && prev->trailers) + { + if (conf->trailers == NULL) { + conf->trailers = prev->trailers; + + } else if (conf->trailers_inherit == NGX_HTTP_HEADERS_INHERIT_MERGE) { + hv = ngx_array_push_n(conf->trailers, prev->trailers->nelts); + if (hv == NULL) { + return NGX_CONF_ERROR; + } + + ngx_memcpy(hv, prev->trailers->elts, + sizeof(ngx_http_header_val_t) * prev->trailers->nelts); + } } return NGX_CONF_OK;