On 12/14/2012 3:29 PM, André Warnier wrote:
Ryan Gies wrote:
On 12/14/2012 8:52 AM, André Warnier wrote:
I suppose that in the end I will want to do something like this :
my $finfo = $r->finfo();
# do something to $finfo to set the flag
$r->finfo($finfo);
$r->handler('modperl');
$r->set_handlers(PerlResponseHandler => \&_my_response_handler);
but how do I "do something to $finfo" ?
Or am I totally off-track here ?
TIA
For what it's worth, I have consistent success in using $r->finfo to
tell Apache the final destination. In the case that $you_want_to_hook
(below) is false, Apache will also serve the intended file. The
timing used is:
PerlMapToStorageHandler
$r->filename($path); # where $path is an absolute file-system path
$r->finfo(APR::Finfo::stat($path, APR::Const::FINFO_NORM, $r->pool));
return Apache2::Const::OK;
PerlFixupHandler
if ($you_want_to_hook) {
$r->push_handlers(PerlResponseHandler => \&_response_handler);
$r->handler('modperl');
return Apache2::Const::OK;
}
Let me explain better what I am looking for :
<LocationMatch "/IIS_app/(.*)$">
PerlAuthenHandler SLC->authenticate
PerlAuthzHandler SLC->authorize
PerlSetVar SLC_login_page "/public/login.html"
...
ProxyPassMatch http://localhost:8800/$1
</LocationMatch>
In other words,
- Apache+mod_perl is acting as a reverse proxy for an application
running under IIS on the same server
- but this IIS application requires a special HTTP header to
authenticate the user
- In the Location above, the PerlAuthenHandler checks if the user is
authenticated.
- If yes, it adds the required HTTP header to the request, and
then a few steps later the proxying happens to IIS, and that's fine.
- If not, it sends back a login page.
What I want to do refers to the "sends back a login page".
In case the user is not authenticated, I do /not/ want Apache to proxy
the call to IIS.
I want to reset the response handler so that it is no longer
mod_proxy, but mod_perl, and my own PerlResponseHandler (which sends
back the login page "/public/login.html", after munching on it).
But what happens is that the proxying runs anyway, and the request
ends up in IIS, but without the authentication header.
That's what I want to avoid.
In the PerlAuthenHandler, I already do this :
if ($not_authenticated)
{
$r->handler('modperl'); # (1)
$r->set_handlers(PerlResponseHandler => \&_my_send_login_handler);
# (2)
$r->set_handlers(PerlFixupHandler => sub {
$_[0]->handler('modperl') } ); # (3)
return Apache2::Const::OK;
}
But that is apparently not enough. It is still (later) proxying the
request to IIS.
So it is apparently ignoring the line
$r->handler('modperl'); # (1)
What am I missing ? (as another way of phrasing the initial question)
I am led to believe that it has to do with the "map-to-storage" phase,
which has already happened by the time the PerlAuthenHandler runs, and
that in order to completely override the mod_proxy response handler, I
need to set/reset some flag(s).
I'd like (if possible) to do that "dynamically" in the
PerlAuthenHandler, without having to configure an extra
PerlMapToStorageHandler in my configuration for that Location.
(In the above, (1) and (3) are probably the same thing, with (3)
happening later and having maybe a better chance. But it's still not
working.
Would these 2 lines :
> $r->filename($path); # where $path is an absolute file-system path
> $r->finfo(APR::Finfo::stat($path, APR::Const::FINFO_NORM, $r->pool));
added to the above current code, do the trick ?
I would need to duplicate your scenario, setting up a ProxyPass
situation such as you've described, to help answer that. I do however
suspect that if you change the approach to do something like this:
my $login_page = '/public/login.html';
$r->add_config(["ErrorDocument 401 $login_page"]);
$r->err_headers_out->add('WWW-Authenticate' => 'Web'); # Required header
return Apache2::Const::AUTH_REQUIRED;
That the ProxyPass will not happen. You would then munch on
/public/login.html separately, as a sub-request.