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 9 - Perl API Reference Guide / The Apache Request Object
mod_perl-Specific Methods

There are a handful of Perl API methods for which there is no C-language counterpart. Those who are only interested in learning the C API can skip this section.

exit()

It is common to come across Perl CGI scripts that use the Perl built-in exit() function to leave the script prematurely. Calling exit() from within a CGI script, which owns its process, is harmless, but calling exit() from within mod_perl would have the unfortunate effect of making the entire child process exit unceremoniously, in most cases before completing the request or logging the transaction. On Win32 systems, calling exit() will make the whole server quit. Oops!

For this reason mod_perl's version of this function call, Apache::exit(), does not cause the process to exit. Instead, it calls Perl's croak() function to halt script execution but does not log a message to the ErrorLog. If you really want the child server process to exit, call Apache::exit() with an optional status argument of DONE (available in Apache::Constants). The child process will be shut down but only after it has had a chance to properly finish handling the current requests.

In scripts running under Apache::Registry, Perl's built-in exit() is overridden by Apache::exit() so that legacy CGI scripts don't inadvertently shoot themselves in the foot. In Perl Versions 5.005 and higher, exit() is overridden everywhere, including within handlers. In versions of mod_perl built with Perl 5.004, however, handlers can still inadvertently invoke the built-in exit(), so you should be on the watch for this mistake. One way to avoid it is to explicitly import the exit symbol when you load the Apache module.

Here are various examples of exit():

$r->exit;
Apache->exit;
$r->exit(0);
$r->exit(DONE);
use Apache 'exit';  #this override's Perl's builtin
exit;

If a handler needs direct access to the Perl built-in version of exit() after it has imported Apache's version, it should call CORE::exit().

gensym()

This function creates an anonymous glob and returns a reference to it for use as a safe file or directory handle. Ordinary bareword filehandles are prone to namespace clashes. The IO::File class avoids this, but some users have found that the IO::File carries too much overhead. Apache::gensym avoids this overhead and still avoids namespace clashes.

my $fh = Apache->gensym;
open $fh, $r->filename or die $!;
$r->send_fd($fh);
close $fh;

Because of its cleanliness, most of the examples in this book use the Apache::File interface for reading and writing files (see "The Apache::File Class"). If you wish to squeeze out a bit of overhead, you may wish to use Apache::gensym() with Perl's built-in open() function instead.

current_callback()

If a module wishes to know what handler is currently being run, it can find out with the current_callback() method. This method is most useful to Perl-DispatchHandlers who wish to only take action for certain phases.

if($r->current_callback eq "PerlLogHandler") {
   $r->warn("Logging request");
}

get_handlers()

The get_handlers() method will return an array reference containing the list of all handlers that are configured to handle the current request. This method takes a single argument specifying which handlers to return.

my $handlers = $r->get_handlers('PerlAuthenHandler');

set_handlers()

If you would like to change the list of Perl handlers configured for the current request, you can change it with set_handlers(). This method takes two arguments; the name of the handler you wish to change and an array reference pointing to one or more references to the handler subroutines you want to run for that phase. If any handlers were previously defined, such as with a Perl*Handler directive, they are replaced by this call. Provide a second argument of undef to remove all handlers for that phase.

$r->set_handlers(PerlAuthenHandler => [\&auth_one, \&auth_two]);
$r->set_handlers(PerlAuthenHandler => undef);

push_handlers()

The push_handlers() method is used to add a new Perl handler routine to the current request's handler "stack". Instead of replacing the list of handlers, it just appends a new handler to the list. Each handler is run in turn until one returns an error code. You'll find more information about using stacked handlers and examples in Chapters 4, 6, and 7.

This method takes two arguments: the name of the phase you want to manipulate and a reference to the subroutine you want to handle that phase.

Example:

$r->push_handlers(PerlLogHandler => \&my_logger);

module()

If you need to find out if a Perl module has already been loaded, the module() method will tell you. Pass it the package name of the module you're interested in. It will return a true value if the module is loaded.

do { #something } if Apache->module('My::Module');

This method can also be used to test if a C module is loaded. In this case, pass it the filename of the module, just as you would use with the IfModule directive. It will return a true value if the module is loaded.

do { #something } if Apache->module('mod_proxy.c');   

define()

Apache Version 1.3.1 added a -D command-line switch that can be used to pass the server parameter names for conditional configuration with the IfDefine directive. These names exist for the lifetime of the server and can be accessed at any time by Perl modules using the define() method.

if(Apache->define("SSL")) {
   #the server was started with -DSSL
}

post_connection()

This method is simply an alias for the register_cleanup() method described in the "Server Core Functions" section.

request()

The Apache->request() class method returns a reference to the current request object, if any. Handlers that use the vanilla Perl API will not need to call this method because the request object is passed to them in their argument list. However, Apache::Registry scripts and plain Perl modules do not have a subroutine entry point and therefore need a way to gain access to the request object. For example, CGI.pm uses this method to provide proper mod_perl support.

Called with no arguments, request() returns the stored Apache request object. It may also be called with a single argument to set the stored request object. This is what Apache::Registry does before invoking a script.

my $r = Apache->request;  # get the request
Apache->request($r);      # set the request

Actually, it's a little known fact that Apache::Registry scripts can access the request object directly via @_. This is slightly faster than using Apache->request() but has the disadvantage of being obscure. This technique is demonstrated in "Subclassing the Apache Class" in Chapter 7.

httpd_conf()

The httpd_conf() method allows you to pass new directives to Apache at start-up time. Pass it a multiline string containing the configuration directives that you wish Apache to process. Using string interpolation, you can use this method to dynamically configure Apache according to arbitrarily complex rules.

httpd_conf() can only be called during server startup, usually from within a Perl startup file. Because there is no request method at this time, you must invoke httpd_conf() directly through the Apache class.

my $ServerRoot = '/local/web';
Apache->httpd_conf(<<EOF);
Alias /perl $ServerRoot/perl
Alias /cgi-bin $ServerRoot/cgi-bin
EOF

Should a syntax error occur, Apache will log an error and the server will exit, just as it would if the error was present in the httpd.conf configuration file. A more sophisticated way of configuring Apache at startup time via <Perl> sections is discussed in Chapter 8, Customizing the Apache Configuration Process.

Footnotes

1 As of this writing, HTTP/1.1 requests that do not have a Content-length header, such as those that use chunked encoding, are not properly handled by this API.

2 In case you were wondering, the epoch began at 00:00:00 GMT on January 1, 1970, and is due to end in 2038. There's probably a good explanation for this choice.

3 If you are wondering why this method has an r prefix, it is carried over from the C API I/O methods (described in Chapter 10), all of which have an ap_r prefix. This is the only I/O method from the group for which there is a direct Perl interface. If you find that the r prefix is not pleasing to the eye, this is no accident. It is intended to discourage the use of rflush() due to the performance implications.

4 In fact, the log-level API now provides direct syslog support. See the Apache documentation for the ErrorLog directive, which explains how to enable logging via syslog.

   Show Contents   Previous Page   Next Page
Copyright © 1999 by O'Reilly & Associates, Inc.