Show Contents Previous Page Next Page
Appendix A - Standard Noncore Modules In this section... Introduction Show Contents Go to Top Previous Page Next Page In This Appendix The mod_perl distribution comes with a number of helper classes that
add specialized functionality to the package. None of them are essential to
write Apache modules in the Perl API or have any equivalent in the C-language
API, but they can be very handy at times. The Apache::Registry Class Show Contents Go to Top Previous Page Next Page The Apache::Registry class is essentially a CGI environment emulator
that allows many CGI scripts to run without modification under mod_perl.
Because there are many differences between CGI and the Apache API, Apache::Registry
has to do a great deal of work to accomplish this sleight of hand. It loads
the scripts in its designated directory, compiles them, and stores them persistently
in a memory structure. Before Apache::Registry runs a script, mod_perl
will set up the various CGI environment variables, provided PerlSetupEnv
is configured to On, which is the default. When the PerlSendHeader
directive is On, mod_perl monitors the text printed by
the script, intercepts the HTTP header, and passes it through send_cgi_header().
It also arranges for STDIN to be read from the request object when the script
attempts to process POST data. Apache::Registry also monitors
the modification dates of the script files it is responsible for and reloads
them if their timestamp indicates they have been changed more recently than
when they were last compiled. Despite its complexity, Apache::Registry is easy to set up. The standard
configuration consists of an Alias directive and a <Location>
section:
Alias /perl/ /home/www/perl
<Location /perl>
SetHandler perl-script
PerlHandler Apache::Registry
Options +ExecCGI
# optional
PerlSendHeader On
</Location>
After restarting the server, you can place any (well, almost any) Perl CGI
script into /home/www/perl (or the location of your choice) and make
it executable. It runs just like an ordinary CGI script but will load much faster.
The behavior of Apache::Registry can be tuned with the following
directives: PerlTaintCheck
When set to On, mod_perl will activate Perl taint checks
on all the scripts under its control. Taint checks cause Perl to die with
a fatal error if unchecked user-provided data (such as the values of CGI variables)
is passed to a potentially dangerous function, such as exec(), eval(),
or system().
PerlSendHeader
When set to On, mod_perl will scan for script output that
looks like an HTTP header and automatically call send_http_header().
Scripts that send header information using CGI. pm's header() function
do not need to activate PerlSendHeader. While scripts that use CGI.pm's
header() will still function properly with PerlSendHeader On,
turning it Off will save a few CPU cycles.
PerlFreshRestart
If PerlFreshRestart is set to On, mod_perl will
flush its cache and reload all scripts when the server is restarted. This
is very useful during module development to immediately see the changes to
the source code take effect.
PerlWarn
If the script mentions the -w switch on its #! line,
Apache::Registry will turn Perl warnings on by setting the $^W
global to a nonzero value. The Perl-Warn directive can be configured
to On to turn on warnings for all code inside the server.
Apache::Registry has several debug levels which write various informational
messages to the server error log. Apache::Registry scripts can change
the debug level by importing Apache::Debug with its level
pragma:
use Apache::Debug level => $level;
The debug level is a bit mask generated by ORing together some combination
of the following values: 1 | Make a note in the error log whenever the module is recompiled | 2 | Call Apache::Debug::dump() on errors | 4 | Turn on verbose tracing |
The current value of the debug level can be found in the package global $Apache::Registry::Debug .
You should not set this value directly, however. See Chapter 2,
A First Module, for more hints on debugging Apache::Registry
scripts. The Apache::PerlRun Class Show Contents Go to Top Previous Page Next Page The Apache::PerlRun handler is intended for Perl CGI scripts that
depend strongly on the traditional one-process-per-execution CGI model and cannot
deal with being invoked repeatedly in the same process. For example, a script
that depends on a lot of global variables being uninitialized when it starts
up is unlikely to work properly under Apache::Registry. Like Apache::Registry, Apache::PerlRun manages a directory
of CGI scripts, launching them when they are requested. However, unlike Apache::Registry,
this module does not cache compiled scripts between runs. A script is loaded
and compiled freshly each time it is requested. However, Apache::PerlRun
still avoids the overhead of starting a new Perl interpreter for each CGI script,
so it's faster than traditional Perl CGI scripting but slower than Apache::Registry
or vanilla Apache API modules. It offers a possible upgrade path for CGI scripts:
move the script to Apache::PerlRun initially to get a modest performance
bump. This gives you time to rework the script to make it globally clean so
that it can run under Apache::Registry for the full performance benefit.
The configuration section for running Apache::PerlRun is similar
to Apache::Registry:
Alias /perl-run/ /home/www/perl-run/
<Location /perl>
SetHandler perl-script
PerlHandler Apache::PerlRun
Options +ExecCGI
# optional
PerlSendHeader On
</Location>
The Apache::PerlRun handler is only a small part of the picture.
The rest of the Apache::PerlRun class provides subclassable methods
that implement the functionality of Apache::Registry. The Apache::PerlRun
handler simply uses a subset of these methods; other modules may override certain
methods to implement the Apache::Registry enviroment with a few twists.
However, these Apache::PerlRun class methods were not fully defined
when this book was going to press. The Apache::RegistryLoader Class Show Contents Go to Top Previous Page Next Page Ordinarily, Apache::Registry scripts are not compiled until they
are needed. This means that the very first time one of these scripts is required
by a child process, there will be a delay while the script is loaded and compiled.
Apache::RegistryLoader was designed to avoid this delay by precompiling
Apache::Registry scripts during the server startup phase. In addition
to minimizing loading time, it also reduces memory consumption because the Registry
scripts are compiled into the single server parent process before it
forks off the flock of child servers. The memory occupied by this precompiled
code is then shared among the children, and although there doesn't appear to
be a difference in child process size when you invoke ps (on Unix systems),
overall memory consumption is reduced. See the mod_perl_tuning document
in the mod_perl distribution for more details. Typically, you will invoke Apache::RegistryLoader from a Perl startup
script. A typical entry looks like this:
#!/usr/local/bin/perl
use MyFavoriteModule1 ();
use MyFavoriteModule2 ();
...
use Apache::RegistryLoader ();
my $rl = Apache::RegistryLoader->new;
$rl->handler('/perl/test.pl'=> '/home/www/perl/test.pl');
$rl->handler('/perl/test2.pl'=> '/home/www/perl/test2.pl');
...
This code creates a new Apache::RegistryLoader object by invoking the class's new() method and then calls this object's handler() method for each script you want to load. Apache::RegistryLoader is actually a subclass of Apache::Registry which overrides certain methods such that the Apache::RegistryLoader handler() method only invokes the script compliation and caching methods of Apache::Registry.
Notice that handler() requires two arguments: the URI of the script
to compile and its physical pathname. The reason you can't just provide one
or the other is that the task of translating from a URI to a filename is usually
done at request time by a translation handler. However, at server startup time
there's no request to process, and therefore no way of getting at the translation
handler. If you specify a URI only, Apache::RegistryLoader will try to interpret
it relative to the server root. This will work only if the Apache::Registry
directory URI is aliased to an identically named physical directory beneath
the server root. Here's an example:
# in httpd.conf
ServerRoot /home/www
Alias /perl/ /home/www/perl/
# in Perl startup script
use Apache::RegistryLoader ();
Apache::RegistryLoader->new->handler("/perl/test.pl");
Another solution is to provide a URI translation routine to the new()
method at the time you create the Apache::RegistryLoader object. The
Apache translation handlers can only be run during request time, so we must
roll our own during start-up. The translation handler will take an argument
consisting of the script URI and return the translated physical pathname to
the file as its function result. The following code fragment illustrates how
to precompile all .pl files in the directory ~www/perl/:
# in perl.conf (or any other configuration file)
PerlRequire conf/preload_scripts.pl
# in conf/preload_scripts.pl
#!/usr/local/bin/perl
use Apache::RegistryLoader ();
use DirHandle ();
use strict;
sub do_translate {
my $uri = shift;
return Apache->server_root_relative($uri);
};
my $rl = Apache::RegistryLoader->new(trans => \&do_translate);
my $dir = Apache->server_root_relative("perl/");
my $dh = DirHandle->new($dir) or die $!;
foreach my $file ($dh->read) {
next unless $file =~ /\.pl$/;
$rl->handler("/perl/$file");
}
Show Contents Go to Top Previous Page Next Page Copyright © 1999 by O'Reilly & Associates, Inc. |