Opened 7 years ago

Last modified 7 years ago

#1467 accepted defect

Problem of location matching with a given request

Reported by: samilko.ka@… Owned by: Yaroslav Zhuravlev
Priority: minor Milestone:
Component: documentation Version: 1.13.x
Keywords: location, manual Cc:
uname -a: Linux myserver 3.10.0-693.el7.x86_64 #1 SMP Tue Aug 22 21:09:27 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux
nginx -V: nginx version: nginx/1.13.8
built by gcc 4.8.5 20150623 (Red Hat 4.8.5-16) (GCC)
built with OpenSSL 1.0.2k-fips 26 Jan 2017
TLS SNI support enabled
configure arguments: --prefix=/etc/nginx --sbin-path=/usr/sbin/nginx --modules-path=/usr/lib64/nginx/modules --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --pid-path=/var/run/nginx.pid --lock-path=/var/run/nginx.lock --http-client-body-temp-path=/var/cache/nginx/client_temp --http-proxy-temp-path=/var/cache/nginx/proxy_temp --http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp --http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp --http-scgi-temp-path=/var/cache/nginx/scgi_temp --user=nginx --group=nginx --with-compat --with-file-aio --with-threads --with-http_addition_module --with-http_auth_request_module --with-http_dav_module --with-http_flv_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_mp4_module --with-http_random_index_module --with-http_realip_module --with-http_secure_link_module --with-http_slice_module --with-http_ssl_module --with-http_stub_status_module --with-http_sub_module --with-http_v2_module --with-mail --with-mail_ssl_module --with-stream --with-stream_realip_module --with-stream_ssl_module --with-stream_ssl_preread_module --with-cc-opt='-O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -m64 -mtune=generic -fPIC' --with-ld-opt='-Wl,-z,relro -Wl,-z,now -pie'

Description

Hi, guys. I've got a problem with location request and regexp, 'cause the nginx is not finding match like it describes here: https://nginx.ru/en/docs/http/ngx_http_core_module.html#location

My request is:

http://localhost:8080/catalog/css/asdftail

My conf is:

server {
    listen 8080;

    location ~ ^/catalog/(js|css|i)/(.*)$
    {
            return 405;
    }
    location / {
            location ~ ^.+tail$ {
                    return 403;
            }
            return 402;
    }
}

My problem is:
With my request, my conf must return me 405 error, but it return me 403 error, 'cause nginx starts to check regexp location from "the location with the longest matching prefix is selected and remembered.", not from top of config - "Then regular expressions are checked, in the order of their appearance in the configuration file."

If my conf likes this:

server {
    listen 8080;

    location ~ ^/catalog/(js|css|i)/(.*)$
    {
            return 405;
    }
    
    location ~ ^.+tail$ {
            return 403;
    }

    location / {

            return 402;
    }
}

or this:

server {
    listen 8080;

    location catalog/ {
        location ~ ^/catalog/(js|css|i)/(.*)$
        {
                return 405;
        }
    }
    location / {
            location ~ ^.+tail$ {
                    return 403;
            }
            return 402;
    }
}

Then all works like in manual.

Change History (3)

comment:1 by Maxim Dounin, 7 years ago

Component: otherdocumentation
Priority: majorminor
Status: newaccepted

Location matching procedure as described in the documentation describes matching without nested locations, hence the confusion.

If there are nested locations, the same procedure is additionally applied within a location with longest prefix, location / in your config. That is, nginx will search for longest matching prefix location within location /, and then it'll check for the first matching regular expression within location /. The latter will match location ~ ^.+tail$. Matching will stop here, as we've already found a regular expression match, and regular expressions on previous levels won't be checked.

In other words, regular expressions within prefix locations have higher priority than global ones, making it possible to do more specific processing, for example:

location ~ \.php$ {
    fastcgi_pass global_backend;
    ...
}

location /foo/ {
    ...

    location ~ \.php$ {
        fastcgi_pass foo_backend;
        ...
    }
}

Summing up the above, the behaviour you are seeing is not a bug, location matching works as designed. On the other hand, we might want to improve the documentation to better describe how matching works if there are nested locations.

comment:2 by Yaroslav Zhuravlev, 7 years ago

Owner: set to Yaroslav Zhuravlev
Status: acceptedassigned

comment:3 by Yaroslav Zhuravlev, 7 years ago

Status: assignedaccepted
Note: See TracTickets for help on using tickets.