Hi Torsten.
Once again, I thank you for the time spent researching and answering my question(s). Unfortunately, I am less fluent in C than you (which is why after all I like and use mod_perl), so sometimes referring me to the C code is not as enlightening to me as it undoubtedly is to you. But I am trying to follow, nevertheless.

Torsten Foertsch wrote:
On Sun 12 Oct 2008, André Warnier wrote:
<Location /some/url>

   SetHandler jakarta-servlet
   SetEnvIf REQUEST_URI "\.(htm|web|css|gif|jpg|js|html?)$" no-jk

   PerlXXXHandler My::Module->some_method

   ...

</Location>

("jakarta-servlet" above means mod_jk --> Tomcat)
(and PerlXXXHandler being any kind of Perl HTTP Handler running soon
enough)

The Question :
Is it possible, in the PerlXXXHandler, on a request-by-request base,
to "disable" the jakarta-servlet handler, and install the following
instead

   SetHandler modperl
   PerlResponseHandler My::Module->some_other_method

?

I know that I can do something like the above for regular static
pages, and I use this already :
   $r->handler('modperl');
   $r->set_handlers(PerlAuthzHandler => []); # stop authorization
from running
   $r->set_handlers(PerlResponseHandler => \&_send_login_form);


However, when I try to do the same in a Location like the above, it
seems that the jakarta-servlet handler runs anyway, and my
PerlResponseHandler is never called.

Does that piece of code run in a /Perl(PostReadRequest|Trans|
MapToStorage)Handler/ ?

No, at the moment it runs in a PerlAuthenHandler.
As explained the other thread (requests and subrequests), I thought it was more elegant and mod_perl-ish, instead of doing a re-direct to a login page if the user needed authentifying, to having the login page returned by a content handler. (One main reason is that it allows me, in that content handler,to "filter" the login page and insert in it, things I have stored previously in $r->pnotes().) For that thus, when the user is not authenticated when the request hits the PerlAuthenHandler, this handler tries to set the content handler (PerlResponseHandler) to the method send_login_form() in the same module. This works fine when the previous content handler is Apache's default, iow for static pages. But it fails miserably when there is already a specific content handler (like mod_jk) for this Location.


Please, have a look again at the ap_process_request_internal() function in httpd-2.x.y/server/request.c.
I would first have to know where this thing is. I have never so far looked at the Apache source code, so I need some pointers there. Not that if I look, I would necessarily understand much of it, but I can try.
Now, why would I, since you provide the nice explanation below ?

This function implements almost the
complete request cycle (save PostReadRequest, Response and Log).

Just after ap_run_translate_name(), that is the PerlTransHandler, you'll see this piece:

/* Reset to the server default config prior to running map_to_storage
     */
    r->per_dir_config = r->server->lookup_defaults;

    if ((access_status = ap_run_map_to_storage(r))) {
        /* This request wasn't in storage (e.g. TRACE) */
        return access_status;
    }

/* Rerun the location walk, which overrides any map_to_storage config.
     */
    if ((access_status = ap_location_walk(r))) {
        return access_status;
    }

    /* Only on the main request! */
    if (r->main == NULL) {
        if ((access_status = ap_run_header_parser(r))) {
            return access_status;
        }
    }
...

The line "r->per_dir_config = r->server->lookup_defaults;" resets all request specific configurations applied so far. After that line the request is configured as if no Directory/Location or other container were present in your httpd.conf. Next comes MapToStorage. Here Directory, DirectoryMatch, Files and FilesMatch containers are applied to the request.
So, you mean that for every and each request, Apache re-configures itself ? If that is so, it is quite amazing the speed at which it can serve a page..

Then, and this is what I think hits you, comes an
ap_location_walk. Here Location containers are applied. So, your SetHandler inside the Location overrides any $r->handler seen before.
Well, I am not sure :
The handler set in the configuration file for that Location, is originally "jakarta-servlet" (as per the snippet below). It is I, in my PerlAuthenHandler, who is trying to reset this to "modperl", and in mod_perl, to my send_login_page() method.
Before I do that, there is no $r->handler nor PerlResponseHandler set.

I may be misunderstanding what you say above of course..


After the ap_location_walk comes the PerlHeaderParserHandler. But it is skipped for subrequests.
That's fine, we are always in a main request here.

 A further examination will show you
(probably not)
that the
next phase that is run by all requests is the PerlTypeHandler just before Fixup. So, move your "$r->handler('modperl');" to one of those and it will work.
I don't think I can do that, unless I want the PerlTypeHandler or PerlFixupHandler to become an authentication handler. That would probably for one upset Adam, for two be kind of funky, no ?

 I prefer Fixup but that is based only on the fact
that it is documented as do-what-you-want phase. There are directives that change the handler in the type-checker phase. In fact the AddHandler directive works that way. Mod_mime looks at the file extension and adjusts the handler, e.g "AddHandler cgi-script .pl". So using Fixup your module is the last to kick in.

Now, in summary :
This is a very specialised authentication module, meant to be used in very specific circumstances and not for general usage. I control the environment, so I can pretty much do what I want as long as it does not crash the system or present some big security hole or the like.

In my case, that <Location> containing the
sethandler jakarta-servlet
is pretty much unique: it is not a sub- or super-location of anything else, and it fulfills only one very narrow purpose. To my knowledge, there will be no other module playing a role there, other than the jakarta-servlet initial handler, plus whatever I decide to put in there as mod_perl modules and methods.
This for the entire duration of one request.

Now, assuming I have no other stuff in there than the following lines
<LocationMatch "/servlet.xyz$">
   SetHandler jakarta-servlet
   SetEnvIf REQUEST_URI "\.(htm|web|css|gif|jpg|js|html?)$" no-jk

   AuthType MyModule
   AuthName MyXyzApp
   PerlSetVar MyModule_var1 "value"
   PerlAccessHandler My::Module->some_access_method
   PerlAuthenHandler My::Module->some_auth_method
   PerlAuthzHandler My::Module->some_authz_method
   require valid-user

</Location>

then, if I understand correctly what you write above, since I have no PerlTransHandler, nor Fixup, etc.. I should be able to do the same in the PerlAuthenHandler, is it no so ?
Or am I still confused about the order in which things happen ?

Or, a thought that just occurred to me, is the solution for me (stopping jakarta-servlet from running and running my PerlresponseHandler instead), as easy as setting the "no-jk" variable (if I can do that within my PerlAuthenHandler, and how) ?

Or, another thought that just occurred : can I comment out the "SetHandler jakarta-servlet" originally, set my PerlresponseHandler as the default handler in the <Location>, and then *if the user is authenticated* (the contrary of my current condition), *set* the content handler to be jakarta-servlet instead of modperl ?


To carry state around use pnotes
 (that's what I use mostly)
, notes or subprocess_env.


Reply via email to