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

NAME

Migrating from mod_perl 1.0 to mod_perl 2.0

Description

This chapter explains how to port code from mod_perl 1.0 to mod_perl 2.0.

Configuration Files Porting

To migrate the configuration files to the mod_perl 2.0 syntax, you may need to do certain adjustments if you use any of the configuration directives listed in the following sections.

Remember that if you use any of the new directives, your configuration won't work anymore with mod_perl 1.0.

PerlHandler

PerlHandler was replaced with PerlResponseHandler.

PerlSendHeader

PerlSendHeader was replaced with PerlOptions +/-ParseHeaders directive.

  PerlSendHeader On  => Options +ParseHeaders
  PerlSendHeader Off => Options -ParseHeaders

PerlSetupEnv

PerlSetupEnv was replaced with PerlOptions +/-SetupEnv directive.

  PerlSetupEnv On  => Options +SetupEnv
  PerlSetupEnv Off => Options -SetupEnv

PerlTaintCheck

The tainting mode now can be turned on with:

  PerlSwitches -T

The default is Off. You cannot turn it Off once it's turned On.

PerlWarn

Warnings now can be enabled globally with:

  PerlSwitches -w

Code Porting

mod_perl 2.0 is trying hard to be back compatible with mod_perl 1.0. However some things (mostly APIs) have been changed. In order to gain a complete compatibilty with 1.0 while running under 2.0, you should load the compatibility module as early as possible:

  use Apache::compat;

at the server startup. And unless there are forgotten things or bugs, your code should work without any changes under 2.0 series.

If you have mod_perl 1.0 and 2.0 installed on the same system and the two use the same perl libraries directories (e.g. /usr/lib/perl5), make sure to load first the Apache2 module which will perform the necessary adjustments to @INC.

  use Apache2; # if you have 1.0 and 2.0 installed
  use Apache::compat;

However, unless you want to keep the 1.0 compatibility, you should try to remove the compatibility layer and adjust your code to work under 2.0 without it. You want to do it mainly for the performance improvement.

This document explains what APIs have changed and what new APIs should be used instead.

The Apache::Registry Family

Apache::Registry, Apache::PerlRun and other modules from the registry family now live in the ModPerl:: namespace to avoid collisions with the versions from 1.0.

To run the Apache::Registry module from mod_perl 1.0 you have to load Apache::compat at the startup:

  file:startup.pl:
  ----------------
  use Apache2; # if you have 1.0 and 2.0 installed
  use Apache::compat ();
  use lib ...; # to find 1.0x Apache::Registry

then in httpd.conf:

  Alias /perl /path/to/perl/scripts
  <Location /perl>
     Options +ExecCGI
     SetHandler perl-script
     PerlResponseHandler Apache::Registry
  </Location>

Notice that Apache::compat has to be loaded before CGI.pm if the latter module is used.

META: complete

Apache::Constants

Apache::Constants has been replaced by three classes:

Apache::Const

Apache constants

APR::Const

Apache Portable Runtime constants

ModPerl::Const

mod_perl specific constants

