After trying literally 10 different things and consulting with Fenn Bailey of http://fennb.com, I have to resort to the include solution, which seems to be the only thing that avoids code duplication and actually works.
I moved all directives from location / {} into their own file and did this:
location / {
include /etc/nginx/vhosts/androidpolice-root.conf;
}
location ~* wpsf-(img|js)\.php {
include /etc/nginx/vhosts/androidpolice-root.conf;
proxy_ignore_headers "Set-Cookie" "Cache-Control";
}
At this point I'm quite shocked by nginx's inflexibility when it comes to ifs and conditionals - these things should be so trivial, yet they're not.
By the way, I'm on the latest nginx 1.1.17.
With nginx/1.2.1
, I wasn't able to reproduce your issue of %20
, once decoded into a space, of causing any 400 Bad Request
within nginx; perhaps that's coming from upstream?
Regardless, it is actually not that difficult to use the finite-state automaton that is provided through the rewrite
directive to stop $uri
from containing the decoded request, yet still perform all sorts of transformations of the request.
https://stackoverflow.com/questions/28684300/nginx-pass-proxy-subdirectory-without-url-decoding/37584637#37584637
The idea is that when you change $uri
in place, it doesn't get re-decoded. And, as you know, we do already have the undecoded one in $request_uri
. What's left is to simply set one to the other, and call it a day.
server {
listen 2012;
location /a {
rewrite ^/a(.*) /f$1 last;
}
location /i {
rewrite ^ $request_uri;
rewrite ^/i(.*) /f$1 last;
return 400; #if the second rewrite won't match
}
location /f {
set $url http://127.0.0.1:2016/s?v=h&a=$scheme://$host$uri;
proxy_pass $url;
}
}
server {
listen 2016;
return 200 $request_uri\n;
}
And, yes, the rewrite ^ $request_uri;
part above does do the trick:
% echo localhost:2012/{a,i,f}/h%20w | xargs -n1 curl
/s?v=h&a=http://localhost/f/h w
/s?v=h&a=http://localhost/f/h%20w
/s?v=h&a=http://localhost/f/h w
%
(If you want the "direct" thing to not be decoded, either, then it'll probably be easiest to just make it an "indirect" as well.)
Best Answer
When nginx documentation does not explicitly says that you can use variables for some directive parameter, generally it means you cannot. In particular you can't use variables as the header names in
add_header
,proxy_set_header
and some other related directives. However you can do it using third party modules, e.g.lua-nginx-module
viangx.req.set_header
. You can take a look at the OpenResty bundle which includes aforementioned module and is being packaged for a wide range of OS distributions.