nginx misbehaviour in conjunction with non-ASCII characters

Ruslan Ermilov ru at nginx.com
Thu Dec 19 09:11:40 UTC 2013


On Wed, Dec 18, 2013 at 06:27:31PM -0500, ako673de wrote:
> Found a bug in implementation of MOVE and COPY (webdav) methods. It happens
> if destination header contains non-ASCII characters (that need to be escaped
> with "%").
> 
> An example:
> 
> Rename (=MOVE) file "<www-root>/TheCore.ogm" to "<www-root>/The_Core.ogm":
> 
> Request header:
> --> MOVE http://andinas/TheCore.ogm HTTP/1.1
> --> Destination: http://andinas/The_Core.ogm
> Response header:
> --> HTTP/1.1 204 No Content
> --> Server: nginx/1.5.6
> Result: File renamed to "The_Core.ogm". Fine!
> 
> Now rename (=MOVE) file "<www-root>/andinas/The_Core.ogm" to
> "<www-root>/andinas/The_ Core.ogm" (notice the blank after the underscore,
> but the same is true for äöüß and the like!):
> 
> Request header:
> --> MOVE http://andinas/The_Core.ogm HTTP/1.1
> --> Destination: http://andinas/The_%20Core.ogm
> Response header:
> --> HTTP/1.1 204 No Content
> --> Server: nginx/1.5.6
> Result: File renamed to "The_%20Core.ogm". Not so fine!
> 
> The escaped blank is treated by nginx MOVE as if it was not escaped!

I have a patch for that, would you like to try it?

> Found a similar issue with this config-file line:
> --> if ( $http_destination ~ https?://[^/]+/(.*) ) { set $httpdest
> http://localhost:8008/$remote_user/$1; }
> 
> (for this (working!) code that makes the destination header ready for
> proxy_pass to another webdav server with user dependent base folders
> (pyWebDav allows only one user :-/):
> --> proxy_set_header Destination $httpdest;
> --> proxy_pass http://127.0.0.1:8008/$remote_user$request_uri;
> ).
> 
> Here again, if $http_destination contains the perfectly correct escaped
> characters from the webdav client, the resulting $httpdest will additionally
> escape the "escape" characters.
> Example:
> Destination File = "<www-root>/The_ Core.ogm"
> $http_destination = "http://andinas/The_%20Core.ogm" (correct)
> $httpdest = "http://andinas/The_%2520Core.ogm" (wrong!)
> 
> Obviously here the highly undesirable transformation happens during the
> regex matching. But why? Can I switch that off somehow?
> 
> Workaround: Use perl function to replace "%25" by "%". Use the undocumented
> "r->variable()" for that!

Don't use rewrite.  nginx's DAV module supports relative URLs.

Using the following config snippet:

http {
    server {
        listen 8000;

        location / {
            proxy_set_header Destination /$http_user$http_destination;
            proxy_pass http://127.0.0.1:8001/$http_user$request_uri;
        }
    }
}

and the following request:

printf 'MOVE /foo%%20bar HTTP/1.1\r\nDestination: /bar%%20baz\r\nHost: 127.0.0.1\r\nUser: nobody\r\n\r\n' | nc 127.0.0.1 8000

I get:

$ nc -l 8001
MOVE /nobody/foo%20bar HTTP/1.0
Destination: /nobody/bar%20baz
Host: 127.0.0.1:8001
Connection: close
User: nobody

> If you are still reading :-): There are two very funny things about the
> --> proxy_pass http://127.0.0.1:8008/$remote_user$request_uri;
> line:
> 1) You cannot use localhost here. nginx needs a resolver as soon as there is
> a variable in the string. And at least I didn't manage to find a resolver
> that can resolve localhost.
> 2) Nowhere on the internet it's been said, that you need to add $request_uri
> to that line, but you do need! And it even must not be $uri, because that
> one has the same escaping issues like the other things I mentioned above.
> 
> 
> OK, now I'm done ;-). Please help!
> 
> best regards
> ako673de



More information about the nginx mailing list