See the manpages of the respective modules to figure out which constants they provide. (XXX: the manpages don't exist)

META: add the info how to perform the transition. XXX: may be write a script, which can tell you how to port the constants to 2.0? Currently Apache::compat doesn't provide a complete back compatibility layer.

Apache::

$r->content() and $r->args() in an Array Context

$r->args() in 2.0 returns the query string without parsing and splitting it into an array. You can also set the query string by passing a string to this method.

$r->content() and $r->args() in an array context were mistakes that never should have been part of the mod_perl 1.0 API. There multiple reason for that, among others:

  • does not handle multi-value keys

  • does not handle multi-part content types

  • does not handle chunked encoding

  • slurps $r->headers_in->{'content-length'} into a single buffer (bad for performance, memory bloat, possible dos attack, etc.)

  • in general duplicates functionality (and does so poorly) that is done better in Apache::Request.

  • if one wishes to simply read POST data, there is the more modern {setup,should,get}_client_block API, and even more modern filter API. Along with continued support for read(STDIN, ...) and $r->read($buf, $r->headers_in->{'content-length'})

Instead you should use Apache::Request's params() and similar methods to do the parsing for you. See the Apache::Request manpage.

XXX: ...when Apache::Request will be ported to 2.0. For now you can use the code in Apache::compat that implements these methods in Perl.

chdir_file()

chdir() is not a thread-safe function, therefore chdir_file() is gone from the API.

$r->connection->user

This method is deprecated in 1.0 and $r->user should be used instead for both versions of mod_perl. Apache::user() method is available since mod_perl version 1.24_01.

exit()

Apache::exit() has been replaced with ModPerl::Util::exit(), which is a function (not a method) and accepts a single optional argument: status, whose default is 0 (== do nothing).

See the ModPerl::Util manpage.

finfo()

XXX: not implemented yet. To be implemented. Apache::compat handles that for now with:

  sub finfo {
      my $r = shift;
      stat $r->filename;
      \*_;
  }

gensym()

Since Perl 5.6.1 filehandlers are autovivified and there is no need for Apache::gensym() function, since now it can be done with:

  open my $fh, "foo" or die $!;

Though the C function modperl_perl_gensym() is available for XS/C extensions writers.

header_in(), header_out() and err_header_out()

header_in(), header_out() and err_header_out() are not available in 2.0. Use headers_in(), headers_out() and err_headers_out() instead (which should be used in 1.0 as well). For example you need to replace:

  $r->err_header_out("Pragma" => "no-cache");

with:

  $r->err_headers_out->{'Pragma'} = "no-cache";

See the Apache::RequestRec manpage.

log_reason()

log_reason() has been replaced with a set of dedicated functions: Apache::RequestRec::log_error(), Apache::ServerRec::log_error(), Apache::Log::info() and others.

See the Apache::RequestRec, Apache::Server and Apache::Log manpages.

module()

Apache::module has been replaced with the function Apache::Module::loaded(), which now accepts a single argument: the module name.

register_cleanup()

register_cleanup() has been replaced with APR::Pool::cleanup_register() which accepts the pool object as the first argument instead of the request object. e.g.:

  $r->pool->cleanup_register(\&cleanup, $data);

where the last argument $data is optional.

See the APR::Pool manpage.

$r->request()

Use Apache::request().

Notice that Apache->request is deprecated. It's error-prone and hurts performance when using threaded MPMs, since it has to use thread local storage.

For any location that uses Apache->request and uses "modperl" handler, you need to configure:

  <Location ...>
      SetHandler modperl
      PerlOptions +GlobalRequest
      ...
  </Location>

It's already enabled for:

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

send_fd() and send_fd_length()

currently available only in the 1.0 compatibility layer. The problem is that Apache has changed the API and the its functionality. See the implementation in Apache::compat.

XXX: needs a better resolution

$r->server_root_relative

Apache::server_root_relative is a function in 2.0.

  my $conf_dir = Apache::server_root_relative($r->pool, 'conf');

See the Apache::ServerUtil manpage.

Apache::File

The methods from module Apache::File have been either moved to other packages or removed.

open() and close()

See the implementation in the module Apache::compat.

tmpfile()

See File::Temp, or the implementation in the module Apache::compat.

It was removed since Apache 2.0 doesn't have the API for this method anymore.

mtime()

mtime() now belongs to the module Apache::RequestRec.

discard_request_body(), meets_conditions(), set_content_length(), set_etag(), set_last_modified() and update_mtime()

These functions now belong to the module Apache::Response.

Apache::Util

A few Apache::Util functions have changed their interface.

Apache::Util::size_string

Apache::Util::size_string has been replaced with APR::String::format_size, which returns formatted strings of only 4 characters long. See the APR::String manpage.

Apache::Util::unescape_uri()

Apache::Util::unescape_uri() is now Apache::unescape_url().

Apache::URI

Apache::URI->parse($r, [$uri])

Apache::URI->parse() has been replaced with APR::URI->parse(), which is invoked as:

  my $curl = $r->construct_url;
  APR::URI->parse($r->pool, $curl);

See the APR::URI manpage.

Miscellaneous

Method Handlers

In mod_perl 1.0 the method handlers could be specified by using the ($$) prototype:

  package Bird;
  @ISA = qw(Eagle);
  
  sub handler ($$) {
      my($class, $r) = @_;
      ...;
  }

Starting from Perl version 5.6 the subroutine attributes are used in place of subroutine prototypes:

  package Bird;
  @ISA = qw(Eagle);
  
  sub handler : method {
      my($class, $r) = @_;
      ...;
  }

See the attributes manpage.

mod_perl 2.0 doesn't support the ($$) prototypes, mainly because several callbacks in 2.0 have more arguments than $r, so the ($$) prototype doesn't make sense anymore. Therefore if you want your code to work with both mod_perl generations, you should use the subroutine attributes.

Apache::StatINC

Apache::StatINC has been replaced by Apache::Reload.

Maintainers

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

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

Authors

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

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