Opened 4 years ago

Closed 4 years ago

#2059 closed defect (invalid)

add_header does not work inside if+location, http, or server blocks

Reported by: lance.wordkeeper.com@… Owned by:
Priority: major Milestone:
Component: nginx-core Version: 1.19.x
Keywords: Cc:
uname -a: Linux redacted 5.2.8-1.el7.elrepo.x86_64 #1 SMP Fri Aug 9 13:40:33 EDT 2019 x86_64 x86_64 x86_64 GNU/Linux
nginx -V: nginx version: nginx/1.19.3
built by gcc 8.3.1 20190311 (Red Hat 8.3.1-3) (GCC)
built with OpenSSL 1.1.1h 22 Sep 2020
TLS SNI support enabled
configure arguments: --with-cc-opt='-O0 -g -march=native -flto -funsafe-math-optimizations -fstack-protector --param=ssp-buffer-size=4 -Wformat -Werror=format-security -Wp,-D_FORTIFY_SOURCE=0 -fPIE -Wno-error=strict-aliasing -DTCP_FASTOPEN=23' --with-ld-opt='-Wl,-z,relro -Wl,--as-needed' --with-openssl-opt=enable-tls1_3 --with-openssl-opt=enable-ec_nistp_64_gcc_128 --with-openssl-opt=no-nextprotoneg --with-openssl-opt=no-weak-ssl-ciphers --with-openssl-opt=no-ssl3 --prefix=/usr/share/nginx --without-http_autoindex_module --without-http_ssi_module --conf-path=/opt/wordkeeper/nginx/nginx.conf --http-log-path=/var/log/nginx/access.log --error-log-path=/var/log/nginx/error.log --lock-path=/var/lock/nginx.lock --pid-path=/run/nginx.pid --http-client-body-temp-path=/var/lib/nginx/body --http-fastcgi-temp-path=/var/lib/nginx/fastcgi --http-proxy-temp-path=/var/lib/nginx/proxy --with-debug --with-pcre-jit --with-http_ssl_module --with-http_stub_status_module --with-openssl=/root/openssl-1.1.1h --with-zlib=/root/zlib-1.2.11.1_jtkv6.3 --with-http_realip_module --with-http_auth_request_module --with-http_gzip_static_module --with-http_v2_module --with-http_sub_module --with-libatomic --user=nobody --group=nobody --with-file-aio --with-http_gunzip_module --with-pcre=/root/pcre-8.44 --with-threads --without-http_scgi_module --without-http_uwsgi_module --add-module=/root/ngx_devel_kit-0.3.1 --add-module=/root/lua-nginx-module-0.10.17 --add-module=/root/echo-nginx-module-0.62 --add-module=/root/ngx_brotli --add-module=/root/ngx_http_geoip2_module-3.3

Description

Since at least Nginx 1.19.2, add_header has not been properly responding to its directives inside if blocks in locations, http, or server blocks.

In server blocks, we have defined things like this (paths and site specifics have been redacted)

server {
	listen 80;
	listen [::]:80;
	listen 443 ssl http2;
	listen [::]:443 ssl http2;
	ssl_certificate redacted;
	ssl_certificate_key redacted;

	root redacted;

	# Add index.php to the list if you are using PHP
	index index.html index.htm index.php;

	server_name redacted;

	add_header X-Tester-Value "tester";

This should output a header value of "tester" for X-Tester-Value. But this value is not output.

In location blocks, add_header does work but only if it is directly within the location block and not within an if block.

Here is a sample configuration inside of the / location.

		set $test "0";
		if ($test = "0") {
			add_header X-Test-Value $test;
		}

		set $hsts 1;
		add_header X-HSTS-Value $hsts;

In this configuration, Nginx outputs "X-HSTS-Value: 1" for the X-HSTS-Value header. The X-Test-Value header is not output. Other variations of if block test (e.g. =, ~, ~*, etc) also do not change the result of the add_header output as the test in the if block is not the issue.

These same header configurations also do not appear to work within the HTTP context. As of present, the only place that add_header does seem to be working correctly is inside of the location context and per the manual, it should be working in all of the locations that I have named here.

Due to differences between HTTP2 and HTTP1 in Nginx, we did try disabling HTTP2 within this server block and it did not produce any difference in results.

Change History (1)

comment:1 by Maxim Dounin, 4 years ago

Resolution: invalid
Status: newclosed

Much like any directives in nginx, the add_header directive is only inherited from previous levels if it is not set on the current level. This is explicitly outlined in the documentation:

These directives are inherited from the previous configuration level if and only if there are no add_header directives defined on the current level.

That is, if you want to return some additional headers within a location, and still want the headers defined at the server level to be returned, you have to configure both at the location level, for example:

server {
    listen 8080;

    add_header X-Server-Header test;

    location / {
        add_header X-Server-Header test;
        add_header X-Location-Header test;
    }
}

The same applies to add_header directives in the if blocks: if you use the add_header directive in an if, you have to define all headers to be returned. That is, your example should be instead written in this way to make sure both X-Test-Value and X-HSTS-Value headers will be added:

set $test "0";
if ($test = "0") {
    add_header X-Test-Value $test;
    add_header X-HSTS-Value $hsts;
}

set $hsts 1;
add_header X-HSTS-Value $hsts;

Alternatively, the same configuration can be written in a more readable form by simply using appropriate variable values. Note that an empty value implies that the header will not be added:

set $test "0";
if ($test != "0") {
    set $test "";
}

set $hsts 1;

add_header X-Test-Value $test;
add_header X-HSTS-Value $hsts;

If you have further questions on how to configure nginx, consider using support options available.

Note: See TracTickets for help on using tickets.