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
_______________________________________________
nginx mailing list
nginx@nginx.org
http://mailman.nginx.org/mailman/listinfo/nginx

Reply via email to