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 and configuration files from mod_perl 1.0 to mod_perl 2.0.

As will be explained in details later loading Apache::compat at the server startup, should make the code running properly under 1.0 work under mod_perl 2.0. If you want to port your code to mod_perl 2.0 or writing from scratch and not concerned about backwards compatibility, this document explains what has changed compared to mod_perl 1.0.

Several configuration directives were changed, renamed or removed. Several APIs have changed, renamed, removed, or moved to new packages. Certain functions while staying exactly the same as in mod_perl 1.0, now reside in different packages. Before using them you need to find out those packages and load them.

You should be able to find the destiny of the functions that you cannot find any more or which behave differently now under the package names the functions belong in mod_perl 1.0.

Configuration Files Porting

To migrate the configuration files to the mod_perl 2.0 syntax, you may need to do certain adjustments. Several configuration directives are deprecated in 2.0, but still available for backwards compatibility with mod_perl 1.0. If you don't need the backwards compatibility consider using the directives that have replaced them.

PerlHandler

PerlHandler was replaced with PerlResponseHandler.

PerlSendHeader

PerlSendHeader was replaced with PerlOptions +/-ParseHeaders directive.

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

PerlSetupEnv

PerlSetupEnv was replaced with PerlOptions +/-SetupEnv directive.

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

PerlTaintCheck

The taint mode now can be turned on with:

  PerlSwitches -T

As with standard Perl, by default the taint mode is disabled and once enabled cannot be turned off inside the code.

PerlWarn

Warnings now can be enabled globally with:

  PerlSwitches -w

PerlFreshRestart

PerlFreshRestart is a mod_perl 1.0 legacy and doesn't exist in mod_perl 2.0. A full teardown and startup of interpreters is done on restart.

If you need to use the same httpd.conf for 1.0 and 2.0, use:

  <IfDefine !MODPERL2>
      PerlFreshRestart
  </IfDefine>

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.

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.

If you have mod_perl 1.0 and 2.0 installed on the same system and the two use the same perl libraries directory (e.g. /usr/lib/perl5), to use mod_perl 2.0 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;

So if before loading Apache2.pm the @INC array consisted of:

  /home/stas/perl/ithread/lib/5.8.0/i686-linux-thread-multi
  /home/stas/perl/ithread/lib/5.8.0
  /home/stas/perl/ithread/lib/site_perl/5.8.0/i686-linux-thread-multi
  /home/stas/perl/ithread/lib/site_perl/5.8.0
  /home/stas/perl/ithread/lib/site_perl
  .

It will now look as:

  /home/stas/perl/ithread/lib/site_perl/5.8.0/i686-linux-thread-multi/Apache2
  /home/stas/perl/ithread/lib/5.8.0/i686-linux-thread-multi
  /home/stas/perl/ithread/lib/5.8.0
  /home/stas/perl/ithread/lib/site_perl/5.8.0/i686-linux-thread-multi
  /home/stas/perl/ithread/lib/site_perl/5.8.0
  /home/stas/perl/ithread/lib/site_perl
  .

Notice that a new directory was prepended to the search path, so if for example the code attempts to load Apache::RequestRec and there are two versions of this module undef /home/stas/perl/ithread/lib/site_perl/:

          5.8.0/i686-linux-thread-multi/Apache/RequestRec.pm
  5.8.0/i686-linux-thread-multi/Apache2/Apache/RequestRec.pm

The mod_perl 2.0 version will be loaded first, because the directory 5.8.0/i686-linux-thread-multi/Apache2 is coming before the directory 5.8.0/i686-linux-thread-multi in @INC.

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: not all manpages exist yet.)

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.

Deprecated Constants

REDIRECT and similar constants have been deprecated in Apache for years, in favor of the HTTP_* names. mod_perl 2.0 API performs the following aliasing behind the scenes:

     NOT_FOUND     => 'HTTP_NOT_FOUND',
     FORBIDDEN     => 'HTTP_FORBIDDEN',
     AUTH_REQUIRED => 'HTTP_UNAUTHORIZED',
     SERVER_ERROR  => 'HTTP_INTERNAL_SERVER_ERROR',
     REDIRECT      => 'HTTP_MOVED_TEMPORARILY',

but we suggest moving to use the HTTP_* names. For example if running in 1.0 compatibility mode change:

  use Apache::Constants qw(REDIRECT);

to:

  use Apache::Constants qw(HTTP_MOVED_TEMPORARILY);

This will work in both mod_perl generations.

SERVER_VERSION()

Apache::Constants::SERVER_VERSION() has been replaced with:

  Apache::get_server_version();

export()

Apache::Constants::export() has no replacement in 2.0 as it's not needed.

Apache:: Methods

Apache->server

Apache->server now resides in Apache::ServerUtil. To use it add:

  use Apache::ServerUtil ();

Apache->request

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>

Apache->define

Apache->define has been replaced with Apache::exists_config_define() residing inside Apache::ServerUtil.

