Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Apache mod_rewrite rules don't take any affect under mod_perl ($r->unparsed_uri problem) #536

Open
bigunyak opened this issue Nov 13, 2015 · 9 comments

Comments

@bigunyak
Copy link

Hi there,

I don't think this is necessarily a bug, but something which is definitely was not obvious to me and maybe deserves to be documented somewhere at least.
What I'm trying to achieve seemed very easy to me. I have two different APIs implemented in two different applications, one as a native mod_perl app, another one as a PSGI app, both running under mod_perl. I want to use mod_rewrite to re-route requests to a certain endpoint from the first API to the second API with no redirects. Sounds easy, and there are tons of examples on the internet how to do it with mod_rewrite. Here is a part of my apache config which I expected to work.

    RewriteEngine On
    RewriteRule ^/api1/v1/endpoint /api2/v1/endpoint [PT,L]

    <Location /api1/>
        SetHandler modperl
        PerlResponseHandler MyApp::API1
    </Location>

    <Location /api2/>
        SetHandler perl-script
        PerlResponseHandler Plack::Handler::Apache2
        PerlSetVar psgi_app /var/www/myapp/psgi/api2.psgi
    </Location>

The problem is that it doesn't work. I can see in RewriteLog that the pattern is matched and apache does it part in passing through the rewritten URI, my PSGI app is reached but the URI it gets is actually /api1/v1/endpoint.
After digging in and wasting a lot of time I found the problem in Plack::Handler::Apache2 module, call_app procedure and more specifically in using $r->unparsed_uri. The thing is that unparsed_uri in this case returns the original URI, the modified URI is returned by uri method.
Not sure how this could be fixed, but this is definitely not a place where I'd expect to get problems like that. This thing makes it impossible to use apache mod_rewrite with Plack.
In case it matters, my apache version is 2.2.29.

@miyagawa
Copy link
Member

my PSGI app is reached but the URI it gets is actually /api1/v1/endpoint.

But that's how the app is accessed externally, so it is difficult to call it a bug (as you've originally stated).

It is a known issue if you run a URL rewriting inside Apache URL translation phase Plack can't tell which URL is the path you want to use. In the case of Apache2 handler, the external URI is the URI it uses.

Previously it was using the internal, rewritten $r->uri for a while but there was a problem with URL (un)escaping and multiple slashes squashed.

might be related: #27 #157

@bigunyak
Copy link
Author

Sure it is the original URI which was used to access the application. But the rewritten URI is also available in $r->uri, as you mentioned. The problem is that this information is not passed to the framework level in any standard way which makes a very basic mod_rewrite use case is practically not working.
My intention in opening this ticket was if not fixing the problem, then at least document the situation somewhere, so that other people won't wast time trying to figure out why all those basic examples on the Internet of using Apache mod_rewrite don't really work with PSGI applications.

@miyagawa
Copy link
Member

That's rather passive aggressive :)

You can access Apache's request object with Apache2::RequestUtil->request inside a Plack middleware, so you can restore PATH_INFO and SCRIPT_NAME from there.

@bigunyak
Copy link
Author

That's exactly what I'm doing now, just wish I didn't wast so much time looking for the problem elsewhere but not in Plack, expecting this stuff just work.
Well, at least we have some traces of the problem here now. :)

@miyagawa
Copy link
Member

Why don't you document that middleware (or even package it as a CPAN module) and submit as a doc patch?

@bigunyak
Copy link
Author

Well, the middleware package which allows to do it already exists: Plack::Middleware::Rewrite.
What I do is simply modifying $env->{'SCRIPT_NAME'} and $env->{'PATH_INFO'} values in the way my Mojolicious app doesn't get surprised with them. :)
There is one problem though, the Plack::Handler::Apache2::fixup_path procedure generates an error on every rewritten URI, something like that:

[error] Your request path is '/api1/v1/endpoint' and it doesn't match your Location(Match) '/api2/'. This should be due to the configuration error. See perldoc Plack::Handler::Apache2 for details.

There should be a way to disable that.

@miyagawa
Copy link
Member

There is one problem though, the Plack::Handler::Apache2::fixup_path procedure generates an error on every rewritten URI, something like that:

Am I right that this error is generated regardless of your rewrite stuff? This happens before any Plack Middleware kicks in.

@bigunyak
Copy link
Author

Correct, the error is there even without any middleware code involved.
These errors are probably a good indication of misconfiguration in some cases but with apache rewrite this is exactly what happens, PATH_INFO doesn't match location path.

@miyagawa
Copy link
Member

Well yeah, that's exactly why we were aware of the limitation of this PATH_INFO restoration and put that handy error message there. An option to turn them off and use $r->uri, with acknowledging there's another limitation (like squashed /) doesn't sound unreasonable.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants