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

NAME

mod_perl_traps - common/known mod_perl traps

DESCRIPTION

In the CGI environment, the server starts a single external process (Perl interpreter) per HTTP request which runs single script in that process space. When the request is over, the process goes away everything is cleaned up and a fresh script is started for the next request. mod_perl brings Perl inside of the HTTP server not only for speedup of CGI scripts, but also for access to server functionality that CGI scripts do not and/or cannot have. Now that we're inside the server, each process will likely handle more than one Perl script and keep it "compiled" in memory for longer than a single HTTP request. This new location and longer lifetime of Perl execution brings with it some common traps. This document is here to tell you what they are and how to prevent them. The descriptions here are short, please consult the mod_perl FAQ for more detail. If you trip over something not documented here, please send a message to the mod_perl list.

Migrating from CGI

  • Be sure to have read cgi_to_mod_perl

  • Scripts under Apache::Registry are not run in package main, they are run in a unique namespace based on the requested uri.

  • Apache::Registry scripts cannot contain __END__ or __DATA__ tokens

  • Output of system, exec and open PIPE, "|program" calls will not be sent to the browser unless you Perl was configured with sfio.

  • Perl's exit() built-in function cannot be used in mod_perl scripts. The Apache::exit() function should be used instead. Apache::exit() automatically overrides the built-in exit() for Apache::Registry scripts.

  • Your scripts *will not* run from the command line (yet) unless you use CGI::Switch or CGI.pm and 5.004+ and do not make any direct calls to Apache->methods.

Using CGI.pm and CGI::*

  • CGI.pm users must have version 2.36 of the package or higher, earlier versions will not work under mod_perl. If you have Perl version 5.004 or higher, scripts may 'use CGI'. Otherwise, scripts need to 'use CGI::Switch ()' so i/o goes through the Apache class methods.

  • The CGI::* modules (CGI::Request etal.) can be used only with Perl version 5.004 or higher.

    If you use the SendHeaders() function, be sure to call $req_obj->cgi->done when you are done with a request, just as you would under CGI::MiniSrv.

Perl Modules and Extensions

  • Files pulled in via use or require statements are not automatically reloaded when changed on disk. See the Apache::StatINC module to add this functionality.

  • Undefined subroutines

    A common trap with required files may result in an error message similar to this in the error_log:

     [Thu Sep 11 11:03:06 1997] Undefined subroutine
     &Apache::ROOT::perl::test_2epl::some_function called at
     /opt/www/apache/perl/test.pl line 79.

    As the above items explains, a file pulled in via require will only happen once per-process (unless %INC is modified). If the file does not contain a package declaration, the file's subroutines and variables will be created in the current package. Under CGI, this is commonly package main. However, Apache::Registry scripts are compiled into a unique package name (base on the uri). So, if multiple scripts in the same process try to require the same file, which does not declare a package, only one script will actually be able to see the subroutines. The solution is to read perlmodlib, perlmod and related perl documentation and re-work your required file into a module which exports functions or defines a method interface. Or something more simple, along these lines:

     #required_file.pl
     package Test;
    
     sub some_function {...}
    
     ...
     
     __END__

    Now, have your scripts say:

     require "required_file.pl";
    
     Test::some_function();
  • "Out of memory!"

    If something goes really wrong with your code, Perl may die with an "Out of memory!" message. A common cause of this are never-ending loops, deep recursion or calling an undefined subroutine. Here's one way to catch the problem: See Perl's INSTALL document for this item:

     =item -DPERL_EMERGENCY_SBRK
    
     If PERL_EMERGENCY_SBRK is defined, running out of memory need not be a
     fatal error: a memory pool can allocated by assigning to the special
     variable $^M.  See perlvar(1) for more details.

    If you compile with that option and add 'use Apache::Debug level => 4;' to your PerlScript, it will allocate the $^M emergency pool and the $SIG{__DIE__} handler will call Carp::confess, giving you a stack trace which should reveal where the problem is.

  • If you wish to use a module that is normally linked static with your Perl, it must be listed in static_ext in Perl's Config.pm to be linked with httpd during the mod_perl build.

I/O

Unless you have perl version 5.004 or higher, by default, you cannot print() to STDOUT from your script, use $r->print() instead. Nor can you read() from STDIN, use $r->read() or the $r->content() methods to read POST data.

Clashes with other Apache C modules

mod_auth_dbm

If you are a user of mod_auth_dbm or mod_auth_db, you may need to edit Perl's Config module. When Perl is configured it attempts to find libraries for ndbm, gdbm, db, etc., for the *DBM*_File modules. By default, these libraries are linked with Perl and remembered by the Config module. When mod_perl is configured with apache, the ExtUtils::Embed module returns these libraries to be linked with httpd so Perl extensions will work under mod_perl. However, the order in which these libraries are stored in Config.pm, may confuse mod_auth_db*. If mod_auth_db* does not work with mod_perl, take a look at this order with the following command:

 % perl -V:libs

If -lgdbm or -ldb is before -lndbm, example:

 libs='-lnet -lnsl_s -lgdbm -lndbm -ldb -ldld -lm -lc -lndir -lcrypt';

Edit Config.pm and move -lgdbm and -ldb to the end of the list. Here's how to find Config.pm:

 % perl -MConfig -e 'print "$Config{archlibexp}/Config.pm\n"'

Another solution for building Apache/mod_perl+mod_auth_dbm under Solaris is to remove the DBM and NDBM "emulation" from libgdbm.a. Seems Solaris already provides its own DBM and NDBM, and there's no reason to build GDBM with them (for us anyway).

In our Makefile for GDBM, we changed

  OBJS = $(DBM_OF) $(NDBM_OF) $(GDBM_OF)

to

  OBJS = $(GDBM_OF)

Rebuild libgdbm, then Apache/mod_perl.

2 POD Errors

The following errors were encountered while parsing the POD:

Around line 94:

Expected '=item *'

Around line 133:

Expected '=item *'