See the Apache::ServerUtil manpage.

Apache::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.

Apache::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.

Apache::module()

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

Apache::log_error()

Apache::log_error() is not available in mod_perl 2.0 API. You can use:

  Apache->server->log_error

instead. See the Apache::Log manpage.

Server Object Methods

$s->register_cleanup

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

  sub cleanup_callback { my $data = shift; ... }
  $s->pool->cleanup_register(\&cleanup_callback, $data);

where the last argument $data is optional, and if supplied will be passed as the first argument to the callback function.

See the APR::Pool manpage.

Request Object Methods

$r->lookup_file

See the next item

$r->lookup_uri

$r->lookup_file and $r->lookup_uri didn't change their functionality but moved into Apache::SubRequest. Before using them, add:

  use Apache::SubRequest;

$r->get_remote_host

$r->get_remote_host has been renamed and moved into the package Apache::Connection:

  use Apache::Connection;
  $r->connection->get_remote_host();

$r->content

See the next item.

$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.

$r->chdir_file

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

$r->connection->user

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

$r->is_main

$r->is_main is not part of the mod_perl 2.0 API. Use !$r->main instead.

$r->finfo

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

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

$r->header_in

See the next item.

$r->header_out

See the next item.

$r->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.

$r->log_reason

$r->log_reason is not available in mod_perl 2.0 API. Use the other standard logging functions provided by the Apache::Log module. For example:

  $r->log_error("it works!");

See the Apache::Log manpage.

$r->register_cleanup

$r->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.:

  sub cleanup_callback { my $data = shift; ... }
  $r->pool->cleanup_register(\&cleanup_callback, $data);

where the last argument $data is optional, and if supplied will be passed as the first argument to the callback function.

See the APR::Pool manpage.

$r->post_connection

$r->post_connection has been replaced with:

  $r->connection->pool->cleanup_register();

See the APR::Pool manpage.

$r->request

Use Apache->request.

$r->send_fd

See the next item.

$r->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.

$r->hard_timeout

See the next item.

$r->reset_timeout

See the next item.

$r->soft_timeout

See the next item.

$r->kill_timeout

The functions $r->hard_timeout, $r->reset_timeout, $r->soft_timeout and $r->kill_timeout aren't needed in mod_perl 2.0.

Apache::File

The methods from mod_perl 1.0's 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()

This function now belongs to the module Apache::Response.

meets_conditions()

This function now belongs to the module Apache::Response.

set_content_length()

This function now belongs to the module Apache::Response.

set_etag()

This function now belongs to the module Apache::Response.

set_last_modified()

This function now belongs to the module Apache::Response.

update_mtime()

This function now belongs 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::escape_uri()

Apache::Util::escape_uri() has been replaced with Apache::Util::escape_path() and requires a pool object as a second argument. For example:

  $escaped_path = Apache::Util::escape_path($path, $r->pool);

Apache::Util::unescape_uri()

Apache::Util::unescape_uri() has been replaced with Apache::unescape_url().

Apache::Util::escape_html()

Apache::Util::escape_html currently is available only via Apache::compat until ap_escape_html is reworked to not require a pool.

Apache::Util::parsedate()

Apache::Util::parsedate() has been replaced with APR::Date::parse_http().

Apache::Util::ht_time()

Apache::Util::ht_time() has been replaced (temporary?) with Apache::Util::format_time(), which requires a pool object as a forth argument. All four arguments are now required.

For example:

   use Apache::Util ();
   $fmt = '%a, %d %b %Y %H:%M:%S %Z';
   $gmt = 1;
   $fmt_time = Apache::Util::format_time(time(), $fmt, $gmt, $r->pool);

See the Apache::Util manpage.

Apache::Util::validate_password()

Apache::Util::validate_password() has been replaced with APR::password_validate(). For example:

   my $ok = Apache::Util::validate_password("stas", "ZeO.RAc3iYvpA");

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) = @_;
      ...;
  }

mod_perl 2.0 doesn't handle callbacks with ($$) prototypes differently than other callbacks (as it did in mod_perl 1.0), mainly because several callbacks in 2.0 have more arguments than just $r, so the ($$) prototype doesn't make sense anymore. Therefore if you want your code to work with both mod_perl generations and you can allow the luxury of:

  require 5.6.0;

or if you need the code to run only on mod_perl 2.0, use the method subroutine attribute. (The subroutine attributes are supported in Perl since version 5.6.0.)

Here is the same example rewritten using the method subroutine attribute:

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

See the attributes manpage.

If Class->method syntax is used for a Perl*Handler, the :method attribute is not required.

Apache::Table

Apache::Table has been renamed to APR::Table.

Apache::StatINC

Apache::StatINC has been replaced by Apache::Reload, which works for both mod_perl generations. To migrate to Apache::Reload simply replace:

  PerlInitHandler Apache::StatINC

with:

  PerlInitHandler Apache::Reload

However Apache::Reload provides an extra functionality, covered in the module's manpage.

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.