home | O'Reilly's CD bookshelfs | FreeBSD | Linux | Cisco | Cisco Exam  


Writing Apache Modules with Perl and C
By:   Lincoln Stein and Doug MacEachern
Published:   O'Reilly & Associates, Inc.  - March 1999

Copyright © 1999 by O'Reilly & Associates, Inc.


 


   Show Contents   Previous Page   Next Page

Chapter 7 - Other Request Phases

In this section...

Introduction
The Child Initialization and Exit Phases
The Post Read Request Phase
The URI Translation Phase
The Header Parser Phase
Customizing the Type Checking Phase
Customizing the Fixup Phase
The Logging Phase
Registered Cleanups
Handling Proxy Requests
Perl Server-Side Includes
Subclassing the Apache Class

Introduction

   Show Contents   Go to Top   Previous Page   Next Page

In this Chapter

The previous chapters have taken you on a wide-ranging tour of the most popular and useful areas of the Apache API. But we're not done yet! The Apache API allows you to customize URI translation, logging, the handling of proxy transactions, and the manner in which HTTP headers are parsed. There's even a way to incorporate snippets of Perl code directly into HTML pages that use server-side includes.

We've already shown you how to customize the response, authentication, authorization, and access control phases of the Apache request cycle. Now we'll fill in the cracks. At the end of the chapter, we show you the Perl server-side include system, and demonstrate a technique for extending the Apache Perl API by subclassing the Apache request object itself.

The Child Initialization and Exit Phases

   Show Contents   Go to Top   Previous Page   Next Page

Apache provides hooks into the child process initialization and exit handling. The child process initialization handler, installed with PerlChildInitHandler, is called just after the main server forks off a child but before the child has processed any incoming requests. The child exit handler, installed with PerlChildExitHandler, is called just before the child process is destroyed.

You might need to install handlers for these phases in order to perform some sort of module initialization that won't survive a fork. For example, the Apache::DBI module has a child init handler that initializes a cache of per-child database connections, and the Apache::Resource module steps in during this phase to set up resource limits on the child processes. The latter is configured in this way:

PerlChildInitHandler Apache::Resource

Like other handlers, you can install a child init handler programmatically using Apache::push_handlers(). However, because the child init phase comes so early, the only practical place to do this is from within the parent process, in either a Perl start-up file configured with a PerlModule or PerlRequire directive. For example, here's how to install an anonymous subroutine that will execute during child initialization to choose a truly random seed value for Perl's random number generator (using the Math::TrulyRandom module):

use Math::TrulyRandom ();
Apache->push_handlers(PerlChildInitHandler => sub {
   srand Math::TrulyRandom::truly_random_value();
});

Install this piece of code in the Perl startup file. By changing the value of the random number seed on a per-child basis, it ensures that each child process produces a different sequence of random numbers when the built-in rand() function is called.

The child exit phase complements the child initialization phase. Child processes may exit for various reasons: the MaxRequestsPerChild limit may have been reached, the parent server was shut down, or a fatal error occurred. This phase gives modules a chance to tidy up after themselves before the process exits.

The most straightforward way to install a child exit handler is with the explicit Perl-ChildExitHandler directive, as in:

PerlChildExitHandler Apache::Guillotine

During the child exit phase, mod_perl invokes the Perl API function perl_destruct() to run the contents of END blocks and to invoke the DESTROY method for any global objects that have not gone out of scope already.1 Refer to the section "Special Global Variables, Subroutines, and Literals" in Chapter 9, Perl API Reference Guide, for details.

Note that neither child initialization nor exit hooks are available on Win32 platforms since the Win32 port of Apache uses a single process.

Footnotes

1 perl_destruct() is an internal Perl subroutine that is normally called just once by the Perl executable after a script is run.

The Post Read Request Phase

   Show Contents   Go to Top   Previous Page   Next Page

When a listening server receives an incoming request, it reads the HTTP request line and parses any HTTP headers sent along with it. Provided that what's been read is valid HTTP, Apache gives modules an early chance to step in during the post_read_request phase, known to the Perl API world as the PerlPostReadRequestHandler. This is the very first callback that Apache makes when serving an HTTP request, and it happens even before URI translation turns the requested URI into a physical pathname.

The post_read_request phase is a handy place to initialize per-request data that will be available to other handlers in the request chain. Because of its usefulness as an initialization routine, mod_perl provides the directive PerlInitHandler as a more readable alias to PerlPostReadRequestHandler.

Since the post_read_request phase happens before URI translation, PerlPost-ReadRequestHandler cannot appear in <Location>, <Directory>, or <Files> sections. However, the PerlInitHandler directive is actually a bit special. When it appears outside a <Directory> section, it acts as an alias for PerlPostReadRequestHandler as just described. However, when it appears within a <Directory> section, it acts as an alias for PerlHeaderParserHandler (discussed later in this chapter), allowing for per-directory initialization. In other words, wherever you put Perl-InitHandler, it will act the way you expect.

Several optional Apache modules install handlers for the post_read_request phase. For example, the mod_unique_id module steps in here to create the UNIQUE_ID environment variable. When the module is activated, this variable is unique to each request over an extended period of time and so is useful for logging and the generation of session IDs (see Chapter 5, Maintaining State). Perl scripts can get at the value of this variable by reading $ENV{UNIQUE_ID} or by calling $r->subprocess_env('UNIQUE_ID').

mod_setenvif also steps in during this phase to allow you to set environment variables based on the incoming client headers. For example, this directive will set the environment variable LOCAL_REFERRAL to true if the Referer header matches a certain regular expression:

SetEnvIf Referer \.acme\.com LOCAL_REFERRAL

mod_perl itself uses the post_read_request phase to process the PerlPassEnv and PerlSetEnv directives, allowing environment variables to be passed to modules that execute early in the request cycle. The built-in Apache equivalents, PassEnv and SetEnv, don't get processed until the fixup phase, which may be too late. The Apache::StatINC module, which watches .pm files for changes and reloads them if necessary, is also usually installed into this phase:

PerlPostReadRequestHandler Apache::StatINC
PerlInitHandler Apache::StatINC  # same thing, but easier to type
   Show Contents   Go to Top   Previous Page   Next Page
Copyright © 1999 by O'Reilly & Associates, Inc.