nginx misbehaviour in conjunction with non-ASCII characters

ako673de nginx-forum at
Wed Dec 18 23:27:31 UTC 2013

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!

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$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.

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!

If you are still reading :-): There are two very funny things about the
--> proxy_pass$remote_user$request_uri;
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

Posted at Nginx Forum:,245702,245702#msg-245702

More information about the nginx mailing list