Apache mod_rewrite double encodes query string on redirect

apache-2.2escapingmod-rewritequerystring

We've encountered a strange issue (a bug, perhaps?) with Apache mod_rewrite's behavior when passing through query strings.

To reproduce, we've set up a clean Ubuntu (oneiric) install with the default Apache configuration. We have enabled mod_rewrite, and in the default site configuration, we've added the following:

RewriteEngine on
RewriteRule ^/(.*)$ /r/$1 [R]

To test, we use curl:

curl -I 'http://[ubuntu-machine]/a/b%20c?a%20b'

The relevant output is:

HTTP/1.1 302 Found
Server: Apache/2.2.20 (Ubuntu)
Location: http://[ubuntu-machine]/r/a/b%20c?a%2520b

As you can see, the query string is double-escaped, which is wrong. Does anyone have any idea how we could fix this? A couple of things we've tried:

  • Adding [NE]. This gives us the correct query string, but the path is unescaped, which leads to new problems.
  • Adding [NE,B]. This seems to work, but causes the / between the a and b parts of the path to be escaped.
  • Unescaping the query string manually.

    RewriteCond %{QUERY_STRING} .*
    RewriteMap unescape int:unescape  
    RewriteRule ^(.*)$          $1?${unescape:%{QUERY_STRING}}
    

    However, this means we cannot distinguish between, say, an & and an escaped & in the query-string.

Update:

This bug report describes the same issue. The first comment links to a commit apparently fixing the issue, but as Pieter says below, it doesn't seem like it is actually fixed.

Best Answer

This seems to be a bug in Apache. This bug report is a bit messy, but describes your problem exactly:

https://issues.apache.org/bugzilla/show_bug.cgi?id=34602

It looks like they are aware of the issue. Though the bug claims they have fixed, I have tested this with Apache 2.3.15, and the problem still seems to be there. Also note that Apache 2.3 is a beta version, so it's no use to you even if it did fix it, until Apache 2.4 is out.