Show Contents Previous Page Next Page
Chapter 4 - Content Handlers Chaining Content Handlers In this section... Introduction Show Contents Go to Top Previous Page Next Page
The C-language Apache API only allows a single content handler to completely process a request. Several handlers may be given a shot at it, but the first one to return an OK status will terminate the content handling phase of the transaction.
There are times when it would be nice to chain handlers into a pipeline. For
example, one handler could add canned headers and footers to the page, another
could correct spelling errors, while a third could add trademark symbols to
all proprietary names. Although the native C API can't do this yet,3
the Perl API can, using a technique called "stacked handlers."
It is actually quite simple to stack handlers. Instead of declaring a single module or subroutine in the PerlHandler directive, you declare several. Each handler will be called in turn in the order in which it was declared. The exception to this rule is if one of the handlers in the series returns an error code (anything other than OK , DECLINED , or DONE ). Handlers can adjust the stacking order themselves, or even arrange to process each other's output.
Simple Case of Stacked Handlers Show Contents Go to Top Previous Page Next Page Example 4-20 gives a very simple example of
a stack of three content handlers. It's adapted slightly from the mod_perl
manual page. For simplicity, all three handlers are defined in the same file,
and are subroutines named header(), body(), and footer().
As the names imply, the first handler is responsible for the top of the page
(including the HTTP header), the second is responsible for the middle, and the
third for the bottom.
A suitable configuration section looks like this:
PerlModule My
<Location /My>
SetHandler perl-script
PerlHandler My::header My::body My::footer
</Location>
We first load the whole module into memory using the PerlModule directive. We then declare a URI location /My and assign the perl-script handler to it. Perl in turn is configured to run the My::header, My::body, and My::footer subroutines by passing them as arguments to a PerlHandler directive. In this case, the /My location has no corresponding physical directory, but there's no reason that it couldn't.
After bringing in the OK constant from Apache::Constants, we define the subroutines header(), body(), and footer(). header() sets the document's content type to plain text, sends the HTTP header, and prints out a line at the top of the document. body() and footer() both print out a line of text to identify themselves. The resulting page looks like this:
header text
body text
footer text Example 4-20.A Simple Stacked Handler package My;
use strict;
use Apache::Constants 'OK';
sub header {
my $r = shift;
$r->content_type('text/plain');
$r->send_http_header;
$r->print("header text\n");
OK;
}
sub body {
my $r = shift;
$r->print("body text\n");
OK;
}
sub footer {
my $r = shift;
$r->print("footer text\n");
OK;
}
1;
Coordinating Stacked Handlers Show Contents Go to Top Previous Page Next Page
Stacked handlers often have to coordinate their activities. In the example of the previous section, the header() handler must be run before either of the other two in order for the HTTP header to come out correctly. Sometimes it's useful to make the first handler responsible for coordinating the other routines rather than relying on the configuration file. The request object's push_handlers() method will help you do this.
push_handlers() takes two arguments: a string representing the phase to handle, and a reference to a subroutine to handle that phase. For example, this code fragment will arrange for the footer() subroutine to be the next content handler invoked:
$r->push_handlers(PerlHandler => \&footer);
With this technique, we can rewrite the previous example along the lines shown
in Example 4-21. In the revised module, we declare
a subroutine named handler() that calls push_handlers() three
times, once each for the header, body, and footer of the document. It then exits.
The other routines are unchanged.
The revised configuration file entry looks like this:
<Location /MyChain>
SetHandler perl-script
PerlHandler My::Chain
</Location>
Because we followed the mod_perl convention of naming the first handler subroutine handler(), there's now no need for a PerlModule statement to load the module into memory.
Example 4-21. Coordinated Stacked
Handlers
package My::Chain;
use strict;
use Apache::Constants 'OK';
sub handler {
my $r = shift;
for my $cv (\&header, \&body, \&footer) { $r->push_handlers(PerlHandler => $cv);
}
OK;
}
sub header {
my $r = shift;
$r->content_type('text/plain');
$r->send_http_header;
$r->print("header text\n");
OK;
}
sub body {
my $r = shift;
$r->print("body text\n");
OK;
}
sub footer {
my $r = shift;
$r->print("footer text\n");
OK;
} 1;
__END__
Show Contents Go to Top Previous Page Next Page Copyright © 1999 by O'Reilly & Associates, Inc. |