—=head1 Apache::* modules
=head1 Apache::Session - Maintain session state across HTTP requests
This module provides the Apache/mod_perl user with a mechanism for
storing persistent user data in a global hash, which is independent of
the underlying storage mechanism. Currently you can choose from these
storage mechanisms C<Apache::Session::DBI>, C<Apache::Session::Win32>,
C<Apache::Session::File>, C<Apache::Session::IPC>. Read the man page
of the mechanism you want to use for a complete reference.
C<Apache::Session> provides persistence to a data structure.
The data structure has an ID number, and you can retrieve it by using
the ID number. In the case of Apache, you would store the ID number in
a cookie or the URL to associate it with one browser, but the method of
dealing with the ID is completely up to you. The flow of things is
generally:
Tie a session to Apache::Session.
Get the ID number.
Store the ID number in a cookie.
End of Request 1.
(time passes)
Get the cookie.
Restore your hash using the ID number in the cookie.
Use whatever data you put in the hash.
End of Request 2.
Using C<Apache::Session> is easy: simply tie a hash to the session
object, stick any data structure into the hash, and the data you put
in automatically persists until the next invocation. Here is a quick
example which uses cookies to track the user's session.
# Pull in the required packages
use Apache::Session::DBI;
use Apache;
use strict;
# Read in the cookie if this is an old session
my $r = Apache->request;
my $cookie = $r->header_in('Cookie');
$cookie =~ s/SESSION_ID=(\w*)/$1/;
# Create a session object based on the cookie we got from the
# browser, or a new session if we got no cookie
my %session;
tie %session, 'Apache::Session::DBI', $cookie,
{DataSource => 'dbi:mysql:sessions',
UserName => $db_user,
Password => $db_pass
};
# Might be a new session, so lets give them their cookie back
my $session_cookie = "SESSION_ID=$session{_session_id};";
$r->header_out("Set-Cookie" => $session_cookie);
After setting this up, you can stick anything you want into %session
(except file handles and code references), and it will still be there
when the user invokes the next page.
It is possible to write an Apache authentication handler using
C<Apache::Session>. You can put your authentication token into the
session. When a user invokes a page, you open their session, check to
see if they have a valid token, and authenticate or forbid based on that.
By way of comparison note that IIS's sessions are only valid on the
same web server as the one that issued the session.
C<Apache::Session>'s session objects can be shared amongst a farm of
many machines running different operating systems, including even
Win32. IIS stores session information in RAM. C<Apache::Session>
stores sessions in databases, file systems, or RAM. IIS's sessions
are only good for storing scalars or arrays. C<Apache::Session>'s
sessions allow you to store arbitrarily complex objects. IIS sets up
the session and automatically tracks it for you. With
C<Apache::Session>, you setup and track the session yourself. IIS is
proprietary. C<Apache::Session> is open-source.
C<Apache::Session::DBI> can issue 400+ session requests per second on
light Celeron 300A running Linux. IIS?
An alternative to C<Apache::Session> is Apache::ASP, which has session
tracking abilities. HTML::Embperl hooks into C<Apache::Session> for
you.
=head1 Apache::DBI - Initiate a persistent database connection
See L<mod_perl and relational
Databases|databases/Apache_DBI_Initiate_a_persist>
=head1 Apache::Watchdog::RunAway - Hanging Processes Monitor and Terminator
This module monitors hanging Apache/mod_perl processes. You define the
time in seconds after which the process is to be counted as I<hanging> or
I<run away>.
When the process is considered to be I<hanging> it will be killed and the
event logged in a log file.
Generally you should use the C<amprapmon> program that is bundled with
this module's distribution package, but you can write your own code
using the module as well. See the I<amprapmon> manpage for more
information about it.
Note that it requires the C<Apache::Scoreboard> module to work.
Referer to the C<Apache::Watchdog::RunAway> manpage for the
configuration details.
=head1 Apache::VMonitor -- Visual System and Apache Server Monitor
C<Apache::VMonitor> is the next generation of
L<mod_status|debug/mod_status>. It provides all the information
mod_status provides and much more.
This module emulates the reporting functions of the top(), mount(),
df() and ifconfig() utilities. There is a special mode for mod_perl
processes. It has visual alert capabilities and a configurable
I<automatic refresh> mode. It provides a Web interface, which can be
used to show or hide all the sections dynamically.
The are two main modes:
=over
=item *
Multi processes mode -- All system processes and information is shown.
=item *
Single process mode -- In-depth information about a single process is shown.
=back
The main advantage of this module is that it reduces the need to
telnet to the machine in order to monitor it. Indeed it provides information
about mod_perl processes that cannot be acquired from telneting to the
machine.
=head3 Configuration
# Configuration in httpd.conf
<Location /sys-monitor>
SetHandler perl-script
PerlHandler Apache::VMonitor
</Location>
# startup file or <Perl> section:
use Apache::VMonitor();
$Apache::VMonitor::Config{BLINKING} = 0; # Blinking is evil
$Apache::VMonitor::Config{REFRESH} = 0;
$Apache::VMonitor::Config{VERBOSE} = 0;
$Apache::VMonitor::Config{SYSTEM} = 1;
$Apache::VMonitor::Config{APACHE} = 1;
$Apache::VMonitor::Config{PROCS} = 1;
$Apache::VMonitor::Config{MOUNT} = 1;
$Apache::VMonitor::Config{FS_USAGE} = 1;
$Apache::VMonitor::Config{NETLOAD} = 1;
@Apache::VMonitor::NETDEVS = qw(lo eth0);
$Apache::VMonitor::PROC_REGEX = join "\|", qw(httpd mysql squid);
More information is available in the module's extensive manpage.
It requires C<Apache::Scoreboard> and C<GTop> to work. C<GTop> in
turn requires the C<libgtop> library but is not available for all
platforms. Visit http://www.home-of-linux.org/gnome/libgtop/ to check whether
your platform/flavor is supported.
=head1 Apache::GTopLimit - Limit Apache httpd processes
This module allows you to kill off Apache processes if they grow
too large or if they share too little of their memory. You can
choose to set up the process size limiter to check the process
size on every request:
The module is thoroughly explained in the sections: "L<Keeping the
Shared Memory Limit|performance/Keeping_the_Shared_Memory_Limit>" and
"L<Limiting the Size of the
Processes|performance/Limiting_the_Size_of_the_Process>"
=head1 Apache::Request (libapreq) - Generic Apache Request Library
This package contains modules for manipulating client request data via
the Apache API with Perl and C. Functionality includes:
=over
=item parsing of application/x-www-form-urlencoded data
=item parsing of multipart/form-data
=item parsing of HTTP Cookies
=back
The Perl modules are simply a thin xs layer on top of libapreq, making
them a lighter and faster alternative to CGI.pm and CGI::Cookie. See
the C<Apache::Request> and C<Apache::Cookie> documentation for more
details and eg/perl/ for examples.
C<Apache::Request> and libapreq are tied tightly to the Apache API,
to which there is no access in a process running under mod_cgi.
(L<Apache::Request|download/Apache_Request>)
=head1 Apache::RequestNotes - Allow Easy, Consistent Access to Cookie and Form Data Across Each Request Phase
C<Apache::RequestNotes> provides a simple interface allowing all
phases of the request cycle access to cookie or form input parameters
in a consistent manner. Behind the scenes, it uses libapreq
L<Apache::Request|modules/Apache_Request_libapreq_Gen>>) functions to
parse request data and puts references to the data in C<pnotes()>.
Once the request is past the PerlInit phase, all other phases can have
access to form input and cookie data without parsing it themselves.
This relieves some strain, especially when the GET or POST data is
required by numerous handlers along the way.
See the C<Apache::RequestNotes> manpage for more information.
=head1 Apache::PerlRun - Run unaltered CGI scripts under mod_perl
See L<Apache::PerlRun - a closer
look|porting/Apache_PerlRun_a_closer_look>.
=head1 Apache::RegistryNG -- Apache::Registry New Generation
C<Apache::RegistryNG> is the same as C<Apache::Registry>, aside from
using filenames instead of URIs for namespaces. It also uses an Object
Oriented interface.
PerlModule Apache::RegistryNG
<Location /perl>
SetHandler perl-script
PerlHandler ApacheRegistryNG->handler
</Location>
C<Apache::RegistryNG> inherits from C<Apache::PerlRun>, but the
handler() is overriden. Aside from the handler(), the rest of
C<Apache::PerlRun> contains all the functionality of
C<Apache::Registry> broken down into several subclass-able methods.
These methods are used by C<Apache::RegistryNG> to implement the exact
same functionality of C<Apache::Registry>, using the
C<Apache::PerlRun> methods.
There is no compelling reason to use C<Apache::RegistryNG> over
C<Apache::Registry>, unless you want to do add or change the
functionality of the existing I<Registry.pm>. For example,
C<Apache::RegistryBB> (Bare-Bones) is another subclass that skips the
stat() call performed by C<Apache::Registry> on each request.
One situation where C<Apache::RegistryNG> may definitely be required
is if you are rewriting URIs (using either mod_rewrite or your own
handler) in certain ways.
For instance if you have a rewrite rule of the form:
XYZ123456.html ==> /perl/foo.pl?p1=XYZ&p2=123456
C<Apache::Registry> loses big, as it recompiles I<foo.pl> for each
unique URL -- C<Apache::RegistryNG> should be used instead.
=head1 Apache::RegistryBB -- Apache::Registry Bare Bones
It works just like C<Apache::Registry>, but does not test the x bit
(-x) only compiles the file once (no stat() call is made per
requsest), skips the OPT_EXECCGI checks and does not C<chdir()> into
the script parent directory. It uses the Object Oriented interface.
Configuration:
PerlModule Apache::RegistryBB
<Location /perl>
SetHandler perl-script
PerlHandler ApacheRegistryBB->handler
</Location>
See L<Apache::RegistryNG|modules/Apache_RegistryNG_Apache_Re> for more
info.
=head1 Apache::OutputChain -- Chain Stacked Perl Handlers
Apache::OutputChain was written as a way of exploring the possibilities
of stacked handlers in mod_perl. It ties STDOUT to an object which
catches the output and makes it easy to build a chain of modules that
work on output data stream.
Examples of modules that are build on this idea are
C<Apache::SSIChain>, C<Apache::GzipChain> and C<Apache::EmbperlChain>
-- the first processes the SSI's in the stream, the second compresses
the output on the fly, the last adds Embperl processing.
The syntax goes like this:
<Files *.html>
SetHandler perl-script
PerlHandler Apache::OutputChain Apache::SSIChain Apache::PassHtml
</Files>
The modules are listed in the reverse order of their execution -- here
the C<Apache::PassHtml> module simply picks a file's content and sends
it to STDOUT ... then it's processed by C<Apache::SSIChain>, which
sends its output to STDOUT again ... then it's processed by
C<Apache::OutputChain>, which finally sends the result to the browser.
An alternative to this approach is C<Apache::Filter>, which has a more
natural "forward" configuration order and is easier to interface with
other modules.
It works with C<Apache::Registry> as well, for example:
Alias /foo /home/httpd/perl/foo
<Location /foo>
SetHandler "perl-script"
Options +ExecCGI
PerlHandler Apache::OutputChain Apache::GzipChain Apache::Registry
</Location>
It's really a regular C<Apache::Registry> setup, except for the added
modules in the PerlHandler line.
(L<Apache::GzipChain|modules/Apache_GzipChain_compress_HTM> allows to
compress the output on the fly.)
=head1 Apache::GzipChain - compress HTML (or anything) in the OutputChain
Have you ever served a huge HTML file (e.g. a file bloated with
JavaScript code) and wondered how could you send it compressed, thus
dramatically cutting down the download times? After all java applets
can be compressed into a jar and benefit from faster download times.
Why can't we do the same with plain ASCII (HTML, JS etc.)? ASCII text
can often be compressed by a factor of 10.
C<Apache::GzipChain> comes to help you with this task. If a client
(browser) understands C<gzip> encoding, this module compresses the
output and sends it downstream. The client decompresses the data upon
receipt and renders the HTML as if it were fetching plain HTML.
For example to compress all html files on the fly, do this:
<Files *.html>
SetHandler perl-script
PerlHandler Apache::OutputChain Apache::GzipChain Apache::PassFile
</Files>
Remember that it will work only if the browser claims to accept
compressed input, by setting the C<Accept-Encoding> header.
C<Apache::GzipChain> keeps a list of user-agents, thus it also looks
at the C<User-Agent> header to check for browsers known to accept
compressed output.
For example if you want to return compressed files which will in
addition pass through the Embperl module, you would write:
<Location /test>
SetHandler perl-script
PerlHandler Apache::OutputChain Apache::GzipChain Apache::EmbperlChain Apache::PassFile
</Location>
Hint: Watch the C<access_log> file to see how many bytes were actually
sent, and compare that with the bytes sent using a regular
configuration.
(See also C<perldoc Apache::GzipChain>).
Notice that the rightmost PerlHandler must be a content producer.
Here we are using C<Apache::PassFile> but you can use any module which
creates output.
=head1 Apache::Filter - Alter the output of previous handlers
META: to be written (actually summarized the info from Apache::Filter
manpage)
=head1 Apache::Gzip - Auto-compress web files with Gzip
Similar to L<Apache::GzipChain|modules/Apache_GzipChain_compress_HTM>
but works with C<Apache::Filter>.
This configuration:
PerlModule Apache::Filter
<Files ~ "*\.html">
SetHandler perl-script
PerlSetVar Filter On
PerlHandler Apache::Gzip
</Files>
will send all the I<*.html> files compressed if the client accepts the
compressed input.
And this one:
PerlModule Apache::Filter
Alias /home/http/perl /perl
<Location /perl>
SetHandler perl-script
PerlSetVar Filter On
PerlHandler Apache::RegistryFilter Apache::Gzip
</Location>
Will compess the output of the C<Apache::Registry> scripts. Yes, you
should write C<Apache::RegistryFilter> and not C<Apache::Registry>.
You can use as many filters as you want:
PerlModule Apache::Filter
<Files ~ "*\.blah">
SetHandler perl-script
PerlSetVar Filter On
PerlHandler Filter1 Filter2 Apache::Gzip
</Files>
You can test that it works by either looking at the size of the
response in the I<access.log> or by telnet:
telnet localhost 8000
Trying 127.0.0.1
Connected to 127.0.0.1
Escape character is '^]'.
GET /perl/test.pl HTTP 1.1
Accept-Encoding: gzip
User-Agent: Mozilla
And you will get the data compressed if configured correctly.
=head1 Apache::PerlVINC - set a different @INC perl-location
With this module you can configure C<@INC> and have modules reloaded
for a given C<Location>. Suppose two versions of C<Apache::Status>
are being hacked on the same server, this fixup handler will simply
C<delete $INC{ $filename }>, unshift the preferred C<PerlINC> path
into C<@INC>, and reload the file with C<require()>:
PerlModule Apache::PerlVINC
<Location /dougm-status>
SetHandler perl-script
PerlHandler Apache::Status
PerlVersionINC On
PerlINC /home/dougm/dev/modperl/lib
PerlFixupHandler Apache::PerlVINC
PerlRequire Apache/Status.pm
</Location>
<Location /other-status>
SetHandler perl-script
PerlHandler Apache::Status
PerlVersionINC On
PerlINC /home/other/current/modperl/lib
PerlFixupHandler Apache::PerlVINC
PerlRequire Apache/Status.pm
</Location>
C<PerlVersionINC On> must come before the C<PerlINC>
statement. C<PerlINC> won't store that path unless C<PerlVersionINC>
is On.
It's important to be aware that a changed C<@INC> is effective only
inside the C<E<lt>LocationE<gt>> or a similar configuration directive.
C<Apache::PerlVINC> subclasses the C<PerlRequire> directive, marking
the file to be reloaded by the fixup handler, using the value of
C<PerlINC> for C<@INC>. That's local to the fixup handler, so you
won't actually see C<@INC> changed in your script.
To address possible issues of namespace clashes during reload, the
handler could call C<$r-E<gt>child_terminate()> so the next server to
load the different versions will have a fresh namespace. This is not
a good idea in a high load environment, of course.
=head1 Apache::LogSTDERR
When Apache's builtin syslog support is used, the stderr stream is
redirected to C</dev/null>. This means that Perl warnings, any
messages from C<die()>, C<croak()>, etc., will also end up in the
black hole. The I<HookStderr> directive will hook the stderr stream
to a file of your choice, the default is shown in this example:
PerlModule Apache::LogSTDERR
HookStderr logs/stderr_log
=head1 Apache::RedirectLogFix
Because of the way mod_perl handles redirects, the status code is
not properly logged. The C<Apache::RedirectLogFix> module works around
that bug until mod_perl can deal with this. All you have to do is to
enable it in the I<httpd.conf> file.
PerlLogHandler Apache::RedirectLogFix
For example, you will have to use it when doing:
$r->status(304);
and do some manual header sending, like this:
$r->status(304);
$r->send_http_header();
=head1 Apache::SubProcess
The output of C<system()>, C<exec()>, and C<open(PIPE,"|program")> calls
will not be sent to the browser unless your Perl was configured with
C<sfio>.
One workaround is to use backticks:
print `command here`;
But a cleaner solution is provided by the C<Apache::SubProcess>
module. It overrides the exec() and system() calls with calls that
work correctly under mod_perl.
Let's see a few examples:
use strict;
use Apache::SubProcess qw(system exec);
my $r = shift;
$r->send_http_header('text/plain');
# override built-in system() function
system "/bin/echo hi there";
# send the output of a program
my $efh = $r->spawn_child(\&env);
$r->send_fd($efh);
# pass arguments to a program and sends its output
my $fh = $r->spawn_child(\&banner);
$r->send_fd($fh);
# pipe data to a program and send its output
use vars qw($String);
$String = "hello world";
my($out, $in, $err) = $r->spawn_child(\&echo);
print $out $String;
$r->send_fd($in);
# override the built-in exec() function
exec "/usr/bin/cal";
print "NOT REACHED\n";
sub env {
my $r = shift;
#$r->subprocess_env->clear;
$r->subprocess_env(HELLO => 'world');
$r->filename("/bin/env");
$r->call_exec;
}
sub banner {
my $r = shift;
# /usr/games/banner on many Unices
$r->filename("/usr/bin/banner");
$r->args("-w40+Hello%20World");
$r->call_exec;
}
sub echo {
my $r = shift;
$r->subprocess_env(CONTENT_LENGTH => length $String);
$r->filename("/tmp/pecho");
$r->call_exec;
}
# where /tmp/pecho is:
# --------------------
#!/usr/bin/perl
#read STDIN, $buf, $ENV{CONTENT_LENGTH};
#print "STDIN: `$buf' ($ENV{CONTENT_LENGTH})\n";
=cut