rewrite and map ??interfering regexps

Norman Gray gray at nxg.name
Sun Apr 26 12:49:19 UTC 2020


Greetings.

I'm trying to do some fairly intricate URI rewriting, and the behaviour 
of the 'rewrite' statement does not correspond to anything I can explain 
from the docs.

The goal is that /A/foo/modified is rewritten to /_newroot/foo and 
/B/foo/modified to /_defaultroot/foo.  I hope to achieve this with

     map $uri $modroot {
         default _defaultroot;
         ~^/A _newroot;
     }

and

     location ~ /modified$ {
         rewrite ^(.+)/modified$ /$modroot/-$1-;
     }

(in the real config, /_newroot is reverse-proxied to a web service, so 
that the URIs it handles end up grafted on to selected trees; the 'map' 
is intended to select/limit which URIs are passed on to this service).

The complete nginx.conf is at the bottom.

Looking in the error log, when I retrieve /hello/modified I find

2020/04/26 12:23:28 [notice] 63328#0: *5 "^(.+)/modified$" matches 
"/hello/modified", client: 127.0.0.1, server: localhost, request: "GET 
/hello/modified HTTP/1.1", host: "localhost"
2020/04/26 12:23:28 [notice] 63328#0: *5 rewritten data: 
"/_defaultroot/-/hello-", args: "", client: 127.0.0.1, server: 
localhost, request: "GET /hello/modified HTTP/1.1", host: "localhost"

...which is fine: the map defines $modroot as /_defaultroot, and the 
rewrite captures the /hello.

But retrieving /A/hello/modified,

2020/04/26 13:00:51 [notice] 63828#0: *6 "^(.+)/modified$" matches 
"/A/hello/modified", client: 127.0.0.1, server: localhost, request: "GET 
/A/hello/modified HTTP/1.1", host: "localhost"
2020/04/26 13:00:51 [notice] 63828#0: *6 rewritten data: "/_newroot/--", 
args: "", client: 127.0.0.1, server: localhost, request: "GET 
/A/hello/modified HTTP/1.1", host: "localhost"

I would expect this to be rewritten to /_newroot/-/A/hello-

Here, the map has defined $modroot as /_newroot (which is correct).  The 
'rewrite' _has_ matched, but the $1 in that line appears to be empty.  
Note the '+' in the regexp: there is supposed be be a string of non-zero 
length in there (ie, this is ruling out that I'm inadvertently matching, 
and replacing, an empty string, as a result of being somehow confused 
about where in the string '^' is matching).

It's as if the regexp match in the 'map' is somehow interfering with the 
group-capturing in the 'rewrite'.

As a workaround, I can get this to work with ^(?<newprefix>/A) in the 
'map', and using $newprefix in the 'rewrite', but that's fiddly/ugly and 
more confusing than localising the rewriting to the 'rewrite' statement.

Am I misunderstanding how 'rewrite' matches things, or is there an issue 
here?

Best wishes,

Norman






% ../sbin/nginx -V
nginx version: nginx/1.18.0
built by clang 11.0.3 (clang-1103.0.32.29)
configure arguments: --prefix=/Data/tools/nginx-1.18 
--with-pcre=../pcre-8.44

Both nginx and pcre built, as shown, from source.

This is on macOS 10.15.3, but I get the same results with (packaged) 
nginx/1.16.1 on FreeBSD 12.1


Complete nginx.conf:

worker_processes  1;

events {
     worker_connections  1024;
}


http {
     include       mime.types;
     default_type  application/octet-stream;

     error_log logs/error.log debug;
     rewrite_log on;

     sendfile        on;
     keepalive_timeout  65;

     # selected URIs are dynamically 'rehomed'
     map $uri $modroot {
         default _defaultroot;
         ~^/A _newroot;
     }

     server {
         listen       80;
         server_name  localhost;

         location / {
             root   html;
             index  index.html index.htm;
         }
         location ~ /modified$ {
             rewrite ^(.+)/modified$ /$modroot/-$1-;
         }
         location /_defaultroot { # not a 'rehomed' one
             internal;
             error_page 404 /404-private.html;
         }
         location /_newroot {
             internal;
             root html/x;
         }

         error_page   500 502 503 504  /50x.html;
         location = /50x.html {
             root   html;
         }
     }
}


-- 
Norman Gray  :  https://nxg.me.uk


More information about the nginx mailing list