Show Contents Previous Page Next Page Chapter 4 - Content Handlers In this section...
Errors in Apache modules do occur, and tracking them down is significantly trickier than in standalone Perl or C programs. Some errors are due to bugs in your code, while others are due to the unavoidable hazards of running in a networked environment. The remote user might cancel a form submission before it is entirely done, the connection might drop while you're updating a database, or a file that you're trying to access might not exist. A virtuous Apache module must let at least two people know when a problem has occurred: you, the module's author, and the remote user. You can communicate errors and other exception conditions to yourself by writing out entries to the server log. For alerting the user when a problem has occurred, you can take advantage of the simple but flexible Apache ErrorDocument system, use CGI::Carp, or roll your own error handler. Show Contents Go to Top Previous Page Next PageWe talked about tracking down code bugs in Chapter 2 and will talk more about C-language specific debugging in Chapter 10. This section focuses on defensive coding techniques for intercepting and handling other types of runtime errors. The most important rule is to log everything. Log anything unexpected, whether it is a fatal error or a condition that you can work around. Log expected but unusual conditions too, and generate routine logging messages that can help you trace the execution of your module under normal conditions.
Apache versions 1.3 and higher offer To use this adjustable logging API, you must load the standard Apache::Log module. This adds a log() method to the Apache request object, which will return an Apache::Log object. You can then invoke this object's methods in order to write nicely formatted log entries to the server's error log at the priority level you desire. Here's a short example: use Apache::Log (); my $log = $r->log; $log->debug("Trying to lock guestbook file now"); unless (lock($GUESTBOOKFILE,1)) { $log->emerg("Can't get lock!"); return SERVER_ERROR; } $log->debug("Got lock"); In this example, we first obtain a log object by calling the request object's log() method. We call the log object's debug() method to send a debug message to the error log and then try to perform a locking operation. If the operation fails, we log an error message at the emerg priority level using the log object's emerg() method and exit. Otherwise, we log another debugging message. You'll find the full list of method calls made available by Apache::Log in Chapter 9, in the subsection "Logging Methods" under "The Apache Request Object." In addition, the Apache Perl API offers three simpler methods for entering messages into the log file. You don't have to import the Apache::Log module to use these methods, and they're appropriate for smaller projects (such as most of the examples in this book).
access to /usr/local/apache/htdocs/index.html failed for ppp12.yahoo.com, reason: user phyllis not authorized
You might also choose to include a Apache provides a handy ErrorDocument directive that can be used to display a custom page when a handler returns a non-OK status code. The custom page can be any URI, including a remote web page, a local static page, a local server-side include document, or a CGI script or module. In the last three cases, the server generates an internal redirect, making the redirection very efficient. For example, the configuration file for Lincoln's laboratory site contains this directive: ErrorDocument 404 /perl/missing.cgi
When the server encounters a 404 "Not Found" status code, whether generated by a custom module or by the default content handler, it will generate an internal redirect to a
A slightly simplified version of missing.cgi that works with Apache::Registry (as well as a standalone CGI script) is shown in Example 4-16. For a screenshot of what the user gets when requesting a nonexistent URI, see Figure 4-9. Figure 4-9. The missing.cgi script generates a custom page to display when a URI is not found. Example 4-16. A Simple Apache::Registry ErrorDocument Handler #!/usr/local/bin/perl # file: missing.cgi use CGI qw(:standard); use strict; print header, start_html(-title => 'Missing Document', -bgcolor => 'white'), h1(img({-src => '/icons/unknown.gif'}), 'Document Not Found'), p("I'm sorry, but the document you requested,", strong($ENV{REDIRECT_URL}), "is not available. Please try the", a({-href => "/search.html"}, "search page"), "for help locating the document."), hr, address(a({-href => "mailto:$ENV{SERVER_ADMIN}"}, 'webmaster')), end_html; If you want to implement the ErrorDocument handler as a vanilla Apache Perl API script, the various REDIRECT_ environment variables will not be available to you. However, you can get the same information by calling the request object's prev() method. This returns the request object from the original request. You can then query this object to recover the requested URI, the request method, and so forth. Example 4-17 shows a rewritten version of missing.cgi that uses prev() to recover the URI of the missing document. The feature to note in this code is the call to $r->prev on the fifth line of the handler() subroutine. If the handler was invoked as the result of an internal redirection, this call will return the original request object, which we then query for the requested document by calling its uri() method. If the handler was invoked directly (perhaps by the user requesting its URI), the original request will be undefined and we use an empty string for the document URI. Example 4-17. An ErrorDocument Handler Using the Vanilla Apache API package Apache::Missing; # File: Apache/Missing.pm use strict; use Apache::Constants qw(:common); use CGI qw(:html); sub handler { my $r = shift; $r->content_type('text/html'); $r->send_http_header; return OK if $r->header_only; my $original_request = $r->prev; my $original_uri = $original_request ? $original_request->uri : ''; my $admin = $r->server->server_admin; $r->print( start_html(-title => 'Missing Document', -bgcolor => 'white'), h1(img({-src => '/icons/unknown.gif'}), 'Document Not Found'), p( "I'm sorry, but the document you requested,", strong($original_uri), ", is not available. Please try the", a({-href => "/search.html"}, "search page"), "for help locating the document." ), hr, address(a({-href => "mailto:$admin"}, 'webmaster')), end_html ); return OK; } 1; __END__
Here's an example using <Location /Missing> SetHandler perl-script PerlHandler Apache::Missing </Location> If the static nature of the Apache ErrorDocument directive is inadequate for your needs, you can set the error document dynamically from within a handler by calling the request object's custom_response() method. This method takes two arguments: the status code of the response you want to handle and the URI of the document or module that you want to pass control to. This error document setting will persist for the lifetime of the current request only. After the handler exits, the setting returns to its default.
For example, the following code snippet sets up a custom error handler for the package Apache::GoFish; # file: Apache/GoFish.pm use strict; use Apache::Constants qw(:common); sub handler { my $r = shift; if (things_are_ok($r)) { do_something(); return OK; } $r->custom_response(SERVER_ERROR, "/Carp"); return SERVER_ERROR; } 1; __END__Show Contents Go to Top Previous Page Next Page Copyright © 1999 by O'Reilly & Associates, Inc. |
HIVE: All information for read only. Please respect copyright! |