Other headers disappear after adding Set-Cookie header

Hi,

I have the following problem.

In a configuration with several locations, I am using
add_header Set-Cookie “name=value; domain=xyz.com; path=/”;
and some other headers, like
add_header X-Info “Some information”

When the Set-Cookie header is added, all additional headers suddenly
disappear. When the Set-Cookie add_header call is disabled, the
additional headers appear as normal.

First I thought it might be a bug, but this behavior doesn’t occur when
I put this combination of headers in another location in another
(simpler) server block. I also upgraded from 0.7.67 to 0.8.49 to see if
that would make a difference, but it still happens.

Apparently there is something that drops the additional headers, but I
have no idea what. I have disabled all other locations, disabled all
other things (like expires), but without any effect.

The server block in which this happens is build up as follows:

  • Capture of a variable from the URL;
  • Rewrite of certain URLs to a static HTML page;
  • Location to serve the static HTML pages, which includes the add_header
    call for Set-Cookie, to pass on the value from the captured variable in
    a cookie;
  • Location to serve other static content (css, images, etc);
  • Location to proxy to apache.

I hope someone knows why this happens, and if it should be considered a
bug or not.

Thanks,

Raymond

Posted at Nginx Forum:
http://forum.nginx.org/read.php?2,120295,120295#msg-120295

Hello!

On Mon, Aug 16, 2010 at 07:57:51AM -0400, Unimatrix02 wrote:

disappear. When the Set-Cookie add_header call is disabled, the

bug or not.
Please show:

  1. Exact config which exposes the problem.

  2. nginx -V output

  3. Debug log.

See http://wiki.nginx.org/NginxDebugging for details.

Maxim D.

Hi Maxim,

Thanks for your reply. I hereby provide the requested details.

nginx -v output
nginx version: nginx/0.8.49
built by gcc 4.1.2 20080704 (Red Hat 4.1.2-48)
TLS SNI support disabled
configure arguments: --user=nginx --group=nginx
–prefix=/usr/share/nginx --sbin-path=/usr/sbin/nginx
–conf-path=/etc/nginx/nginx.conf
–error-log-path=/var/log/nginx/error.log
–http-log-path=/var/log/nginx/access.log
–http-client-body-temp-path=/var/lib/nginx/tmp/client_body
–http-proxy-temp-path=/var/lib/nginx/tmp/proxy
–http-fastcgi-temp-path=/var/lib/nginx/tmp/fastcgi
–pid-path=/var/run/nginx.pid --lock-path=/var/lock/subsys/nginx
–with-http_secure_link_module --with-http_random_index_module
–with-http_ssl_module --with-http_realip_module
–with-http_addition_module --with-http_sub_module
–with-http_dav_module --with-http_flv_module
–with-http_gzip_static_module --with-http_stub_status_module
–with-http_perl_module --with-mail --with-mail_ssl_module
–with-cc-opt=’-O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions
-fstack-protector --param=ssp-buffer-size=4 -m64 -mtune=generic’
–with-ipv6
–add-module=/builddir/build/BUILD/nginx-0.8.49/nginx-upstream-fair
–add-module=/builddir/build/BUILD/nginx-0.8.49/nginx-upload-progress-module
–add-module=/builddir/build/BUILD/nginx-0.8.49/mod_zip-1.1.5
–add-module=/builddir/build/BUILD/nginx-0.8.49/nginx_upload_module-2.0.12
–add-module=/builddir/build/BUILD/nginx-0.8.49/nginx_mod_h264_streaming-2.2.7

nginx.conf
user nginx;

worker_processes 2;
worker_cpu_affinity 0001 0010;

error_log /var/log/nginx/error.log debug;
pid /var/run/nginx.pid;

events {
worker_connections 8192;
use epoll;
}

