Bad side effect of (even unmatched) nested regex locations in regex locations with anonymous captures with try_files/alias

Christoph Schug chris+nginx at schug.net
Thu Aug 2 08:38:15 UTC 2012


Hello!

I have another interesting scenario ;-) Given is following minimized 
test case

server {
     listen                          80;
     server_name                     t2.example.com;

     root                            /data/web/t2.example.com/htdoc;

     location                        ~ ^/bar(/.*)? {
         alias                       
/data/web/t2.example.com/htdoc/foo$1;
         try_files                   '' =404;
     }

     location                        ~ ^/bla(/.*)? {
         alias                       
/data/web/t2.example.com/htdoc/foo$1;
         try_files                   '' =404;

         location                    ~ child_of_bla(?P<x>.*)$ {
             return                  418;
         }
     }
}

on Nginx 1.3.4 (but not specific to that version)

# nginx -V
nginx version: nginx/1.3.4
TLS SNI support enabled
configure arguments: --prefix=/usr/share/nginx 
--conf-path=/etc/nginx/nginx.conf --sbin-path=/usr/sbin/nginx 
--http-log-path=/var/log/nginx/access.log 
--error-log-path=/var/log/nginx/error.log --pid-path=/var/run/nginx.pid 
--user=nginx --group=nginx --with-openssl=openssl-1.0.1c --with-debug 
--with-http_stub_status_module --with-http_ssl_module --with-ipv6

and follow file system layout

$ find /data/web/t2.example.com/htdoc/
/data/web/t2.example.com/htdoc/
/data/web/t2.example.com/htdoc/foo
/data/web/t2.example.com/htdoc/foo/quux.txt

Plain access to quux.txt works of course

$ curl -s -D - -H 'Host: t2.example.com' http://127.0.0.1/foo/quux.txt
HTTP/1.1 200 OK
Server: nginx/1.3.4
Date: Thu, 02 Aug 2012 08:27:57 GMT
Content-Type: text/plain
Content-Length: 5
Last-Modified: Thu, 02 Aug 2012 07:15:43 GMT
Connection: keep-alive
ETag: "501a291f-5"
Accept-Ranges: bytes

QUUX

Access to location /bar works as well as expected

$ curl -s -D - -H 'Host: t2.example.com' http://127.0.0.1/bar/quux.txt
HTTP/1.1 200 OK
Server: nginx/1.3.4
Date: Thu, 02 Aug 2012 08:28:10 GMT
Content-Type: application/octet-stream
Content-Length: 5
Last-Modified: Thu, 02 Aug 2012 07:15:43 GMT
Connection: keep-alive
ETag: "501a291f-5"
Accept-Ranges: bytes

QUUX

but it breaks when the location of the same style has a nested location 
(which might be even unmatched; here this child_of_bla thingy), which 
also does a regex capture (doesn't matter whether this is an anonymous 
or named capture)

$ curl -s -D - -H 'Host: t2.example.com' http://127.0.0.1/bla/quux.txt
HTTP/1.1 404 Not Found
Server: nginx/1.3.4
Date: Thu, 02 Aug 2012 08:28:13 GMT
Content-Type: text/html
Content-Length: 168
Connection: keep-alive

<html>
<head><title>404 Not Found</title></head>
<body bgcolor="white">
<center><h1>404 Not Found</h1></center>
<hr><center>nginx/1.3.4</center>
</body>
</html>

Nginx doesn't even seem to process anyhting in the 'try files phase' 
according to the debug log.

2012/08/02 10:28:13 [debug] 15741#0: *17 http process request line
2012/08/02 10:28:13 [debug] 15741#0: *17 http request line: "GET 
/bla/quux.txt HTTP/1.1"
2012/08/02 10:28:13 [debug] 15741#0: *17 http uri: "/bla/quux.txt"
2012/08/02 10:28:13 [debug] 15741#0: *17 http args: ""
2012/08/02 10:28:13 [debug] 15741#0: *17 http exten: "txt"
2012/08/02 10:28:13 [debug] 15741#0: *17 http process request header 
line
2012/08/02 10:28:13 [debug] 15741#0: *17 http header: "User-Agent: 
curl/7.19.7 (i386-redhat-linux-gnu) libcurl/7.19.7 NSS/3.13.1.0 
zlib/1.2.3 libidn/1.18 libssh2/1.2.2"
2012/08/02 10:28:13 [debug] 15741#0: *17 http header: "Accept: */*"
2012/08/02 10:28:13 [debug] 15741#0: *17 http header: "Host: 
t2.example.com"
2012/08/02 10:28:13 [debug] 15741#0: *17 http header done
2012/08/02 10:28:13 [debug] 15741#0: *17 rewrite phase: 0
2012/08/02 10:28:13 [debug] 15741#0: *17 test location: ~ "^/bar(/.*)?"
2012/08/02 10:28:13 [debug] 15741#0: *17 test location: ~ "^/baz(/.*)?"
2012/08/02 10:28:13 [debug] 15741#0: *17 using configuration ""
2012/08/02 10:28:13 [debug] 15741#0: *17 http cl:-1 max:1048576
2012/08/02 10:28:13 [debug] 15741#0: *17 rewrite phase: 2
2012/08/02 10:28:13 [debug] 15741#0: *17 post rewrite phase: 3
2012/08/02 10:28:13 [debug] 15741#0: *17 generic phase: 4
2012/08/02 10:28:13 [debug] 15741#0: *17 generic phase: 5
2012/08/02 10:28:13 [debug] 15741#0: *17 access phase: 6
2012/08/02 10:28:13 [debug] 15741#0: *17 access phase: 7
2012/08/02 10:28:13 [debug] 15741#0: *17 post access phase: 8
2012/08/02 10:28:13 [debug] 15741#0: *17 try files phase: 9

(nothing happens here?)

2012/08/02 10:28:13 [debug] 15741#0: *17 content phase: 10
2012/08/02 10:28:13 [debug] 15741#0: *17 content phase: 11
2012/08/02 10:28:13 [debug] 15741#0: *17 content phase: 12
2012/08/02 10:28:13 [debug] 15741#0: *17 http filename: 
"/data/web/t2.example.com/htdoc/bla/quux.txt"
2012/08/02 10:28:13 [error] 15741#0: *17 open() 
"/data/web/t2.example.com/htdoc/bla/quux.txt" failed (2: No such file or 
directory), client: 127.0.0.1, server: t2.example.com, request: "GET 
/bla/quux.txt HTTP/1.1", host: "t2.example.com"
2012/08/02 10:28:13 [debug] 15741#0: *17 http finalize request: 404, 
"/bla/quux.txt?" a:1, c:1
2012/08/02 10:28:13 [debug] 15741#0: *17 http special response: 404, 
"/bla/quux.txt?"
2012/08/02 10:28:13 [debug] 15741#0: *17 http set discard body
2012/08/02 10:28:13 [debug] 15741#0: *17 HTTP/1.1 404 Not Found

Interestingly enough it works when I change the anonymous capture for 
/bar to a named one and replace the $1 in the alias by that named 
variable.
Is this expected behavior or should I rather assume "anonymous captures 
are evil"?

-cs



More information about the nginx mailing list