=head1 NAME
Writing mod_perl Handlers and Scripts
=head1 Description
This chapter covers the mod_perl coding specifics, different from
normal Perl coding. Most other perl coding issues are covered in the
perl manpages and rich literature.
=head1 Prerequisites
=head1 Where the Methods Live
mod_perl 2.0 has all its methods spread across many modules. In order
to use these methods the modules containing them have to be loaded
first. If you don't do that mod_perl will complain that it can't find
the methods in question. The module
C> can
be used to find out which modules need to be used.
=head1 Techniques
=head2 Method Handlers
In addition to function handlers method handlers can be used. Method
handlers are useful when you want to write code that takes advantage
of inheritance. To make the handler act as a method under mod_perl 2,
use the C attribute.
See the Perl I manpage for details on the attributes
syntax (C).
For example:
package Bird::Eagle;
@ISA = qw(Bird);
sub handler : method {
my ($class_or_object, $r) = @_;
...;
}
sub new { bless {}, __PACKAGE__ }
and then register it as:
PerlResponseHandler Bird::Eagle
When mod_perl sees that the handler has a method attribute, it passes
two arguments to it: the calling object or a class, depending on how
it was called, and the request object, as shown above.
If Cmethod> syntax is used for a C, e.g.:
PerlResponseHandler Bird::Eagle->handler;
the C<:method> attribute is not required.
In the preceding configuration example, the C method will
be called as a class (static) method.
Also, you can use objects created at startup to call methods. For example:
use Bird::Eagle;
$Bird::Global::object = Bird::Eagle->new();
...
PerlResponseHandler $Bird::Global::object->handler
In this example, the C method will be called as an instance
method on the global object $C.
=head2 Cleaning up
It's possible to arrange for cleanups to happen at the end of various
phases. One can't rely on C blocks to do the job, since these
L until the interpreter quits, with
an exception to the
L handlers.
Module authors needing to run cleanups after each HTTP request, should
use
C>.
Module authors needing to run cleanups at other times can always
register a cleanup callback via
C>
on the pool object of choice. Here are some examples of its usage:
To run something at the server shutdown and restart use a cleanup
handler registered on
C>
in F:
#PerlPostConfigRequire startup.pl
use Apache2::ServerUtil ();
use APR::Pool ();
warn "parent pid is $$\n";
Apache2::ServerUtil::server_shutdown_cleanup_register((\&cleanup);
sub cleanup { warn "server cleanup in $$\n" }
This is usually useful when some server-wide cleanup should be
performed when the server is stopped or restarted.
To run a cleanup at the end of each connection phase, assign a cleanup
callback to the connection pool object:
use Apache2::Connection ();
use APR::Pool ();
my $pool = $c->pool;
$pool->cleanup_register(\&my_cleanup);
sub my_cleanup { ... }
You can also create your own pool object, register a cleanup callback
and it'll be called when the object is destroyed:
use APR::Pool ();
{
my @args = 1..3;
my $pool = APR::Pool->new;
$pool->cleanup_register(\&cleanup, \@args);
}
sub cleanup {
my @args = @{ +shift };
warn "cleanup was called with args: @args";
}
In this example the cleanup callback gets called, when C<$pool> goes
out of scope and gets destroyed. This is very similar to OO C
method.
=head1 Goodies Toolkit
=head2 Environment Variables
mod_perl sets the following environment variables:
=over
=item *
C<$ENV{MOD_PERL}> - is set to the mod_perl version the server is
running under. e.g.:
mod_perl/2.000002
If C<$ENV{MOD_PERL}> doesn't exist, most likely you are not running
under mod_perl.
die "I refuse to work without mod_perl!" unless exists $ENV{MOD_PERL};
However to check which version is used it's better to use the
following technique:
use mod_perl;
use constant MP2 => ( exists $ENV{MOD_PERL_API_VERSION} and
$ENV{MOD_PERL_API_VERSION} >= 2 );
# die "I want mod_perl 2.0!" unless MP2;
=back
mod_perl passes (exports) the following shell environment variables
(if they are set) :
=over
=item *
C - Executables search path.
=item *
C - Time Zone.
=back
Any of these environment variables can be accessed via C<%ENV>.
=head2 Threaded MPM or not?
If the code needs to behave differently depending on whether it's
running under one of the threaded MPMs, or not, the class method
Cis_threaded> can be used. For example:
use Apache2::MPM ();
if (Apache2::MPM->is_threaded) {
require APR::OS;
my $tid = APR::OS::current_thread_id();
print "current thread id: $tid (pid: $$)";
}
else {
print "current process id: $$";
}
This code prints the current thread id if running under a threaded
MPM, otherwise it prints the process id.
=head2 Writing MPM-specific Code
If you write a CPAN module it's a bad idea to write code that won't
run under all MPMs, and developers should strive to write a code that
works with all mpms. However it's perfectly fine to perform different
things under different mpms.
If you don't develop CPAN modules, it's perfectly fine to develop your
project to be run under a specific MPM.
use Apache2::MPM ();
my $mpm = lc Apache2::MPM->show;
if ($mpm eq 'prefork') {
# prefork-specific code
}
elsif ($mpm eq 'worker') {
# worker-specific code
}
elsif ($mpm eq 'winnt') {
# winnt-specific code
}
else {
# others...
}
=head1 Code Developing Nuances
=head2 Auto-Reloading Modified Modules with Apache2::Reload
META: need to port Apache2::Reload notes from the guide here. but the
gist is:
PerlModule Apache2::Reload
PerlInitHandler Apache2::Reload
#PerlPreConnectionHandler Apache2::Reload
PerlSetVar ReloadAll Off
PerlSetVar ReloadModules "ModPerl::* Apache2::*"
Use:
PerlInitHandler Apache2::Reload
if you need to debug HTTP protocol handlers. Use:
PerlPreConnectionHandler Apache2::Reload
for any handlers.
Though notice that we have started to practice the following style in
our modules:
package Apache2::Whatever;
use strict;
use warnings FATAL => 'all';
C 'all'> escalates all warnings into fatal errors. So
when C is modified and reloaded by C
the request is aborted. Therefore if you follow this very healthy
style and want to use C, flex the strictness by
changing it to:
use warnings FATAL => 'all';
no warnings 'redefine';
but you probably still want to get the I warnings, but
downgrade them to be non-fatal. The following will do the trick:
use warnings FATAL => 'all';
no warnings 'redefine';
use warnings 'redefine';
Perl 5.8.0 allows to do all this in one line:
use warnings FATAL => 'all', NONFATAL => 'redefine';
but if your code may be used with older perl versions, you probably
don't want to use this new functionality.
Refer to the I manpage for more information.
=head1 Integration with Apache Issues
In the following sections we discuss the specifics of Apache behavior
relevant to mod_perl developers.
=head2 HTTP Response Headers
=head3 Generating HTTP Response Headers
The best approach for generating HTTP response headers is by using the
L. Some common
headers have dedicated methods, others are set by manipulating the
C>
table directly.
For example to set the I header you should call
Ccontent_type|docs::2.0::api::Apache2::RequestRec/C_content_type_>>:
use Apache2::RequestRec ();
$r->content_type('text/html');
To C> a custom header
I you should call:
use Apache2::RequestRec ();
use APR::Table;
$r->headers_out->set(My-Header => "SomeValue");
If you are inside a registry script L the
C> object.
Howerever you can choose a slower method of generating headers by just
printing them out before printing any response. This will work only if
C> is
in effect. For example:
print "Content-type: text/html\n";
print "My-Header: SomeValue\n";
print "\n";
This method is slower since Apache needs to parse the text to identify
certain headers it needs to know about. It also has several
limitations which we will now discuss.
When using this approach you must make sure that the C
filehandle is not set to flush the data after each print (which is set
by the value of a special perl variable C<$|>). Here we assume that
STDOUT is the currently C