http {
server_names_hash_bucket_size 64;
include /etc/nginx/ibood-mime.types;
include /etc/nginx/conf.d/*.conf;
default_type application/octet-stream;

log_format common '$http_X_Cluster_Client_IP - $remote_user
[$time_local] “$request” ’
'$status $body_bytes_sent “$http_referer” ’
‘"$http_user_agent" “$http_x_forwarded_for”’;

log_format main '$remote_addr $proxy_add_x_forwarded_for $remote_user
[$time_local] $request ’
'"$status" $body_bytes_sent “$http_referer” ’
‘"$http_user_agent" “$http_x_forwarded_for”
“$http_x_cluster_client_ip”’;

log_format  details  '$http_X_Cluster_Client_IP $remote_user

[$time_local] $request ’
'"$status" $body_bytes_sent $bytes_sent
$connection “$pipe” ’
'$msec $request_time $request_length ’
'"$http_referer" ’
‘"$http_user_agent" “$http_x_forwarded_for”’;
access_log /var/log/nginx/access.log common;
sendfile on;
tcp_nopush on;
keepalive_timeout 15;

gzip off;

— Virtual hosts —

[ irrelevant vhosts cut out ]

The default server

server
{
listen 80 default backlog=1024;
server_name _;
server_name_in_redirect off;

# Look for affiliate in URI
set $aff_id "";
if ($request_uri ~* "(affiliate,|affiliate=)([a-z0-9]*)")
{
  set $aff_id $2;
}

# Redirect old NL variants to main NL variant
rewrite ^/(depers|ad|iex|nu)/nl(.*)$ /nl/nl$2 permanent;

# Redirect banners to ext
rewrite ^/(banners/.*)$ http://ext.ibood.com/$1 permanent;

# Redirect feed requests to ext.ibood.com
rewrite ^/feeds/ibood_([^_/]+)_([^_/]+)\.xml$

http://feeds.ibood.com/ibood/$1_$2 permanent;

# Redirect all traffic on /feeds to ext.ibood.com
rewrite ^/feeds/(.*)$ http://ext.ibood.com/$1 permanent;

rewrite ^(/cms/.*)$ $1 break;

# Static content ----
rewrite ^([^\.]*)/imgdesign/([^\.]*)\.([^\.]*)$ 

/main/imgdesign/$2.$3
last;
rewrite ^([^.])/style/(.).css$ /main/style/$2.css last;
rewrite ^([^.])/js/(.).js$ /main/js/$2.js last;
rewrite ^/img/(.).(swf|js|ico|gif|jpg|JPG|png|css)$ /img/$1.$2
last;
rewrite ^/templates_dynamic/(.
).(js|ico|gif|jpg|JPG|png|css)$
/templates_dynamic/$1.$2 last;

# Remove trailing slash from .html URIs
rewrite ^(.+)\.html/?$ $1.html last;

# Rewrite for affiliate handling
#if ($request_uri ~

“^/(pl/pl|nl/nl|de/de|uk/en|be/nl|ie/en|bild/de).(affiliate,|affiliate=).”)
#{
# rewrite ^.*$ /handle_affiliate.php last;
#}

# Serve static pages -----

# Only if not containing "affiliate"
#if ($request_uri !~ "(affiliate=|affiliate,)" )
#{
  rewrite

^/(pl/pl|nl/nl|de/de|uk/en|be/nl|ie/en|bild/de)/(product_specs/.)$
/static/generated/$1/$2 last;
rewrite ^/(pl/pl|nl/nl|de/de|uk/en|be/nl|ie/en|bild/de)(/?)$
/static/generated/$1/index.html last;
rewrite ^/(pl/pl|nl/nl|de/de|uk/en|be/nl|ie/en|bild/de)/index.

/static/generated/$1/index.html last;
#}

# Redirect to splash page if request uri is still /
rewrite ^/$ /index.html last;

# ----

# Serve generated HTML files directly, but expire immediately
location ~ /static/generated/.*\.html$
{
  # Set cookie with affiliate ID, if present
  if ($aff_id != "")
  {
    add_header  Set-Cookie  "iboodaffiliates=$aff_id; path=/;

domain=.ibood.com;";
}

  add_header  X-DebugInfo    aff_id=$aff_id;
  add_header  X-Info  "Served by nginx 1:$uri";

  root    /var/www/html;
  expires    -1h;
}

# Serve static files directly
location ~* \.(jpg|jpeg|gif|css|png|js|ico|xml|swf|pdf|doc|cur)$
{
  root    /var/www/html;
  access_log  off;
  # expires    30d;
  expires    12h;
  add_header  X-Info  "Served by nginx 2:$uri";
}

# Serve generated static pages
location /static/generated
{
  add_header  X-DebugInfo    aff_id=$aff_id;

  # Set cookie with affiliate ID, if present
  if ($aff_id != "")
  {
    #add_header  Set-Cookie  "testcookie=$aff_id; path=/;";
  }
  root    /var/www/html;
  access_log  off;
  expires    12h;
  add_header  X-Info  "Served by nginx 3:$uri";
}

# Set default languages
#rewrite ^/pl/?$    /pl/pl/    permanent;
#rewrite ^/nl/?$    /nl/nl/    permanent;
#rewrite ^/de/?$    /de/de/    permanent;
#rewrite ^/uk/?$    /uk/en/    permanent;
#rewrite ^/be/?$    /be/nl/    permanent;
#rewrite ^/ie/?$    /ie/en/    permanent;

#rewrite ^/$ /index.html last;
#rewrite ^(/cms/.*)$ $1 break;

# Pass calls to API client through without rewrites
#rewrite ^(/ac/.*)$ $1 break;

# Don't rewrite request to affiliate handler
#rewrite ^(/handle_affiliate.php) $1 break;

# Send everything to front controller
#rewrite ^.*$ /main/frontend.php break;

location /
{
  add_header  X-Info  "Served by apache";

  proxy_set_header   Host          $host;
  proxy_set_header   X-Cluster-Client-IP  $remote_addr;
  proxy_set_header   X-Forwarded-For    $proxy_add_x_forwarded_for;
  proxy_set_header   X-Request-URI      $request_uri;

  proxy_pass       http://127.0.0.1:8080;
  proxy_redirect     off;
}

error_page  404      /main/404.php;

}
}

debug log
2010/08/16 15:12:22 [notice] 24579#0: 1
"(affiliate,|affiliate=)([a-z0-9]
)" matches
“/nl/nl/index/affiliate,Affilinet/”, client: 192.168.32.50, server: ,
request: “GET /nl/nl/index/affiliate,Affilinet/ HTTP/1.1”, host:
r.dev.ibood.com
2010/08/16 15:12:22 [notice] 24579#0: 1 "^/(depers|ad|iex|nu)/nl(.)$"
does not match “/nl/nl/index/affiliate,Affilinet/”, client:
192.168.32.50, server: , request: “GET
/nl/nl/index/affiliate,Affilinet/ HTTP/1.1”, host: “r.dev.ibood.com
2010/08/16 15:12:22 [notice] 24579#0: 1 "^/(banners/.)$" does not
match “/nl/nl/index/affiliate,Affilinet/”, client: 192.168.32.50,
server: , request: “GET /nl/nl/index/affiliate,Affilinet/ HTTP/1.1”,
host: “r.dev.ibood.com
2010/08/16 15:12:22 [notice] 24579#0: *1
"^/feeds/ibood
([^
/]+)
([^_/]+).xml$" does not match
“/nl/nl/index/affiliate,Affilinet/”, client: 192.168.32.50, server: _,
request: “GET /nl/nl/index/affiliate,Affilinet/ HTTP/1.1”, host:
r.dev.ibood.com
2010/08/16 15:12:22 [notice] 24579#0: 1 "^/feeds/(.)$" does not match
“/nl/nl/index/affiliate,Affilinet/”, client: 192.168.32.50, server: _,
request: “GET /nl/nl/index/affiliate,Affilinet/ HTTP/1.1”, host:
r.dev.ibood.com
2010/08/16 15:12:22 [notice] 24579#0: 1 "^(/cms/.)$" does not match
“/nl/nl/index/affiliate,Affilinet/”, client: 192.168.32.50, server: _,
request: “GET /nl/nl/index/affiliate,Affilinet/ HTTP/1.1”, host:
r.dev.ibood.com
2010/08/16 15:12:22 [notice] 24579#0: 1
"^([^.]
)/imgdesign/([^.]).([^.])$" does not match
“/nl/nl/index/affiliate,Affilinet/”, client: 192.168.32.50, server: _,
request: “GET /nl/nl/index/affiliate,Affilinet/ HTTP/1.1”, host:
r.dev.ibood.com
2010/08/16 15:12:22 [notice] 24579#0: 1 "^([^.])/style/(.).css$"
does not match “/nl/nl/index/affiliate,Affilinet/”, client:
192.168.32.50, server: _, request: “GET
/nl/nl/index/affiliate,Affilinet/ HTTP/1.1”, host: “r.dev.ibood.com
2010/08/16 15:12:22 [notice] 24579#0: 1 "^([^.])/js/(.
).js$" does
not match “/nl/nl/index/affiliate,Affilinet/”, client: 192.168.32.50,
server: _, request: “GET /nl/nl/index/affiliate,Affilinet/ HTTP/1.1”,
host: “r.dev.ibood.com
2010/08/16 15:12:22 [notice] 24579#0: 1
"^/img/(.
).(swf|js|ico|gif|jpg|JPG|png|css)$" does not match
“/nl/nl/index/affiliate,Affilinet/”, client: 192.168.32.50, server: _,
request: “GET /nl/nl/index/affiliate,Affilinet/ HTTP/1.1”, host:
r.dev.ibood.com
2010/08/16 15:12:22 [notice] 24579#0: 1
"^/templates_dynamic/(.
).(js|ico|gif|jpg|JPG|png|css)$" does not match
“/nl/nl/index/affiliate,Affilinet/”, client: 192.168.32.50, server: _,
request: “GET /nl/nl/index/affiliate,Affilinet/ HTTP/1.1”, host:
r.dev.ibood.com
2010/08/16 15:12:22 [notice] 24579#0: *1 “^(.+).html/?$” does not match
“/nl/nl/index/affiliate,Affilinet/”, client: 192.168.32.50, server: _,
request: “GET /nl/nl/index/affiliate,Affilinet/ HTTP/1.1”, host:
r.dev.ibood.com
2010/08/16 15:12:22 [notice] 24579#0: 1
"^/(pl/pl|nl/nl|de/de|uk/en|be/nl|ie/en|bild/de)/(product_specs/.
)$"
does not match “/nl/nl/index/affiliate,Affilinet/”, client:
192.168.32.50, server: _, request: “GET
/nl/nl/index/affiliate,Affilinet/ HTTP/1.1”, host: “r.dev.ibood.com
2010/08/16 15:12:22 [notice] 24579#0: *1
“^/(pl/pl|nl/nl|de/de|uk/en|be/nl|ie/en|bild/de)(/?)$” does not match
“/nl/nl/index/affiliate,Affilinet/”, client: 192.168.32.50, server: _,
request: “GET /nl/nl/index/affiliate,Affilinet/ HTTP/1.1”, host:
r.dev.ibood.com
2010/08/16 15:12:22 [notice] 24579#0: 1
"^/(pl/pl|nl/nl|de/de|uk/en|be/nl|ie/en|bild/de)/index.
" matches
“/nl/nl/index/affiliate,Affilinet/”, client: 192.168.32.50, server: _,
request: “GET /nl/nl/index/affiliate,Affilinet/ HTTP/1.1”, host:
r.dev.ibood.com
2010/08/16 15:12:22 [notice] 24579#0: *1 rewritten data:
“/static/generated/nl/nl/index.html”, args: “”, client: 192.168.32.50,
server: _, request: “GET /nl/nl/index/affiliate,Affilinet/ HTTP/1.1”,
host: “r.dev.ibood.com

I hope this helps to figure it out. My idea is that it has something to
do with the placement of the add_header call in a specific location
block but I haven’t been able to reproduce this problem with a simpler
server block.

Posted at Nginx Forum:
http://forum.nginx.org/read.php?2,120295,120324#msg-120324

Ah, that explains it. Thank you very much.

Posted at Nginx Forum:
http://forum.nginx.org/read.php?2,120295,120348#msg-120348

Hello!

On Mon, Aug 16, 2010 at 09:22:07AM -0400, Unimatrix02 wrote:

[…]

  add_header  X-DebugInfo    aff_id=$aff_id;
  add_header  X-Info  "Served by nginx 1:$uri";

This code defines two locations. One of them has add_header array
set to “X-DebugInfo, X-Info” and another one (implicitly defined
by “if”) has it redefined to “Set-Cookie”.

You have to duplicate other add_header directives within implicit
location defined by “if”, i.e.

location ... {
    add_header X-DebugInfo ...
    add_header X-Info ...

    if (...) {
        add_header Set-Cookie ...
        add_header X-DebugInfo ...
        add_header X-Info ...
    }
}

Further reading:

http://wiki.nginx.org/IfIsEvil

[…]

debug log
2010/08/16 15:12:22 [notice] 24579#0: 1
"(affiliate,|affiliate=)([a-z0-9]
)" matches
“/nl/nl/index/affiliate,Affilinet/”, client: 192.168.32.50, server: _,
request: “GET /nl/nl/index/affiliate,Affilinet/ HTTP/1.1”, host:
r.dev.ibood.com

This isn’t a debug log as you haven’t recompiled nginx with
–with-debug option. Doesn’t matter though, problem is clear from
the config itself.

Maxim D.