
aw at ice-sa
Oct 13, 2008, 7:41 AM
Post #3 of 13
(880 views)
Permalink
|
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. >
|