Bug 51077 - mod_rewrite does not pass query string to mod_proxy_fcgi and mod_proxy_scgi
Summary: mod_rewrite does not pass query string to mod_proxy_fcgi and mod_proxy_scgi
Status: RESOLVED WORKSFORME
Alias: None
Product: Apache httpd-2
Classification: Unclassified
Component: mod_rewrite (show other bugs)
Version: 2.5-HEAD
Hardware: PC Linux
: P2 normal (vote)
Target Milestone: ---
Assignee: Apache HTTPD Bugs Mailing List
URL:
Keywords: PatchAvailable
Depends on:
Blocks:
 
Reported: 2011-04-18 14:35 UTC by Mark Montague
Modified: 2012-09-16 20:54 UTC (History)
1 user (show)



Attachments
FastCGI test server for demonstrating the problem (732 bytes, text/x-perl-script)
2011-04-18 14:36 UTC, Mark Montague
Details
SCGI test server for demonstrating the problem (932 bytes, text/x-perl-script)
2011-04-18 14:37 UTC, Mark Montague
Details
Patch to make mod_rewrite pass query strings to mod_proxy_fcgi and mod_proxy_scgi (902 bytes, patch)
2011-04-18 14:38 UTC, Mark Montague
Details | Diff
Version 2 - Patch to make mod_rewrite pass query strings to mod_proxy_fcgi and mod_proxy_scgi (1.41 KB, patch)
2011-04-19 01:32 UTC, Mark Montague
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Mark Montague 2011-04-18 14:35:08 UTC
mod_rewrite does not pass the query string to the back-end server when the
[P] flag is used with mod_proxy_fcgi or mod_proxy_scgi.

To reproduce the problem, add the following directives to the virtual host
context and restart httpd:

ProxyPass /fcgi-test-proxypass/ fcgi://127.0.0.1:4000/
ProxyPass /scgi-test-proxypass/ scgi://127.0.0.1:4001/
RewriteRule ^/(fcgi-test-rewrite/.*)$ fcgi://127.0.0.1:4000/$1 [P]
RewriteRule ^/(scgi-test-rewrite/.*)$ scgi://127.0.0.1:4001/$1 [P]


Then start each of the two perl scripts attached to this issue; each
one is a simple server (FastCGI and SCGI, respectively) that do nothing
but echo back the request environment variables to the client:

# ./fcgi-test-server.pl &
# ./scgi-test-server.pl &


The query string is handled properly when the ProxyPass directive is used:

$ curl -s http://127.0.0.1/fcgi-test-proxypass/some/script.php?q=hello | \
  grep QUERY_STRING
QUERY_STRING="q=hello"
$ curl -s http://127.0.0.1/scgi-test-proxypass/some/script.php?q=hello | \
  grep QUERY_STRING
QUERY_STRING="q=hello"
$


However, the query string is not passed to the back-end server when
mod_rewrite is used.  (mod_proxy_fcgi sets the query string to an empty
value, while mod_proxy_scgi does not set it at all.)

$ curl -s http://127.0.0.1/fcgi-test-rewrite/some/script.php?q=hello | \
  grep QUERY_STRING
QUERY_STRING=""
$ curl -s http://127.0.0.1/scgi-test-rewrite/some/script.php?q=hello | \
  grep QUERY_STRING
$
Comment 1 Mark Montague 2011-04-18 14:36:58 UTC
Created attachment 26894 [details]
FastCGI test server for demonstrating the problem
Comment 2 Mark Montague 2011-04-18 14:37:27 UTC
Created attachment 26895 [details]
SCGI test server for demonstrating the problem
Comment 3 Mark Montague 2011-04-18 14:38:46 UTC
Created attachment 26896 [details]
Patch to make mod_rewrite pass query strings to mod_proxy_fcgi and mod_proxy_scgi
Comment 4 Mark Montague 2011-04-18 14:39:39 UTC
The attached patch fixes the problem:

$ curl -s http://127.0.0.1/fcgi-test-rewrite/some/script.php?q=hello | \
  grep QUERY_STRING
QUERY_STRING="q=hello"
$ curl -s http://127.0.0.1/scgi-test-rewrite/some/script.php?q=hello | \
  grep QUERY_STRING
QUERY_STRING="q=hello"
$

The test for the http and https schemata is done first in order to
provide a small performance improvement by short-circuiting quickly in
what should usually be the most common cases.

This should be a complete fix; none of the other schemata listed
in mod_rewrite.c:is_absolute_uri() nor any of the other proxy modules
appear to be candidates for accepting query strings.
Comment 5 Mark Montague 2011-04-19 01:32:17 UTC
Created attachment 26901 [details]
Version 2 - Patch to make mod_rewrite pass query strings to mod_proxy_fcgi and mod_proxy_scgi


The original patch resulted in different behavior in virtual host context versus directory context.

In virtual host context, mod_rewrite finishes with:

2011-04-19 00:23:30.735588 Xs3Z3t0NPeY pid=14843 127.0.0.1:36448 127.0.0.1:80 rewrite:trace1 mod_rewrite.c(468): 127.0.0.1 - - [127.0.0.1/sid#7f17e5faf738][rid#7f17c80129f0/initial] go-ahead with proxy request proxy:fcgi://127.0.0.1:4000/fcgi-test-rewrite/some/script.php [OK]

However, if the rewrite rule is placed in directory context, the final result has the query string appended to the URI, which in turn causes mod_proxy_fcgi to include the query string as a part of the SCRIPT_FILENAME environment variable, which is unexpected and causes problems for some (many?) back-end servers, including php-fpm.

2011-04-19 00:25:20.246937 Tc9g5R0PPeY pid=14841 127.0.0.1:52797 127.0.0.1:80 rewrite:trace1 mod_rewrite.c(468): 127.0.0.1 - - [127.0.0.1/sid#7f17e5faf738][rid#7f17c8002970/initial] [perdir /www/html/] go-ahead with proxy request proxy:fcgi://127.0.0.1:4000/fcgi-test-rewrite2/some/script.php?q=hello [OK]

The virtual host context case and directory context case do not diverge from what is expected for each of them until the final trace message (above).

Investigation shows that mod_rewrite.c:hook_uri2file() (which is used for rewrite rules in server context) uses different tests for determining whether to append the query string to the filename than mod_rewrite.c:hook_fixup() (which is used for rewrite rules in directory context).

Version 2 of the patch (attached) fixes the original problem and also modifies hook_fixup() to use the same logic as hook_uri2file() in order to get consistent behavior between directory and virtual host contexts for rewrite rules that use the [P] flag.
Comment 6 Jim Jagielski 2011-09-23 18:30:50 UTC
-            if (r->args != NULL) {
+	    if ((r->args != NULL)
+                && ((r->proxyreq == PROXYREQ_PROXY)
+                    || (rulestatus == ACTION_NOESCAPE))) {
+                /* see proxy_http:proxy_http_canon() */

breaks framework tests... don't see the rationale for it
Comment 7 Mark Montague 2012-09-16 20:54:01 UTC
This problem does not occur under httpd 2.4.3: RewriteRule with the [P] flag now passes the query string to the back-end server just like the ProxyPass directive does.

Closing the issue.