=head1 NAME

Mod_perl_api - accessing the Apache API via mod_perl ($Date: 2000/03/05 11:57:55 $)

=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');
    	}
        # ...
    }
