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

Chapter 8 - Customizing the Apache Configuration Process / The Apache Configuration Directive API
Restricting Configuration Directive Usage

In addition to specifying the syntax of your custom configuration directives, you can establish limits on how they can be used by specifying the req_override key in the data passed to command_table(). This option controls which parts of the configuration files the directives can appear in, called the directive's "context" in the Apache manual pages. This key should point to a bitmap formed by combining the values of several C-language constants:

RSRC_CONF

The directive can appear in any .conf file outside a directory section (<Directory>, <Location> , or <Files>; also <FilesMatch> and kin). The directive is not allowed in .htaccess files.

ACCESS_CONF

The directive can appear within directory sections. The directive is not allowed in .htaccess files.

OR_AUTHCFG

The directive can appear within directory sections but not outside them. It is also allowed within .htaccess files, provided that the directive AllowOverride AuthConfig is set for the current directory.

OR_LIMIT

The directive can appear within directory sections but not outside them. It is also allowed within .htaccess files, provided that the directive AllowOverride Limit is set for the current directory.

OR_OPTIONS

The directive can appear anywhere within the .conf files as well as within .htaccess files provided that AllowOverride Options is set for the current directory.

OR_FILEINFO

The directive can appear anywhere within the .conf files as well as within .htaccess files provided that AllowOverride FileInfo is set for the current directory.

OR_INDEXES

The directive can appear anywhere within the .conf files as well as within .htaccess files provided that AllowOverride Indexes is set for the current directory.

OR_ALL

The directive can appear anywhere. It is not limited in any way.

OR_NONE

The directive cannot be overridden by any of the AllowOverride options.

The value of req_override is actually a bit mask. Apache derives the directive context by taking the union of all the set bits. This allows you to combine contexts by combining them with logical ORs and ANDs. For example, the following combination of constants will allow the directive to appear anywhere in a .conf file but forbid it from ever being used in a .htaccess file:

'req_override' => 'RSRC_CONF | ACCESS_CONF'

As in the case of args_how, the value of the req_override key is not evaluated by Perl. It is simply a string that is written into the .xs file and eventually passed to the C compiler. This means that any errors in the string you provide for req_override will not be caught until the compilation phase.

Directive Definition Shortcuts

   Show Contents   Go to Top   Previous Page   Next Page

We've already seen how to simplify your configuration directives by allowing command_table() to deduce the correct args_how from the callback's function prototype. One other shortcut is available to you as well.

If you pass command_table() a list of array references rather than hash references, then it will take the first item in each array ref to be the name of the configuration directive, and the second item to be the error/usage message. req_override will default to OR_ALL (allowing the directive to appear anywhere), and args_how will be derived from the callback prototype, if present, or TAKE123 if not.

By taking advantage of this shortcut, we can rewrite the list of configuration directives at the beginning of this section more succinctly:

@directives = (
        [
         'TrafficCopSpeedLimit',
         'an integer specifying the maximum allowable bytes per second',
        ],
        [
         'TrafficCopRightOfWay',
          'list of domains that can go as fast as they want',
        ],
       );
command_table(\@directives);

You can also mix and match the two configuration styles. The @directives list can contain a mixture of array refs and hash refs. command_table() will do the right thing.

Configuration Creation and Merging

   Show Contents   Go to Top   Previous Page   Next Page

Digging deeper, the process of module configuration is more complex than you'd expect because Apache recognizes multiple levels of configuration directives. There are global directives contained within the main httpd.conf file, per-server directives specific to virtual hosts contained within <VirtualHost> sections, and per-directory configuration directives contained within <Directory> sections and .htaccess files.

To understand why this issue is important, consider this series of directives:

TrafficCopSpeedLimit 55
<Location /I-95>
  TrafficCopRightOfWay .mil .gov
  TrafficCopSpeedLimit 65
</Location>
<Location /I-95/exit-13>
  TrafficCopSpeedLimit 30
</Location>

When processing URLs in /I-95/exit13, there's a potential source of conflict because the TrafficCopSpeedLimit directive appears in several places. Intuitively, the more specific directive should take precedence over the one in its parent directory, but what about TrafficCopRightOfWay? Should /I-95/exit13 inherit the value of TrafficCopRightOfWay or ignore it?

On top of this, there is the issue of per-server and per-directory configuration information. Some directives, such as HostName, clearly apply to the server as a whole and have no reason to change on a per-directory basis. Other directives, such as Options, apply to individual directories or URIs. Per-server and per-directory configuration information should be handled separately from each other.

To handle these issues, modules may declare as many as four subroutines to set configuration policy: SERVER_CREATE(), DIR_CREATE(), SERVER_MERGE(), and DIR_MERGE().

