home | O'Reilly's CD bookshelfs | FreeBSD | Linux | Cisco | Cisco Exam  


Writing Apache Modules with Perl and C
By:   Lincoln Stein and Doug MacEachern
Published:   O'Reilly & Associates, Inc.  - March 1999

Copyright © 1999 by O'Reilly & Associates, Inc.


 


   Show Contents   Previous Page   Next Page

Appendix A - Standard Noncore Modules
The Apache::Resource Class

Apache::Resource allows you to set resource limitations on the Apache server process. You can limit the amount of CPU time a child process will use, the amount of memory it allocates, the number of files it can have open simultaneously, the number of processes it can spawn, and other low-level resources. This allows you to limit the overall impact of a runaway process or to degrade processing gracefully if the server is overloaded by too many requests.

In order to use Apache::Resource, you must have the Perl BSD::Resource module installed. This module does not come installed in Perl by default. As the name implies, BSD::Resource will only compile on BSD-derived versions of Unix and a few close approximations. It will not run correctly on Win32 systems.

To use Apache::Resource, place the following declarations in one of your server configuration files:

PerlSetEnv  PERL_RLIMIT_DEFAULTS
PerlModule  Apache::Resource
PerlChildInitHandler Apache::Resource

This chooses reasonable defaults for the resource limits, loads the Apache::Resource module, and sets it to run whenever a child process is initialized.

You can further customize the module by using PerlSetEnv to declare more specific resource limits for CPU usage, memory, and so on. There are actually two limits you can set for each of these resources: a hard limit that can't be changed and a soft limit that can be increased by modules if they choose to do so (up to the hard limit). You can use a single number for each resource variable, in which case it will be used for both the hard and soft limits, or you can specify a pair of numbers delimited by a colon in S:H format. The first number is the soft limit, and the second is the hard.

The following variables are available for your use:

PERL_RLIMIT_DATA

Child memory limit in megabytes.

PERL_RLIMIT_CPU

Child CPU units in seconds.

PERL_RLIMIT_FSIZE

Maximum file size in megabytes.

PERL_RLIMIT_RSS

Maximum process size in megabytes.

PERL_RLIMIT_STACK

Child stack limit in megabytes.

PERL_RLIMIT_CORE

Maximum core file size in megabytes.

Within a handler, modules can examine the limits and change them (up to the ceiling specified by the hard limits) by calling the getrlimit() and setrlimit() methods of BSD::Resource.

The Apache::PerlSections Class

   Show Contents   Go to Top   Previous Page   Next Page

As described in Chapter 7, Other Request Phases, it's possible to configure the Apache server entirely via Perl scripts embedded in <Perl> sections. The Apache::PerlSections module is a helper class that provides convenient functions for this process. It provides two public functions, dump() and store().

dump()

Called from within a <Perl> configuration section, dump() returns a pretty-printed string containing the current configuration variables. The string can be written out to a file and later brought back in via a require.

Example:

<Perl>
  use Apache::PerlSections ();
  $Port = 8529;
  @DocumentIndex = qw(index.htm index.html);
   print Apache::PerlSections->dump();
</Perl>

This will print out something like this:

package Apache::ReadConfig;
#scalars:
$Port = 8529;
 #arrays:
@DocumentIndex = (
 'index.htm',
 'index.html'
);
# hashes
1;
__END__

Notice that the variables are declared in the Apache::ReadConfig package. We give the reason for this in the next section.

store()

This is identical to dump(), except that the formatted string is written directly to the file path you specify.

Example:

<Perl>
  .....
  print Apache::PerlSections->store('httpd_config.pl');
</Perl>

If a relative path is given to store(), it will be taken as relative to the current configuration file.

The Apache::ReadConfig Class

   Show Contents   Go to Top   Previous Page   Next Page

Apache::ReadConfig is a namespace used by the <Perl> configuration section mechanism to store its global variables. All global variables defined in this namespace are processed as if they were configuration directives during server startup time. See Chapter 8 for detailed examples on configuring httpd with Perl.

The Apache::StatINC Class

   Show Contents   Go to Top   Previous Page   Next Page

When you write a script using the Apache::Registry mechanism, Apache::Registry watches the script file's modification date and reloads the script if it is more recent than the compiled version in memory. This lets you edit the script file and see the changes immediately.

However, this is not the case with Apache Perl API modules or any Perl library files that they depend on. Changing the .pm file does not cause the module to be reloaded automatically. You ordinarily have to restart the whole server with apachectl restart or apache -k restart to see any changes take effect.

You can use the Apache::StatINC to alter this behavior. Each time it runs, Apache::StatINC checks the contents of the Perl global %INC hash of loaded modules. Apache::StatINC keeps track of each module's modification time. When it notes that a module has been modified since it was last loaded, it removes the module from %INC, forcing Perl to reload and compile it.

