| =head1 NAME |
| |
| Mod_perl_api - accessing the Apache API via mod_perl ($Date$) |
| |
| =head1 DESCRIPTION |
| |
| 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. |
| |
| =head1 Why can't the server find the handler I wrote? |
| |
| =head2 Did you enable the required hook? |
| |
| 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 |
| |
| =head2 Is the handler correctly referenced in the configuration? |
| |
| Apache must be told to load your handler, either as a module with the |
| C<PerlModule> directive or as a script with C<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 C<Package Trans;> and define a |
| subroutine called C<handler>. |
| |
| =head1 Where can I find examples to get me started? |
| |
| 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; |
| |
| =head1 How can I check if mod_perl is available during configuration? |
| |
| 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> |
| |
| =head1 How can I terminate a chain of handlers? |
| |
| 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; |
| |
| =head1 Why can't my handler see an environment variable that I set in httpd.conf? |
| |
| 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. |
| |
| =head1 Why does the server hang when I try to read a FORM? |
| |
| The C<$r-E<gt>content> method reads C<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'); |
| } |
| # ... |
| } |