The SERVER_CREATE() and DIR_CREATE() routines are responsible for creating per-server and per-directory configuration objects. If present, they are invoked before Apache has processed any of the module's configuration directives in order to create a default per-server or per-directory configuration. Provided that at least one of the module's configuration directives appears in the main part of the configuration file, SERVER_CREATE() will be called once for the main server host and once for each virtual host. Similarly, DIR_CREATE() will be called once for each directory section (including <Location> and .htaccess files) in which at least one of the module's configuration directives appears.

As Apache parses and processes the module's custom directives, it invokes the directive callbacks to add information to the per-server and per-directory configuration records. Since the vast majority of modules act at a per-directory level, Apache passes the per-directory configuration object to the callbacks as the first argument. This is the $cfg argument that we saw in the previous examples. A callback that is concerned with processing per-server directives will simply ignore this argument and use the Apache::ModuleConfig class to retrieve the per-server configuration record manually. We'll see how to do this later.

Later in the configuration process, one or both of the SERVER_MERGE() and DIR_MERGE() subroutines may be called. These routines are responsible for merging a parent per-server or per-directory configuration record with a configuration that is lower in the hierarchy. For example, merging will be required when one or more of a module's configuration directives appear in both a <Location /images> section and a <Location /images/PNG> section. In this case, DIR_CREATE() will be called to create default configuration records for each of the /images and /images/PNG directories, and the configuration directives' callbacks will be called to set up the appropriate fields in these newly created configurations. After this, the DIR_MERGE() subroutine is called once to merge the two configuration objects together. The merged configuration now becomes the per-directory configuration for /images/PNG.

This merging process is repeated as many times as needed. If a directory or virtual host section contains none of a particular module's configuration directives, then the configuration handlers are skipped and the configuration for the closest ancestor of the directory is used instead.

In addition to being called at server startup time, the DIR_CREATE() function may be invoked again at request time, for example, whenever Apache processes a .htaccess file. The DIR_MERGE() functions are always invoked at request time in order to merge the current directory's configuration with its parents.

When C modules implement configuration directive handlers they must, at the very least, define a per-directory or per-server constructor for their configuration data. However, if a Perl module does not implement a constructor, mod_perl uses a default per-directory constructor that creates a hash reference blessed into the current package's class. Later Apache calls your module's directive callbacks to fill in this empty hash, which is, as usual, passed in as the $cfg argument. No per-server configuration object is created by default.

Neither C nor Perl modules are required to implement merging routines. If they do not, merging simply does not happen and Apache uses the most specific configuration record. In the example at the top of this section, the configuration record for the URI location /I-95/exit-13 would contain the current value of TrafficCop-SpeedLimit but no specific value for TrafficCopRightOfWay.

Depending on your module's configuration system, you may wish to implement one or more of the configuration creation and merging methods described in the following list. The method names use the all-uppercase naming convention because they are never called by any other user code.

DIR_CREATE()

If the directive handler's class defines or inherits a DIR_CREATE() method, it will be invoked to create per-directory configuration objects. This object is the second argument passed to all directive handlers, which is normally used to store the configuration arguments. When no DIR_CREATE() method is found, mod_perl will construct the configuration object for you like this:

bless {}, $Class;

You might use a DIR_CREATE() method to define various defaults or to use something other than a hash reference to store the configuration values. This example uses a blessed hash reference and sets the value of TopLimit to a default value:

package Apache::TrafficCop;
sub new {
  return bless {}, shift;
}
sub DIR_CREATE {
   my $class = shift;
   my $self = $class->new;
   $self->{TopLimit} ||= 65;
   return $self;
}
DIR_MERGE()

When the <Directory> or <Location> hierarchy contains configuration entries at multiple levels, the directory merger routine will be called on to merge all the directives into the current, bottom-most level.

When defining a DIR_MERGE() method, the parent configuration object is passed as the first argument, and the current object as the second. In the example DIR_ MERGE() routine shown below, the keys of the current configuration will override any like-named keys in the parent. The return value should be a merged configuration object blessed into the module's class:

sub DIR_MERGE {
   my($parent, $current) = @_;
   my %new = (%$parent, %$current);
   return bless \%new, ref($parent);
}
SERVER_CREATE()
SERVER_MERGE()

The SERVER_CREATE() and SERVER_MERGE() methods work just like DIR_ CREATE() and DIR_MERGE(). The difference is simply in the scope and timing in which they are created and merged. The SERVER_CREATE() method is only called once per configured virtual server. The SERVER_MERGE() method is invoked during server startup time, rather than at request time like DIR_MERGE().

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