To install Apache::StatINC, add the following configuration directive to perl.conf (or any of the configuration files):

PerlInitHandler Apache::StatINC

This directive arranges for Apache::StatINC's handler() method to be invoked every time Apache handles an HTTP request, before any other Perl*Handlers are run.

Note that Apache::StatINC only sees the directories that were present in the @INC include path at the time the server was started. During a request, a script or module may modify the @INC path, but those changes are lost when mod_perl restores @INC to the same value it had at server startup time. If you wish to monitor custom directories, you should install them at Perl startup time, either by putting the requisite use lib lines in the Perl startup script or by defining the PERL5LIB environment variable before starting the server.

We do not recommend Apache::StatINC for use on a production server. It introduces significant overhead on every transaction.

The Apache::Include Class

   Show Contents   Go to Top   Previous Page   Next Page

This class provides methods to support integration between mod_include and mod_perl. It makes it possible for parsed HTML files (.shtml) to include Apache::Registry scripts with directives like this one:

<!--#perl sub="Apache::Include" arg="/perl/ssi.pl" -->

When this directive is processed by Apache's standard mod_include module, the Apache::Registry script ssi.pl is run and its output incorporated into the page.

Apache::Include provides a method named virtual() for those who wish to include the contents of another document in the output of their Apache::Registry scripts. It is called with two arguments: the URI you wish to incorporate and the current request object. Only local URIs can be included in this way.

Here's an example:

#!/usr/local/bin/perl
use Apache ();
use Apache::Include ();
my $r = Apache->request;
print "Content-type: text/plain\n\n";
print "I am including a document now:\n";
Apache::Include->virtual('/contents.txt', $r);
print "I am done.\n";

See Chapter 7, Perl Server-Side Includes, for more details on using the #perl element with server-side includes.

The Apache::Status Class

   Show Contents   Go to Top   Previous Page   Next Page

The Apache::Status class provides dynamic status and debug information about the mod_perl interpreter. When installed, it will display symbol table dumps, inheritance trees, lists of global variables, and other displays that may be of interest to Perl module developers (Figure A-1).

Figure A-1. The Apache::Status module produces detailed reports on the state of mod_perl.

A URI to run Apache::Status must be installed before the module can be used. To do this, create an entry like the following in one of the Apache configuration files:

<Location /perl-status>
  SetHandler  perl-script
  PerlHandler Apache::Status
</Location>

After restarting the server, requests for the URI /perl-status will display a series of pages showing the status of various Apache modules, including your own.

Apache::Status requires the Devel::Symdump module to run at all. This is not a standard part of the Perl distribution and will need to be downloaded from CPAN and installed. Certain other features of the module are not activated unless you also install a few third party pieces. With the Data::Dumper module installed and StatusDumper set to On, it is possible to view the contents of global variables. Installing Apache::Peek and setting StatusPeek to On enables inspection of symbols the same way Perl views them internally. If mod_perl was compiled with Perl 5.005 or higher and the B::Graph module was installed, along with the dot program, setting StatusGraph to On enables Apache::Status to render GIF graphs of OP trees. The three modules can be found on CPAN. dot is part of AT&T's graph visualization toolkit available at http://www.research.att.com/sw/tools/graphviz/. Here is a sample configuration that enables all of these features:

<Location /perl-status>
  SetHandler  perl-script
  PerlHandler Apache::Status
  PerlSetVar  StatusDumper On
  PerlSetVar  StatusPeek   On
  PerlSetVar  StatusGraph  On
</Location>

Your module can add one or more custom menu items to the Apache::Status main page. When you click on this link, Apache::Status runs a subroutine defined in your module and displays the subroutine's output, usually some HTML. To install this type of custom menu item, include a code snippet like this at the bottom of the module:

if (Apache->module("Apache::Status")) {
   Apache::Status->menu_item('MyApp' => "MyApp Menu Item",
                             \&myapp_debug_menu);
}
sub myapp_debug_menu {
 my ($r,$q) = @_;
 push(@s,'<h2>some html</h2>');
 push(@s,'some <b>more</b> html');
 return \@s;
}

In this example, we first check with Apache to see if the Apache::Status module is present. If so, we call its menu_item() method. The first two arguments to menu_item() are the name of the current module and the descriptive title to use for its custom menu item. The third argument is a CODE reference to a subroutine to run when the menu item is selected.

In this example, the subroutine is named myapp_debug_menu(). On entry to this subroutine, Apache::Status passes it the Apache request object and a CGI object (from the CGI.pm module). The subroutine is free to do whatever it likes with these objects or ignore them entirely. The subroutine builds up an array containing the HTML it wants to display. Its function result is a reference to that array.

Good examples of creating custom menu items can be found by inspecting the source code of the Apache::Resource and the Apache::DBI modules.

   Show Contents   Go to Top   Previous Page   Next Page
Copyright © 1999 by O'Reilly & Associates, Inc.