Mod_perl_api - accessing the Apache API via mod_perl ($Date: 2000/03/05 11:57:55 $)
This part of the mod_perl FAQ deals with the Apache Application Programmer's Interface and how to access it from perl via mod_perl.
As described in the mod_perl/INSTALL document, the only callback hook enabled by default is PerlHandler. If you want to intervene at a different stage of request processing you must enable the relevant hook. So to add a special authentication handler, for instance, you would start the installation process with:
perl Makefile.PL PERL_AUTHEN=1
Apache must be told to load your handler, either as a module with the
PerlModule
directive or as a script with PerlRequire
. The
handler subroutine will then be available, but you must also specify
which requests it should process. This is done by naming it in one of
the Perl*Handler directives (PerlInitHandler, PerlTransHandler, etc.).
If this directive is put in access.conf outside of any restrictive
context, your handler will be called during the given phase of each
request processed by the server. You can make it more selective by
restricting it to a directory (-hierarchy) in a <Directory ...>
section of access.conf or by putting it in a .htaccess file.
Here is an example of the directives needed to call a handler during Apache's URI to filename translation phase:
PerlRequire /full/path/to/script/Trans.pl PerlTransHandler Trans::handler
Trans.pl would start with the statement Package Trans;
and define a
subroutine called handler
.
Check out the Apache-Perl-contrib tarfile at http://perl.apache.org/src/
Here is an example from Vivek Khera. It allows you to filter files through a perl script based on their location. Rather than having to invoke a CGI script, the user just references the file with a normal URL and it is automagically processed by this code...
#! /usr/local/bin/perl use strict;
# filter a file before returning it to the web client # tell Apache to use the PerlHandler FileFilter on file which need # filtering in the htaccess file: # # <Files *.baz> # SetHandler perl-script # PerlHandler FileFilter # </Files>
package FileFilter;
use Apache::Constants ':common';
# find out the file name, then write it out with our header attached sub handler { my $r = shift;
my $fileName = $r->filename;
open(F,$fileName) or return NOT_FOUND; # file not found
$r->content_type('text/html'); $r->no_cache(1); # don't be caching my dynamic documents!
$r->send_http_header;
$r->print("<HEAD><TITLE>This is my personal header!</TITLE></HEAD><BODY>");
# Now copy the file to the client. If you do not need to make any # changes you can copy it verbatim with the single statement # $r->send_fd(\*F); # Otherwise, loop over each line... while(<F>) { # mangle the contents here if you want $r->print ($_); } close(F);
$r->print("<HR>Document created: ", scalar localtime time); $r->print("</BODY>");
OK; }
1;
Ralf Engelschall writes:
When you compiled one httpd with and the other without mod_perl, then you can simply use <IfModule mod_perl.c>...</IfModule> to surround the stuff for the httpd compiled with mod_perl. The other then ignores these lines. Example:
<IfModule mod_perl.c> ...stuff for httpd w/ mod_perl... </IfModule> <IfModule !mod_perl.c> ...stuff for httpd w/o mod_perl... </IfModule>
During each phase of request processing, apache calls handlers which have registered an interest in looking at and possibly handling the request. In some phases it makes sense to let all of the handlers have a chance to look at the request. In other phases the first handler to return ``OK'' terminates that phase (see the Apache documentation, /manual/misc/API.html).
If you define more than one PerlHandler for a phase, they are placed on a stack and all of the handlers on the stack are called sequentially by mod_perl, as long as they return ``DECLINED'' or ``OK''. Apache sees the return code from the final handler and reacts to it. If a handler wants to terminate the chain and ensure that no other handler is called after it, it should set the corresponding stack to undef. For instance, when a TransHandler has set $r->filename, it should terminate with
$r->set_handlers(PerlTransHandler => undef); return OK;
The configuration directives SetEnv and PassEnv are handled by apache's mod_env during the fixup stage, so mod_perl handlers that run prior to the fixup-stage don't see variables set with them. You can use PerlSetEnv/PerlPassEnv instead - they are processed as soon as possible during a request.
The $r->content
method reads application/x-www-form-urlencoded
data directly from the client and it does not keep a copy, so if you
(or another handler) call it again, the server will hang. One way of
avoiding this, if you do not have full control of all the handlers
involved, is to convert the request from POST to GET in the first
handler that reads the content:
use Apache::Constants qw(M_GET);
sub My::Test::handler { my $r = shift;
if ($r->method eq 'POST') { my $content = $r->content; # ... #make sure nobody else tries to read POST data now that we have $r->method('GET'); $r->method_number(M_GET); $r->headers_in->unset('Content-length'); } # ... }