2

I face a strange issue with Nginx. This is a minimal config that reproduce the error:

server {
    server_name     mydomain.com;
    listen          111.111.111.111:80;
    root            /some/path;

    set     $some_var   $sent_http_content_type;
    add_header  "X-Debug" $sent_http_content_type;
}

In this case X-Debug header is never shown in the response. But, if I comment this line:

set     $some_var   $sent_http_content_type;

everything works. It seems very strange to me because this line doesn't reassign the $sent_http_content_type var, but only reads.

It looks like it belongs to $sent_http_ variables only.

I also tried "${sent_http_content_type}" instead of $sent_http_content_type with the same result.

more_set_headers directive doesn't fix this.

Why does Nginx behave like this? Is this a bug?

Edit:
The example I have provided is just the simpest case where $sent_http_ vars desappear. In fact I want to do something like this:

if ($sent_http_access_control_allow_origin ~ "^(https?)://([^/]+)") {
    set $new_cors http://$1.$2.proxy.mydomain.com;
}
more_set_headers "Access-Control-Allow-Origin: $new_cors";

I write a proxy server and I need to replace Access-Control-Allow-Origin response header, because otherwise proxied sites don't work as expected.

In the above example if condition (in server section) never yields true, even if there is such header and it fits my regular expression.

Can this be fixed? Appreciate your help!

Oleg
  • 276
  • 4
  • 18

1 Answers1

2

Nginx's rewrite module (where variables and set directive belongs) is quite non-intuitive and fragile. But, actually

set     $some_var   $sent_http_content_type;

is meaningless anyway because set directive is executed at the beginning of request and there is no $sent_http_* variables available at the moment.

What you could do (if you really want to use $sent_http_* variables somehow) is to use map directive.

map $sent_http_content_type $some_var {
    default $sent_http_content_type;
}

...
server {
    ...
    add_header "X-Debug"  $sent_http_content_type;
    add_header "X-Debug2" $some_var;
}

EDIT: Your problem could be solved with some more maps, but it would be a lot easier if you could use Lua module.

Here how it could be done with maps: (quite unreadable and unmaintainable)

map $sent_http_access_control_allow_origin $__proto {
    default "NONE";
    "~^(?<_>https?):" "$_";
}

map $sent_http_access_control_allow_origin $__host {
    default "";
    "~^https?://(?<_>[^/]+)" "$_";
}

map "http://$__proto.$__host.proxy.mydomain.com" $new_cors {
    default "";
    "~^http://NONE" "";
    "~^(?<_>.+)$" "$_";
}
Alexey Ten
  • 8,435
  • 1
  • 34
  • 36
  • +1 Thank you for the explanation! However `map` directive doesn't solve my real issue. Please see my edit. Is it possible to achieve what I want? Appreciate your help. – Oleg Mar 01 '16 at 08:15
  • Your last `map` solution is a bit twisted but it **does work**. Thanks again, @AlexeyTen! – Oleg Mar 01 '16 at 10:18