Bug 14648

Summary: mod_rewrite does not proxy included requests
Product: Apache httpd-1.3 Reporter: Alex Krohn <alex-apache>
Component: mod_rewriteAssignee: Apache HTTPD Bugs Mailing List <bugs>
Status: CLOSED FIXED    
Severity: normal CC: cramer
Priority: P3 Keywords: PatchAvailable
Version: 1.3.27   
Target Milestone: ---   
Hardware: All   
OS: All   
Attachments: One line fix to each: mod_dir & mod_rewrite

Description Alex Krohn 2002-11-18 19:48:58 UTC
This is a duplicate of PR2074, PR5338, PR6804 and possibly others I couldn't 
find in bugzilla.

Basically the problem is, if you have:

ProxyPass /foo http://newserver/foo
ProxyPassReverse /foo http://newserver/foo

Then an SSI of:

<!--#include virtual="/foo/bar"-->

_will_ be proxied. If instead of ProxyPass you use:

RewriteRule /foo(.*) http://newserver/foo$1 [P]

then the above SSI is _not proxied_. This is because of:

        /*
         *  Ignore this rule on subrequests if we are explicitly
         *  asked to do so or this is a proxy-throughput or a
         *  forced redirect rule.
         */
        if (r->main != NULL &&
            (p->flags & RULEFLAG_IGNOREONSUBREQ ||
             p->flags & RULEFLAG_PROXY          || 
             p->flags & RULEFLAG_FORCEREDIRECT    )) {
            continue;
        }

in mod_rewrite. If you comment out the RULEFLAG_PROXY, it works as expected. 
I'm not sure of the consequences this has. Can anyone comment on the reasoning 
behind this? 

I believe this also applies to httpd-2.0, but I haven't actually compiled it 
yet.
Comment 1 Mike Cramer 2002-11-27 15:15:36 UTC
This doesn't work perfectly, I've discovered. Take the follwoing setup:

## relevant conf directives
DirectoryIndex index.html index.php
RewriteRule ^/(.*\.php)$ http://localhost:8888/$1 [P]
##

$DocRoot/blah/ contains: index.php and test.html

Now...*without* patching mod_rewrite, a request for http://www.domain.org/blah/
will return index.php just fine, and it will be properly proxied over to
localhost:8888. And, as this bug points out, if test.html just contains
<!--#include virtual="index.php"-->, requests for it return the unparsed source
of index.php, which is incorrect.

But if you remove the one line from mod_rewrite, allowing proxy requests in
subrequests, the situation reverses. The SSI part works properly, but requests
for /blah/ give you a directory index instead of the output of index.php.

So this patch doesn't do exactly the right thing. 
Comment 2 Mike Cramer 2002-11-27 20:08:58 UTC
I've done some more digging and think I've come a little closer to the real
source of the problem:

mod_dir makes subrequests for each of its potential index file names until it
finds one to return. Line 165 of mod_dir.c is this:

if (rr->status == HTTP_OK && S_ISREG(rr->finfo.st_mode)) {

So, for mod_dir to return an index file the subrequest has to be HTTP_OK and it
must be a regular file. This works fine with the unpatched mod_rewrite, because
it will return HTTP_OK and the file will be there -- even if the server is going
to end up proxying it in the end.

But, if you patch mod_rewrite then you'll still get the HTTP_OK, but
rr->filename will have been changed to start with "proxy:", so S_ISREG() will fail. 

Which leads to this solution:

change the call to ap_sub_req_lookup_uri on line 163 of mod_dir.c to
ap_sub_req_lookup_file. ap_sub_req_lookup_file doesn't do the URI translation,
so it skips mod_rewrite in the subrequest. But then mod_dir still does an
internal redirect, which in turn *does* do the URI translation, so everything
works out in the end.

With these changes both mod_include and mod_dir do the right thing when they are
dealing with a file proxied via mod_rewrite+mod_proxy. I'll attach a patch which
changes both parts.
Comment 3 Mike Cramer 2002-11-27 20:11:06 UTC
Created attachment 3973 [details]
One line fix to each: mod_dir & mod_rewrite
Comment 4 Jeff Trawick 2003-11-21 18:08:27 UTC
I'm going through the bug db to make sure patches are findable.  Please see 
http://httpd.apache.org/dev/patches.html
Comment 5 Jeremy Brown 2003-11-27 15:20:21 UTC
Another solution to this problem is to utilize the proxy: moniker instead of 
[P} to invoke the proxy client.

[P] as you have pointed out invokes the proxy client but does not continue with 
additional includes on the invoked page.

Wheras the proxy: moniker is invoked in the file mapping handler which contiues 
with additional ssi requests.

Example:
RewriteRule ^(.*) proxy:http://host/$1

This assumes that mod_proxy is installed and configured correctly!

The other benefit is that additional SSI requests will continue to be processed 
on the calling page.
Comment 6 André Malo 2004-01-14 00:41:39 UTC
Fixed in 2.1.

Thanks for the report and thanks for using Apache.