The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

Introducing mod_perl Handlers

Description

This chapter provides an introduction into mod_perl handlers.

What are Handlers?

Apache distinguishes between numerous phases for which it provides hooks (because the C functions are called ap_hook_<phase_name>) where modules can plug various callbacks to extend and alter the default behavior of the webserver. mod_perl provides a Perl interface for most of the available hooks, so mod_perl modules writers can change the Apache behavior in Perl. These callbacks are usually referred to as handlers and therefore the configuration directives for the mod_perl handlers look like: PerlFooHandler, where Foo is one of the handler names. For example PerlResponseHandler configures the response callback.

A typical handler is simply a perl package with a handler subroutine. For example:

  file:MyApache/CurrentTime.pm
  ----------------------------
  package MyApache::CurrentTime;
  
  use strict;
  use warnings;
  
  use Apache::RequestRec ();
  use Apache::RequestIO ();
  
  use Apache::Const -compile => qw(OK);
  
  sub handler {
      my $r = shift;
  
      $r->content_type('text/plain');
      $r->print("Now is: " . scalar(localtime) . "\n");
  
      return Apache::OK;
  }
  1;

This handler simply returns the current date and time as a response.

Since this is a response handler, we configure it as a such in httpd.conf:

  PerlResponseHandler MyApache::CurrentTime

Since the response handler should be configured for a specific location, let's write a complete configuration section:

  PerlModule MyApache::CurrentTime
  <Location /time>
      SetHandler modperl
      PerlResponseHandler MyApache::CurrentTime
  </Location>

Now when a request is issued to http://localhost/time this response handler is executed and a response that includes the current time is returned to the client.

mod_perl Handlers Categories

The mod_perl handlers can be divided by their application scope in several categories:

Bucket Brigades

Apache 2.0 allows multiple modules to filter both the request and the response. Now one module can pipe its output as an input to another module as if another module was receiving the data directly from the TCP stream. The same mechanism works with the generated response.

With I/O filtering in place, simple filters, like data compression and decompression, can be easily implemented and complex filters, like SSL, are now possible without needing to modify the the server code which was the case with Apache 1.3.

In order to make the filtering mechanism efficient and avoid unnecessary copying, the Bucket Brigades technology was introduced.

A bucket represents a chunk of data. Buckets linked together comprise a brigade. Each bucket in a brigade can be modified, removed and replaced with another bucket. The goal is to minimize the data copying where possible. Buckets come in different types, such as files, data blocks, end of stream indicators, pools, etc. To manipulate a bucket one doesn't need to know its internal representation.

The stream of data is represented by bucket brigades. When a filter is called it gets passed the brigade that was the output of the previous filter. This brigade is then manipulated by the filter (e.g., by modifying some buckets) and passed to the next filter in the stack.

The following figure depicts an imaginary bucket brigade:

bucket brigades

The figure tries to show that after the presented bucket brigade has passed through several filters some buckets were removed, some modified and some added. Of course the handler that gets the brigade cannot tell the history of the brigade, it can only see the existing buckets in the brigade.

Bucket brigades are discussed in detail in the connection protocols and I/O filtering chapters.

Single Phase's Multiple Handlers Behavior

For each phase there can be more than one handler assigned (also known as hooks, because the C functions are called ap_hook_<phase_name>). Phases' behavior varies when there is more then one handler registered to run for the same phase. The following table specifies each handler's behavior in this situation:

    Directive                   Type
  --------------------------------------
  PerlOpenLogsHandler          RUN_ALL
  PerlPostConfigHandler        RUN_ALL
  PerlChildInitHandler         VOID
  PerlChildExitHandler         XXX
  
  PerlPreConnectionHandler     RUN_ALL
  PerlProcessConnectionHandler RUN_FIRST
  
  PerlPostReadRequestHandler   RUN_ALL
  PerlTransHandler             RUN_FIRST
  PerlInitHandler              RUN_ALL
  PerlHeaderParserHandler      RUN_ALL
  PerlAccessHandler            RUN_ALL
  PerlAuthenHandler            RUN_FIRST
  PerlAuthzHandler             RUN_FIRST
  PerlTypeHandler              RUN_FIRST
  PerlFixupHandler             RUN_ALL
  PerlResponseHandler          RUN_FIRST
  PerlLogHandler               RUN_ALL
  PerlCleanupHandler           XXX
  
  PerlInputFilterHandler       VOID
  PerlOutputFilterHandler      VOID

And here is the description of the possible types:

  • VOID

    Handlers of the type VOID will be all executed in the order they have been registered disregarding their return values. Though in mod_perl they are expected to return Apache::OK.

  • RUN_FIRST

    Handlers of the type RUN_FIRST will be executed in the order they have been registered until the first handler that returns something other than Apache::DECLINED. If the return value is Apache::DECLINED, the next handler in the chain will be run. If the return value is Apache::OK the next phase will start. In all other cases the execution will be aborted.

  • RUN_ALL

    Handlers of the type RUN_ALL will be executed in the order they have been registered until the first handler that returns something other than Apache::OK or Apache::DECLINED.

For C API declarations see include/ap_config.h, which includes other types which aren't exposed by mod_perl handlers.

Also see mod_perl Directives Argument Types and Allowed Location

Hook Ordering (Position)

The following constants specify how the new hooks (handlers) are inserted into the list of hooks when there is at least one hook already registered for the same phase.

META: need to verify the following:

  • APR::HOOK_REALLY_FIRST

    run this hook first, before ANYTHING.

  • APR::HOOK_FIRST

    run this hook first.

  • APR::HOOK_MIDDLE

    run this hook somewhere.

  • APR::HOOK_LAST

    run this hook after every other hook which is defined.

  • APR::HOOK_REALLY_LAST

    run this hook last, after EVERYTHING.

META: more information in mod_example.c talking about position/predecessors, etc.

Maintainers

Maintainer is the person(s) you should contact with updates, corrections and patches.

  • Stas Bekman <stas (at) stason.org>

Authors

Only the major authors are listed above. For contributors see the Changes file.

1 POD Error

The following errors were encountered while parsing the POD:

Around line 199:

alternative text 'I/O filtering' contains non-escaped | or /