Imagine a complex server setup in which many different Perl and non-Perl handlers participate in the request processing, and one or more of these handlers misbehaves. A simple example is one where one of the handlers alters the request record, which breaks the functionality of other handlers. Or maybe a handler invoked first for any given phase of the process returns an unexpected OKstatus, thus preventing other handlers from doing their job. You can't just add debug statements to trace the offender—there are too many handlers involved.

The simplest solution is to get a trace of all registered handlers for each phase, stating whether they were invoked and what their return statuses were. Once such a trace is available, it's much easier to look only at the players that actually participated, thus narrowing the search path down a potentially misbehaving module.

The Apache::ShowRequest module shows the phases the request goes through, displaying module participation and response codes for each phase. The content response phase is not run, but possible modules are listed as defined. To configure it, just add this snippet to httpd.conf:

<Location /showrequest>
    SetHandler perl-script
    PerlHandler +Apache::ShowRequest
</Location>

To see what happens when you access some URI, add the URI to /showrequest. Apache::ShowRequest uses PATH_INFO to obtain the URI that should be executed. So, to run /index.html with Apache::ShowRequest, issue a request for /showrequest/index.html. For /perl/test.pl, issue a request for /showrequest/perl/test.pl.

This module produces rather lengthy output, so we will show only one section from the report generated while requesting /showrequest/index.html:

Running request for /index.html
Request phase: post_read_request
  [snip]
Request phase: translate_handler
   mod_perl ....................DECLINED
   mod_setenvif ................undef
   mod_auth ....................undef
   mod_access ..................undef
   mod_alias ...................DECLINED
   mod_userdir .................DECLINED
   mod_actions .................undef
   mod_imap ....................undef
   mod_asis ....................undef
   mod_cgi .....................undef
   mod_dir .....................undef
   mod_autoindex ...............undef
   mod_include .................undef
   mod_info ....................undef
   mod_status ..................undef
   mod_negotiation .............undef
   mod_mime ....................undef
   mod_log_config ..............undef
   mod_env .....................undef
   http_core ...................OK
Request phase: header_parser
  [snip]
Request phase: access_checker
  [snip]
Request phase: check_user_id
  [snip]
Request phase: auth_checker
  [snip]
Request phase: type_checker
  [snip]
Request phase: fixer_upper
  [snip]
Request phase: response handler (type: text/html)
   mod_actions .................defined
   mod_include .................defined
   http_core ...................defined
Request phase: logger
  [snip]

For each stage, we get a report of what modules could participate in the processing and whether they took any action. As you can see, the content response phase is not run, but possible modules are listed as defined. If we run a mod_perl script, the response phase looks like:

Request phase: response handler (type: perl-script)
   mod_perl ....................defined