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!

5
  • if directive also executed too early for you purpose.
    – Alexey Ten
    Commented Mar 1, 2016 at 8:22
  • @AlexeyTen does this mean that it's impossible to replace response header with regex?
    – Oleg
    Commented Mar 1, 2016 at 8:24
  • It's possible. I'll edit answer
    – Alexey Ten
    Commented Mar 1, 2016 at 8:24
  • It would be a lot easier to use Lua module for example. Also, probably you should use $upstream_http_* variables.
    – Alexey Ten
    Commented Mar 1, 2016 at 8:46
  • I've updated answer
    – Alexey Ten
    Commented Mar 1, 2016 at 8:50

1 Answer 1

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" "";
    "~^(?<_>.+)$" "$_";
}
2
  • +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
    Commented Mar 1, 2016 at 8:15
  • Your last map solution is a bit twisted but it does work. Thanks again, @AlexeyTen!
    – Oleg
    Commented Mar 1, 2016 at 10:18

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .