O'Reilly logo

Practical mod_perl by Eric Cholet, Stas Bekman

Stay ahead with the world's most comprehensive technology and business learning platform.

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, tutorials, and more.

Start Free Trial

No credit card required

Configuring mod_perl 2.0

Similar to mod_perl 1.0, in order to use mod_perl 2.0 a few configuration settings should be added to httpd.conf. They are quite similar to the 1.0 settings, but some directives were renamed and new directives were added.

Enabling mod_perl

To enable mod_perl as a DSO, add this to httpd.conf:

LoadModule perl_module modules/mod_perl.so

This setting specifies the location of the mod_perl module relative to the ServerRoot setting, so you should put it somewhere after ServerRoot is specified.

Win32 users need to make sure that the path to the Perl binary (e.g., C:\Perl\bin) is in the PATH environment variable. You could also add the directive:

LoadFile "/Path/to/your/Perl/bin/perl5x.dll"

to httpd.conf to load your Perl DLL, before loading mod_perl.so.

Accessing the mod_perl 2.0 Modules

To prevent you from inadvertently loading mod_perl 1.0 modules, mod_perl 2.0 Perl modules are installed into dedicated directories under Apache2/. The Apache2 module prepends the locations of the mod_perl 2.0 libraries to @INC: @INC is the same as the core @INC, but with Apache2/ prepended. This module has to be loaded just after mod_perl has been enabled. This can be accomplished with:

use Apache2 ( );

in the startup file. If you don't use a startup file, you can add:

PerlModule Apache2

to httpd.conf, due to the order in which the PerlRequire and PerlModule directives are processed.

Startup File

Next, a startup file with Perl code usually is loaded:

PerlRequire "/home/httpd/httpd-2.0/perl/startup.pl"

It's used to adjust Perl module search paths in @INC, preload commonly used modules, precompile constants, etc. A typical startup.pl file for mod_perl 2.0 is shown in Example 24-1.

Example 24-1. startup.pl

use Apache2 ( );

use lib qw(/home/httpd/perl);

# enable if the mod_perl 1.0 compatibility is needed
# use Apache::compat ( );

# preload all mp2 modules
# use ModPerl::MethodLookup;
# ModPerl::MethodLookup::preload_all_modules( );

use ModPerl::Util ( ); #for CORE::GLOBAL::exit

use Apache::RequestRec ( );
use Apache::RequestIO ( );
use Apache::RequestUtil ( );

use Apache::Server ( );
use Apache::ServerUtil ( );
use Apache::Connection ( );
use Apache::Log ( );

use APR::Table ( );

use ModPerl::Registry ( );

use Apache::Const -compile => ':common';
use APR::Const -compile => ':common';

1;

In this file the Apache2 module is loaded, so the 2.0 modules will be found. Afterwards, @INC is adjusted to include nonstandard directories with Perl modules:

use lib qw(/home/httpd/perl);

If you need to use the backward-compatibility layer, to get 1.0 modules that haven't yet been ported to work with mod_perl 2.0, load Apache::compat:

use Apache::compat ( );

Next, preload the commonly used mod_perl 2.0 modules and precompile the common constants. You can preload all mod_perl 2.0 modules by uncommenting the following two lines:

use ModPerl::MethodLookup;
ModPerl::MethodLookup::preload_all_modules( );

Finally, the startup.pl file must be terminated with 1;.

Perl's Command-Line Switches

Now you can pass Perl's command-line switches in httpd.conf by using the PerlSwitches directive, instead of using complicated workarounds.

For example, to enable warnings and taint checking, add:

PerlSwitches -wT

The -I command-line switch can be used to adjust @INC values:

PerlSwitches -I/home/stas/modperl

For example, you can use that technique to set different @INC values for different virtual hosts, as we will see later.

mod_perl 2.0 Core Handlers

mod_perl 2.0 provides two types of core handlers: modperl and perl-script.

modperl

modperl is configured as:

SetHandler modperl

