Opened 11 years ago

Last modified 2 years ago

#348 accepted defect

Excessive urlencode in if-set

Reported by: Petr Messner Owned by:
Priority: minor Milestone:
Component: nginx-core Version:
Keywords: rewrite Cc:
uname -a: Darwin messamac.local 11.4.2 Darwin Kernel Version 11.4.2: Thu Aug 23 16:25:48 PDT 2012; root:xnu-1699.32.7~1/RELEASE_X86_64 x86_64
nginx -V: nginx version: nginx/1.4.0
configure arguments: --prefix=/opt/local --with-cc-opt='-I/opt/local/include -O2' --with-ld-opt=-L/opt/local/lib --conf-path=/opt/local/etc/nginx/nginx.conf --error-log-path=/opt/local/var/log/nginx/error.log --http-log-path=/opt/local/var/log/nginx/access.log --pid-path=/opt/local/var/run/nginx/ --lock-path=/opt/local/var/run/nginx/nginx.lock --http-client-body-temp-path=/opt/local/var/run/nginx/client_body_temp --http-proxy-temp-path=/opt/local/var/run/nginx/proxy_temp --http-fastcgi-temp-path=/opt/local/var/run/nginx/fastcgi_temp --http-uwsgi-temp-path=/opt/local/var/run/nginx/uwsgi_temp --with-ipv6



I had setup Apache with mod_dav_svn behind nginx acting as front-end proxy and while commiting a copied file with brackets ([]) in filename into that subversion I found a bug in nginx.

How to reproduce it (configuration file is as simple as possible while still causing the bug):

$ cat nginx.conf 
error_log  stderr debug;
events {
    worker_connections  1024;
http {
    access_log access.log;
    server {
        listen 8000;
        server_name localhost;
        location / {
            set $fixed_destination $http_destination;
            if ( $http_destination ~* ^(.*)$ )
                set $fixed_destination $1;
            proxy_set_header        Destination $fixed_destination;            

$ nginx -p $PWD -c nginx.conf -g 'daemon off;'

In second terminal window:

$ nc -l 8010

In third terminal window:

$ curl --verbose --header 'Destination: http://localhost:4000/foo%5Bbar%5D.txt' '0:8000/%41.txt'
* About to connect() to 0 port 8000 (#0)
*   Trying
* Adding handle: conn: 0x7fa91b00b600
* Adding handle: send: 0
* Adding handle: recv: 0
* Curl_addHandleToPipeline: length: 1
* - Conn 0 (0x7fa91b00b600) send_pipe: 1, recv_pipe: 0
* Connected to 0 ( port 8000 (#0)
> GET /%41.txt HTTP/1.1
> User-Agent: curl/7.30.0
> Host: 0:8000
> Accept: */*
> Destination: http://localhost:4000/foo%5Bbar%5D.txt

Back in the second terminal window:

($ nc -l 8010)
GET /%41.txt HTTP/1.0
Destination: http://localhost:4000/foo%255Bbar%255D.txt
Connection: close
User-Agent: curl/7.30.0
Accept: */*

The problem is that the Destination header was changed from to This happens only when

  • that if ( $http_destination ~* ^(.*)$ ) is processed
  • and URL (HTTP GET URL, not that Destination URL) also contains urlencoded (%41) character(s).

In other cases (URL does not contain urlencoded character or that if is not matched) the Destination header is proxy_passed untouched, which is expected behavior.

Note: Why do I need that if ( $http_destination ~* ^(.*)$ )? In this example it is simplified, but for that Subversion setup I have mentioned I need to rewrite the Destination from https to http when nginx proxy_passes from https to Apache over http.

This bug also happens on nginx/0.7.67 in Debian Squeeze.

Change History (6)

comment:1 by Maxim Dounin, 11 years ago

Keywords: rewrite added
Status: newaccepted

Looks like unexpected urlencode happens in "set $fixed_destination $1;", much like during rewrite handling. As a quick workaround named captures should work.

Needs additional investigation, see also ticket #52.

comment:3 by Maxim Dounin, 10 years ago

See also #408 and #589.

comment:4 by Maxim Dounin, 8 years ago

See also #963.

comment:5 by Maxim Dounin, 7 years ago

See also #1043.

comment:6 by Maxim Dounin, 4 years ago

See also #1930.

comment:7 by Maxim Dounin, 2 years ago

See also #2320.

Note: See TracTickets for help on using tickets.