Add_header is not working in certain locations

Hi all, I’ve got strange behavior that I don’t understand in two
different
configs. I’ll post examples below, in both of them I use add_header two
times and one of them is not working while second does.

Example 1:
Request is: http://hostname/?region=XX

#This location adds header, so it’s frankly the only reason I use it in
my
config. If I set location to “~ .*”, I’ll get header set also.
location = / {
if ($arg_region) {
add_header Set-Cookie “geoip_country=$arg_region;Path=/”;
}
proxy_pass http://backend;
}
#If I remove the exact match above, I’ll not get header set. Even if
it’s
the only location in whole config and all site is working from there for
sure.
location / {
if ($arg_region) { add_header Set-Cookie
geoip_country=$arg_region; path=/” ;}
proxy_pass http://backend;
}

Example 2:
Request is the same and this chain of locations is recommended by drupal
community.
location / {
#Does not work
if ($arg_region) { add_header Set-Cookie
geoip_country=$arg_region;Path=/”; }
try_files $uri @rewrite;
}

    location @rewrite {
            rewrite ^ /index.php;
    }


    location ~ \.php$ {

#This works
if ($arg_region) { add_header Set-Cookie
geoip_country=$arg_region;Path=/”; }

fastcgi_intercept_errors on;
fastcgi_pass fpm-backend;
}

Posted at Nginx Forum:

On Wed, Aug 13, 2014 at 02:28:27AM -0400, bodomic wrote:

Hi there,

Hi all, I’ve got strange behavior that I don’t understand in two different
configs. I’ll post examples below, in both of them I use add_header two
times and one of them is not working while second does.

Example 1:
Request is: http://hostname/?region=XX

In this case, for location matching the request is “/”, so the
best-match
location for that will be used.

sure.
location / {
if ($arg_region) { add_header Set-Cookie
geoip_country=$arg_region; path=/” ;}
proxy_pass http://backend;
}

It works for me.

In this case, I do get the Set-Cookie header when I have either one of
the two location{} blocks as the only location{} in the configuration. I
think you say that you do not get the Set-Cookie header in the second
case – can you provide a complete, small, config that shows that?

Example 2:
Request is the same and this chain of locations is recommended by drupal
community.

For these ones, I’m not sure how to set up a simple test.

Note, though, that you are using “if” inside “location”. Generally, it
is
not wise to do that unless you understand exactly what your
configuration
actually means.

If is Evil… when used in location context | NGINX for details.

Is there a link to this drupal recommendation? It isn’t obvious to
me from the first few results for “nginx site:drupal.org” or “drupal
site:nginx.org”

    location / {

#Does not work
if ($arg_region) { add_header Set-Cookie
geoip_country=$arg_region;Path=/”; }
try_files $uri @rewrite;
}

That one seems to be “# try_files wont work due to if” on the IfIsEvil
page.

Cheers,

f

Francis D. [email protected]

Hi Francis,

Thanks for your thoughtful entry. It seems that it is a cloudy area of
buggy
‘if’ behaviors :slight_smile:
I’ve created empty host config with just ‘location /’ and ‘if …
add_header’ and proxy_pass - and it works fine.
I’ll have to retest this situation on my real server though to find out
if
my ‘issue’ is gone.

As for the second case - yes, it looks like the whole set of
If is Evil… when used in location context | NGINX so I think that’s the case of
buggy
behavior too.
I’ll try the ‘What to do instead’ section. But, funny to notice, in my
case
try_files does work, while ‘if’ does not in the same location.

Config of Nginx for Drupal is here: Drupal | NGINX
I’m using it literally from there, just trying to add a buggy ‘if’ here
and
there.

Posted at Nginx Forum:

Thanks for your reply, I’ve actually found the second traitor (i.e. why
second example won’t work), will reply to Francis’s post once more.

Posted at Nginx Forum:

Actually, the second problem is described in this document too, I think
I
should re-read it every time I want to use IF.
In my example (before posting it here) I’ve dropped the second IF in the
same location without much thought.
That’s why it worked for you. That’s why it worked in a separate
location -
I didn’t move a second IF there, and again, did not pay enough attention
to
that.

So, the problem was the second IF in the same location. This is really
not
an easy thing to understand, so it should be the sole recommendation of
denying IFs on the top of rewrite module documentation :slight_smile:

Francis D. Wrote:

If is Evil… when used in location context | NGINX for details.


nginx mailing list
[email protected]
nginx Info Page

Posted at Nginx Forum:

Adding a few notes:
IF should only be used to return a state, ea. if … ‘error_page’ and
nothing else because it breaks the chain of processing, when you really
need
IF’s, nested, setting values or otherwise use Lua.
For example: Re: Strange try_files behaviour

The problem lays in event processing, while events are processed a
single IF
won’t do much harm (if ever) but additional IF’s can cause strange
things,

Event1 → EP1 → EP2 → IF1 → goto EP3 or EP4 → IF2 (refers to the
stage
between EP1 and EP2) so you are passed EP2 already when another IF is
thrown
in, this may result in a loopback to EP2 which may end up at EP3 while
your
IF1 wanted to go to EP4. Or IF2 processing produced a result which
overwrites the result of IF1.

Posted at Nginx Forum:

On Thu, Aug 14, 2014 at 10:16:43AM -0400, bodomic wrote:

Hi there,

Actually, the second problem is described in this document too, I think I
should re-read it every time I want to use IF.

“if” is fine.

It is only “if inside location” which needs care.

My general guideline is:

do “return …”; or
do “rewrite … last”; or
don’t do it without understanding it.

In my example (before posting it here) I’ve dropped the second IF in the
same location without much thought.
That’s why it worked for you. That’s why it worked in a separate location -
I didn’t move a second IF there, and again, did not pay enough attention to
that.

Ah, right. Yes, it is always best to create a scratch system with a
small config that reliably shows the problem you encounter (and which
contains no private information), and then copy-paste exactly what is
in the scratch system.

That way, everyone testing things is looking at the same thing.

(And the “nginx -V” output can be useful too, in case there are version
or compile-time differences which matter.)

So, the problem was the second IF in the same location.

I’d say that the problem was using “if” inside “location” without
understanding the nginx quirks.

Two or three "if"s might have been ok. One might have caused things not
to work as you wanted.

f

Francis D. [email protected]