This is the bare mod_perl handler type, which just calls the Perl*Handler's callback function. If you don't need the features provided by the perl-script handler, with the modperl handler, you can gain even more performance. (This handler isn't available in mod_perl 1.0.)

Unless the Perl*Handler callback running under the modperl handler is configured with:

PerlOptions +SetupEnv

or calls:

$r->subprocess_env;

in a void context (which has the same effect as PerlOptions +SetupEnv for the handler that called it), only the following environment variables are accessible via %ENV:

  • MOD_PERL and GATEWAY_INTERFACE (always)

  • PATH and TZ (if you had them defined in the shell or httpd.conf)

Therefore, if you don't want to add the overhead of populating %ENV when you simply want to pass some configuration variables from httpd.conf, consider using PerlSetVar and PerlAddVar instead of PerlSetEnv and PerlPassEnv.

perl-script

perl-script is configured as:

SetHandler perl-script

Most mod_perl handlers use the perl-script handler. Here are a few things to note:

  • PerlOptions +GlobalRequest is in effect unless:

    PerlOptions -GlobalRequest

    is specified.

  • PerlOptions +SetupEnv is in effect unless:

    PerlOptions -SetupEnv

    is specified.

  • STDOUT and STDOUT get tied to the request object $r, which makes it possible to read from STDIN and print directly to STDOUT via print( ), instead of having to use implicit calls like $r->print( ).

  • Several special global Perl variables are saved before the handler is called and restored afterward (as in mod_perl 1.0). These include %ENV, @INC, $/, and STDOUT's $| and END blocks.

A simple response handler example

Let's demonstrate the differences between the modperl and perl-script core handlers. Example 24-2 represents a simple mod_perl response handler that prints out the environment variables as seen by it.

Example 24-2. Apache/PrintEnv1.pm

package Apache::PrintEnv1;

use strict;
use warnings;

use Apache::RequestRec ( ); # for $r->content_type

use Apache::Const -compile => 'OK';

sub handler {
    my $r = shift;

    $r->content_type('text/plain');
    for (sort keys %ENV){
        print "$_ => $ENV{$_}\n";
    }

    return Apache::OK;
}

1;

This is the required configuration for the perl-script handler:

PerlModule Apache::PrintEnv1
<Location /print_env1>
    SetHandler perl-script
    PerlResponseHandler Apache::PrintEnv1
</Location>

Now issue a request to http://localhost/print_env1, and you should see all the environment variables printed out.

The same response handler, adjusted to work with the modperl core handler, is shown in Example 24-3.

Example 24-3. Apache/PrintEnv2.pm

package Apache::PrintEnv2;

use strict;
use warnings;

use Apache::RequestRec ( ); # for $r->content_type
use Apache::RequestIO ( );  # for $r->print

use Apache::Const -compile => 'OK';

sub handler {
    my $r = shift;

    $r->content_type('text/plain');
    $r->subprocess_env;
    for (sort keys %ENV){
        $r->print("$_ => $ENV{$_}\n");
    }

    return Apache::OK;
}

1;

The configuration now will look like this:

PerlModule Apache::PrintEnv2
<Location /print_env2>
    SetHandler modperl
    PerlResponseHandler Apache::PrintEnv2
</Location>

Apache::PrintEnv2 cannot use print( ), so it uses $r->print( ) to generate a response. Under the modperl core handler, %ENV is not populated by default; therefore, subprocess_env( ) is called in a void context. Alternatively, we could configure this section to do:

PerlOptions +SetupEnv

If you issue a request to http://localhost/print_env2, you should see all the environment variables printed out as with http://localhost/print_env1.

PerlOptions Directive

The PerlOptions directive provides fine-grained configuration for what were compile-time-only options in the first mod_perl generation. It also provides control over what class of PerlInterpreter is used for a <VirtualHost> or location configured with <Location>, <Directory>, etc.

Options are enabled by prepending + and disabled with -. The options are discussed in the following sections.

Enable

On by default; can be used to disable mod_perl for a given <VirtualHost>. For example:

<VirtualHost ...>
    PerlOptions -Enable
</VirtualHost>

Clone

Share the parent Perl interpreter, but give the <VirtualHost> its own interpreter pool. For example, should you wish to fine-tune interpreter pools for a given virtual host:

<VirtualHost ...>
    PerlOptions +Clone
    PerlInterpStart 2
    PerlInterpMax 2
</VirtualHost>

This might be worthwhile in the case where certain hosts have their own sets of large modules, used only in each host. Tuning each host to have its own pool means that the hosts will continue to reuse the Perl allocations in their specific modules.

When cloning a Perl interpreter, to inherit the parent Perl interpreter's PerlSwitches, use:

<VirtualHost ...>
    ...
    PerlSwitches +inherit
</VirtualHost>

Parent

Create a new parent Perl interpreter for the given <VirtualHost> and give it its own interpreter pool (implies the Clone option).

A common problem with mod_perl 1.0 was that the namespace was shared by all code within the process. Consider two developers using the same server, each of whom wants to run a different version of a module with the same name. This example will create two parent Perl interpreters, one for each <VirtualHost>, each with its own namespace and pointing to a different path in @INC:

<VirtualHost ...>
    ServerName dev1
    PerlOptions +Parent
    PerlSwitches -Mblib=/home/dev1/lib/perl
</VirtualHost>

<VirtualHost ...>
    ServerName dev2
    PerlOptions +Parent
    PerlSwitches -Mblib=/home/dev2/lib/perl
</VirtualHost>

Perl*Handler

Disable specific Perl*Handlers (all compiled-in handlers are enabled by default). The option name is derived from the Perl*Handler name, by stripping the Perl and Handler parts of the word. So PerlLogHandler becomes Log, which can be used to disable PerlLogHandler:

PerlOptions -Log

Suppose one of the hosts does not want to allow users to configure PerlAuthenHandler, PerlAuthzHandler, PerlAccessHandler, and <Perl> sections:

<VirtualHost ...>
    PerlOptions -Authen -Authz -Access -Sections
</VirtualHost>

Or maybe it doesn't want users to configure anything but the response handler:

<VirtualHost ...>
    PerlOptions None +Response
</VirtualHost>

AutoLoad

Resolve Perl*Handlers at startup time; loads the modules from disk if they're not already loaded.

In mod_perl 1.0, configured Perl*Handlers that are not fully qualified subroutine names are resolved at request time, loading the handler module from disk if needed. In mod_perl 2.0, configured Perl*Handlers are resolved at startup time. By default, modules are not auto-loaded during startup-time resolution. It is possible to enable this feature with:

PerlOptions +Autoload

Consider this configuration:

PerlResponseHandler Apache::Magick

In this case, Apache::Magick is the package name, and the subroutine name will default to handler. If the Apache::Magick module is not already loaded, PerlOptions +Autoload will attempt to pull it in at startup time. With this option enabled you don't have to explicitly load the handler modules. For example, you don't need to add:

PerlModule Apache::Magick

GlobalRequest

Set up the global Apache::RequestRec object for use with Apache->request. This setting is needed, for example, if you use CGI.pm to process the incoming request.

This setting is enabled by default for sections configured as:

<Location ...>
    SetHandler perl-script
    ...
</Location>

And can be disabled with:

<Location ...>
    SetHandler perl-script
    PerlOptions -GlobalRequest
    ...
</Location>

ParseHeaders

Scan output for HTTP headers. This option provides the same functionality as mod_perl 1.0's PerlSendHeaders option, but it's more robust. It usually must be enabled for registry scripts that send the HTTP header with:

print "Content-type: text/html\n\n";

MergeHandlers

Turn on merging of Perl*Handler arrays. For example, with this setting:

PerlFixupHandler Apache::FixupA

<Location /inside>
    PerlFixupHandler Apache::FixupB
</Location>

a request for /inside runs only Apache::FixupB (mod_perl 1.0 behavior). But with this configuration:

PerlFixupHandler Apache::FixupA

<Location /inside>
    PerlOptions +MergeHandlers
    PerlFixupHandler Apache::FixupB
</Location>

a request for /inside will run both the Apache::FixupA and Apache::FixupB handlers.

SetupEnv

Set up environment variables for each request, à la mod_cgi.

When this option is enabled, mod_perl fiddles with the environment to make it appear as if the code is called under the mod_cgi handler. For example, the $ENV{QUERY_STRING} environment variable is initialized with the contents of Apache::args( ), and the value returned by Apache::server_hostname( ) is put into $ENV{SERVER_NAME}.

Those who have moved to the mod_perl API no longer need this extra %ENV population and can gain by disabling it, since %ENV population is expensive. Code using the CGI.pm module requires PerlOptions +SetupEnv because that module relies on a properly populated CGI environment table.

This option is enabled by default for sections configured as:

<Location ...>
    SetHandler perl-script
    ...
</Location>

Since this option adds an overhead to each request, if you don't need this functionality you can turn it off for a certain section:

<Location ...>
    SetHandler perl-script
    PerlOptions -SetupEnv
    ...
</Location>

or globally affect the whole server:

PerlOptions -SetupEnv
<Location ...>
    ...
</Location>

It can still be enabled for sections that need this functionality.

When this option is disabled you can still read environment variables set by you. For example, when you use the following configuration:

PerlOptions -SetupEnv
<Location /perl>
  PerlSetEnv TEST hi
  SetHandler perl-script
  PerlHandler ModPerl::Registry
  Options +ExecCGI
</Location>

and you issue a request for setupenvoff.pl from Example 24-4.

Example 24-4. setupenvoff.pl

use Data::Dumper;
my $r = Apache->request( );
$r->send_http_header('text/plain');
print Dumper(\%ENV);

you should see something like this:

$VAR1 = {
          'GATEWAY_INTERFACE' => 'CGI-Perl/1.1',
          'MOD_PERL' => 'mod_perl/2.0.1',
          'PATH' => '/bin:/usr/bin',
          'TEST' => 'hi'
        };

Notice that we got the value of the environment variable TEST.

Thread-Mode-Specific Directives

The following directives are enabled only in a threaded MPM mod_perl:

PerlInterpStart

The number of interpreters to clone at startup time.

PerlInterpMax

If all running interpreters are in use, mod_perl will clone new interpreters to handle the request, up until this number of interpreters is reached. When PerlInterpMax is reached, mod_perl will block until an interpreter becomes available.

PerlInterpMinSpare

The minimum number of available interpreters this parameter will clone before a request comes in.

PerlInterpMaxSpare

mod_perl will throttle down the number of interpreters to this number as those in use become available.

PerlInterpMaxRequests

The maximum number of requests an interpreter should serve. The interpreter is destroyed and replaced with a fresh clone when this number is reached.

PerlInterpScope

As mentioned, when a request in a threaded MPM is handled by mod_perl, an interpreter must be pulled from the interpreter pool. The interpreter is then available only to the thread that selected it, until it is released back into the interpreter pool. By default, an interpreter will be held for the lifetime of the request, equivalent to this configuration:

PerlInterpScope request

For example, if a PerlAccessHandler is configured, an interpreter will be selected before it is run and not released until after the logging phase.

Interpreters will be shared across subrequests by default; however, it is possible to configure the interpreter scope to be per subrequest on a per-directory basis:

PerlInterpScope subrequest

With this configuration, an autoindex-generated page, for example, would select an interpreter for each item in the listing that is configured with a Perl*Handler.

It is also possible to configure the scope to be per handler:

PerlInterpScope handler

With this configuration, an interpreter will be selected before PerlAccessHandlers are run and put back immediately afterwards, before Apache moves on to the authentication phase. If a PerlFixupHandler is configured further down the chain, another interpreter will be selected and again put back afterwards, before PerlResponseHandler is run.

For protocol handlers, the interpreter is held for the lifetime of the connection. However, a C protocol module (e.g., mod_ftp) might hook into mod_perl and provide a request_rec record. In this case, the default scope is that of the request (the download of one file). Should a mod_perl handler want to maintain state for the lifetime of an FTP connection, it is possible to do so on a per-<VirtualHost> basis:

PerlInterpScope connection

Retrieving Server Startup Options

The httpd server startup options can be retrieved using Apache::exists_config_define( ). For example, to check if the server was started in single-process mode:

panic% httpd -DONE_PROCESS

use the following code:

if (Apache::exists_config_define("ONE_PROCESS")) {
    print "Running in a single process mode";
}

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, interactive tutorials, and more.

Start Free Trial

No credit card required