11.1. Implementing Configuration Directives in C

The C-language API allows modules to install their own configuration directives. The directives' syntax and usage information are defined in a command_rec data structure and processed by directive handler callback routines defined within the module.

Whereas the configuration API is optional in Perl modules due to the catchall PerlSetVar directive, C-language programmers don't have this luxury. You'll have to create custom configuration directives in order to write any module that requires runtime configuration information.

11.1.1. Overview

Modules are responsible for managing their own configuration data. There are two general types of configuration data: data that apply to a particular server or virtual host and data that apply to a directory or URI. A module can maintain both server-specific and directory-specific configuration information or just one or the other, depending on its needs. Because there may be dozens of virtual hosts and hundreds of directories, the Apache API allows modules to juggle thousands of configuration records. During configuration file processing, Apache will call your module's configuration allocation and processing routines at the right time and in the right order to create the configuration data. Then, at request time, Apache will choose the correct configuration record to return to your handler when the handler requests it.

The work of creating and maintaining configuration records is done in several steps. In the first step, the module is given an opportunity to allocate storage for its private configuration settings and to create a reasonable set of defaults, if it chooses. The content of the configuration data is entirely private to your module. Apache sees it only as an opaque void*.

During the second step, which occurs during configuration file processing, the module's directives are parsed and passed back to your code for processing, along with the initialized configuration settings from the previous phase. There is one directive handler for each custom directive that your module declares. The directive handler will alter the configuration block in some way to record the meaning of the directive. Typically the handler will change the contents of a field or add an entry to a table.

The third step is the mysterious-sounding "merging" process. The idea is that configuration information is often nested. For example, a particular directive could appear in the main part of the configuration file, in a <VirtualHost> section, in a <Directory> section, and in a .htaccess file. When the directive appears in a nested scope, your module needs to handle the potential contradiction in some way, either by letting the nested directive take precedence over the parent directive or by merging the contents of the two somehow. Apache handles this process by calling your merge routines. These routines take the base configuration (the configuration that belongs to the parent scope) and the new configuration (the configuration that belongs to the nested section) and merge them into a new configuration block that combines them both.

The last step actually occurs during the transaction. Handlers that need access to their module's per-server or per-directory configuration settings request it from Apache. The ap_get_module_config() API function is able to perform a quick, one-step lookup of your module's configuration data relevant to the current transaction, no matter how many configuration blocks were constructed during server startup.

11.1.2. Creating and Merging Configuration Data Blocks

Your module declares its intent to maintain configuration information by filling in one or more of the slots in the module record labeled config creator or config merger. There are four such slots: one each for functions to create per-directory and per-server configuration settings and one each for merging per-directory and per-server data. The four functions have the following prototypes:

void *create_dir_config(pool *p, char *dir)
void *merge_dir_config(pool *p, void *base_conf, void *new_conf)
void *create_server_config(pool *p, server_rec *s)
void *merge_server_config(pool *p, void *base_conf, void *new_conf)

The create_server_config( ) function is an opportunity for the module to allocate per-server configuration data. It is passed a resource pool and a server_rec server structure. It may, if it chooses, allocate a data structure from within the resource pool, initialize it, and return it to Apache as a void*.

create_dir_config( ) is similar, except that it is called to create per-directory configuration information (directives contained within <Directory>, <Location>, or .htaccess files). In this case, the subroutine is called with a resource pool and the name of the current directory or URI. The routine may, if it chooses, allocate a data structure for the per-directory information and return it to Apache as a void*.

As a concrete example, consider a "traffic cop" module that regulates the flow of traffic on a server. It has two configuration settings: one which sets the maximum speed limit on the server (in bits per second, say) and one which contains a list of domains that have "right-of-way" through the server and can fetch documents at a higher maximum speed. This module could store the information in the following per-server configuration record:

typedef struct {
   int    speed_limit;
   table *right_of_way;
} traffic_server_config;

The following definition of traffic_create_server_config() allocates the storage for the per-server configuration information and sets up appropriate defaults. speed_limit is set to 55 (whatever that means in this context!) and the right_of_way field is initialized to point to a new empty table.

static void *traffic_create_server_config (pool *p, server_rec *s) {
   traffic_server_config *cfg =
      (traffic_server_config *)ap_pcalloc(p, sizeof(traffic_server_config));
   cfg->speed_limit = 55;
   cfg->right_of_way = ap_make_table(p, 0);
   return (void *)cfg;
}

This initial data block will be passed back to your module's directive handlers as a void* when the time comes to process a directive. The handler should typecast the pointer back to the correct data type, then make the appropriate change to the affected field.

A create_dir_config() routine will look almost identical to this, but instead of receiving a server_rec in the second argument, it receives a string containing the path to the relevant directory or URI.

Later on in the process, Apache may be called upon to process a directive that needs to be merged into the parent configuration. You can define up to two such merge routines. The merge_server_config( ) routine is called at server startup time to merge directives in <VirtualHost> blocks with the configuration for the parent server. It receives a pointer to a resource pool, a pointer to the parent server configuration, and a pointer to the child server configuration. The merge routine's job is to create a new configuration structure that combines the two and to return it to Apache as a void*.

merge_dir_config( ) is similar, but it happens at request time and operates on two per-directory structures: the parent directory's configuration and the current directory's configuration. It is expected to merge the two and return a new per-directory configuration structure that combines the configurations in some sensible way.

For example, here is a plausible server merge routine for the traffic cop configuration. We want to overwrite the speed_limit field so that the current virtual host's setting supersedes that of the base host. However, instead of allowing the virtual host's right_of_way settings to supersede those of the parent server, we merge the two using ap_overlay_tables( ) :

static void *traffic_merge_server_config (pool *p, void* base, void* new) {
   traffic_server_config *merged =
      (traffic_server_config*)ap_pcalloc(p, sizeof(traffic_server_config));
   traffic_server_config *parent = (traffic_server_config*)base;
   traffic_server_config *child  = (traffic_server_config*)new;

   merged->speed_limit = child->speed_limit ?
                         child->speed_limit : parent->speed_limit;
   merged->right_of_way = ap_overlay_tables(p, parent->right_of_way,
                                               child->right_of_way);
   return (void*)merged;
}

If your module does not define any merge routines, then Apache will use the configuration of the most recent server or directory configuration, ignoring any directives which previously have been defined for a block's ancestors. If your module defines no create_server_config( ) or create_dir_config( ) routine, then it will have no runtime configuration blocks. However, this doesn't mean that the module can't maintain any configuration information at all; it can still maintain some state in static variables. However, this information will be global to the module, rather than server-specific or directory-specific. This rarely works out the way you want it, nor is it thread-safe.

Rather than having the create_server_config() and create_dir_config() fill in the configuration records' fields with default values, it is often useful to have the two routines fill in the configuration fields with explicit UNSET values. This allows you to distinguish between fields that are unset and fields that just happen to have been set to the default value. It also simplifies merging because the assignment logic now becomes the following:

merged->attr = base->attr == UNSET ? base->attr : new->attr;

There is one major trap in the current Apache configuration API. If your module depends on per-server records and <VirtualHost> sections are in use, then at least one of your module's configuration directives must be present in the <VirtualHost> section or your module's create_server_config() routine will never be called. As a result, your module will have no chance to create its per-server configuration before its handlers are called at transaction time. There are two ways around this problem. You can simply DECLINE to handle the transaction if the per-server configuration block is NULL, or you can try to fill in the values of the configuration block on the fly.

11.1.3. The command_rec Structure

A module defines custom configuration directives using the config directive table slot of its module structure. This table is a pointer to an array of command_rec records having the structure shown in Example 11.1. Usually this array of command_rec data is created as a static data structure in the module source code. The last element of the array must be NULL. As a concrete example, here's a short command_rec definition borrowed from mod_actions.c :

static const command_rec action_cmds[] =
{
    {"Action", add_action, NULL, OR_FILEINFO, TAKE2,
     "a media type followed by a script name"},
    {"Script", set_script, NULL, ACCESS_CONF | RSRC_CONF, TAKE2,
     "a method followed by a script name"},
    {NULL}
};

The action_cmds array declares two directives: Action, which is processed by a handler routine named add_action(), and Script, processed by set_script().

Example 11.1. The command_rec Struct (from http_config.h)
typedef struct command_struct {
   const char *name;           /* Name of this command */
   const char *(*func) ();     /* Function invoked */
   void *cmd_data;             /* Extra data, for functions which
                                * implement multiple commands...*/
   int req_override;           /* What overrides need to be allowed to
                                * enable this command.*/
   enum cmd_how args_how;      /* What the command expects as arguments */
   const char *errmsg;         /* 'usage' message, in case of syntax errors */
} command_rec;

The various fields of the command_rec should look familiar to the Perl API covered in Chapter 8:


char *name

This is the configuration directive's name, used within httpd.conf and the other configuration files. The name may not contain whitespace but is otherwise unrestricted in its contents. However, for consistency, you should stick to the Apache convention of making directives short phrases with the initial letter of each word capitalized. Apache processes directives in a case-insensitive manner.

While processing configuration files, Apache employs a general parsing algorithm. Whenever it hits what appears to be a configuration directive, it searches through the internal module list and peeks into each module's command table until it finds the definition it's looking for. At this point, the server parses the directive's arguments and passes the information to the module's designated configuration processing routine.


const char *(*func) ()

This is a pointer to a directive handler that Apache will call at runtime to process the directive. The prototype for the callback is determined by the args_how field described later in this section. Usually the callback simply sets a value in a module-specific data structure.


void *cmd_data

If the module needs to share common information among multiple directive handlers, the cmd_data field allows you to pass this information around as a void* block. If non-NULL, Apache will pass the contents of cmd_data to the directive handler at runtime in the cmd_parms argument. One use for this would be a situation in which a single directive handler is responsible for processing multiple directives. In order for the handler to determine which directive it's responsible for, the module can leave the address of a distinguishing flag in the cmd_data slot.

For an example of this technique, see how mod_autoindex implements the various AddIcon* and AddAlt* directives.


int override

This field indicates the scope of a directive. The scope is used by Apache to determine what parts of the various configuration files and .htaccess files the directive is allowed to appear in. override is a bit mask constructed from the bitwise OR of a set of constants which we list presently.


enum cmd_how args_how

This field tells the server how it should parse the directive's arguments. It is any of 12 constants that specify the number of mandatory and optional arguments the directive takes. We explain the possibilities later in this section.


char *errmsg

This field contains a short usage message that is displayed when the configuration parser encounters a syntax error in the directive. The usage message is also put to good use by mod_info to display modules' current configurations.

11.1.4. Constants for the override Field

Directives vary in their scope. Some affect low-level processes such as URI translation or the proxy mechanism and therefore belong outside of <Directory> and <Location> sections. Others control access to particular files and directories and only make sense when located within a <Directory> or <Location> section. In other cases, you might want the directive to be available to the webmaster but not allow it to appear in .htaccess files where it would be available to HTML authors.

The override field of the command_rec controls the scope. It is the bitwise combination of the following constants defined in http_config.h:


RSRC_CONF

The directive can only be present in the server .conf files, outside of <Directory>, <Location>, and <Files> containers. Not allowed in any .htaccess files or other files defined by the AccessFileName directive.


ACCESS_CONF

The directive can only be present in the server .conf files, inside <Directory>, <Location>, and <Files> sections. It is not allowed in .htaccess files.


OR_AUTHCFG

The directive has the same scope as ACCESS_CONF, but it is also allowed in .htaccess if AllowOverride AuthConfig is configured for the current directory.


OR_LIMIT

The directive has the same scope as ACCESS_CONF, but it is also allowed in .htaccess if AllowOverride Limit is configured for the current directory.


OR_OPTIONS

The directive is allowed anywhere in the .conf files, and it is also allowed in .htaccess if AllowOverride Options is configured for the current directory.


OR_FILEINFO

The directive is allowed anywhere in the .conf files, and it is also allowed in .htaccess if AllowOverride FileInfo is configured for the current directory.


OR_INDEXES

The directive is allowed anywhere in the .conf files, and it is also allowed in .htaccess if AllowOverride Indexes is configured for the current directory.


OR_ALL

The directive can be just about anywhere it wants to be.


OR_NONE

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

11.1.5. Constants for the args_how Field

Directives differ in their syntax: the number of arguments they take, the number of variable arguments, and the relationship of one argument to another. Apache can handle the common syntaxes, preparsing the directive and its arguments, then presenting the results to a directive handler of your own devising.

Eleven constants, all defined in http_config.h, specify various syntax parsing strategies. If none of these satisfies your needs, a twelfth constant, RAW_ARGS, gives you direct access to the text of the configuration file.

In the list that follows, we give the constant and the recommended function prototype for the directive handler callback. All callbacks take at least two arguments. parms is a pointer to a cmd_parms structure, from which various information about the server and the status of the configuration process can be extracted. More details on the cmd_parms structure are given in the next section.

mconfig is a generic pointer to the module-specific per-directory configuration data that your module created earlier with its create_dir_config() routine. Since most directive handlers work with pre-directory configuration records, this parameter is provided as a convenience. Your handler will typecast this to its specific type, and then set the appropriate fields. Directive handlers that operate on per-server configuration data must manually retrieve the record using ap_get_module_config() as described later.

On successful processing of the directive, the handler should return NULL. If an error occurred while processing the directive, the routine should return a string describing the source of the error. There is also a third possibility. The configuration directive handler can return DECLINE_CMD, a constant defined in http_config.h as the string a. This is useful in the rare circumstance in which a module redeclares another module's directive in order to override it. The directive handler can then return DECLINE_CMD when it wishes the directive to fall through to the original module.


NO_ARGS

The directive takes no arguments at all, for example ClearModuleList.

Function prototype:

static const char *cmd_no_args
      (cmd_parms *parms, void *mconfig)


FLAG

The directive takes one of the string arguments On or Off. The parser converts this argument to an integer Boolean, which it passes to the directive handler. UseCanonicalName is one example of this type of directive.

Function prototype:

static const char *cmd_flag
      (cmd_parms *parms, void *mconfig, int flag)


TAKE1

The directive takes one argument only, e.g., Port.

Function prototype:

static const char *cmd_take1
      (cmd_parms *parms, void *mconfig, const char *arg)

Here is an example of a handler for a TrafficCopSpeedLimit directive that takes a single argument indicating the maximum speed at which clients are allowed to fetch documents:

static const char *traffic_speed_limit_cmd (cmd_parms *parms,
                            void *mconfig, const char *arg)
{
     traffic_dir_config *cfg = (traffic_dir_config *)mconfig;
     traffic_server_config *scfg = (traffic_server_config *)
        ap_get_module_config(parms->server->module_config, &traffic_module);

     long int speed = strtol(arg, (char**)NULL, 10);

     if (speed < 0) {
         return "Speed must be a positive number";
     }
     if (speed == LONG_MAX) {
         return "Integer overflow or invalid number";
     }
     scfg->speed_limit = speed;
     return NULL;
}


TAKE2

The directive takes exactly two arguments, e.g., SetEnv.

Function prototype:

static const char *cmd_take2
      (cmd_parms *parms, void *mconfig, const char *one, const char *two)


ITERATE

The directive takes a list of arguments, each of which has the same meaning, as in IndexIgnore. The callback is invoked repeatedly to process each argument.

Function prototype:

static const char *cmd_iterate
      (cmd_parms *parms, void *mconfig, const char *arg)

For example, a TrafficCopRightOfWay directive for the imaginary traffic cop module might take a list of domains and hostnames that are allowed to retrieve documents as fast as they wish. Assuming that the list of privileged hosts is maintained as the set of keys in an Apache table, here's one way to record the configuration information:

static const char *traffic_rt_of_way_cmd(cmd_parms *parms,
                            void *mconfig, const char *arg)
{
     traffic_dir_config *cfg = (traffic_dir_config *)mconfig;
     traffic_server_config *scfg = (traffic_server_config *)
         ap_get_module_config(parms->server->module_config, &traffic_module);

    ap_table_set(scfg->right_of_way, arg, "t");
    return NULL;
}


ITERATE2

The directive takes a mandatory first argument followed by a variable list of arguments to be applied to the first. A familiar example is the AddIcon directive. Apache will call the directive handler once for each member of the list, passing the handler the mandatory argument and the current list item.

Function prototype:

static const char *cmd_iterate2
      (cmd_parms *parms, void *mconfig, const char *one, const char *two)


TAKE12

The directive will accept one or two arguments, as in the AuthUserFile directive. If the optional second argument is absent, it will be passed as NULL to your handler.

Function prototype:

static const char *cmd_take12
      (cmd_parms *parms, void *mconfig, const char *one, const char *two)


TAKE3

The directive takes exactly three arguments.

Function prototype:

static const char *cmd_take3
      (cmd_parms *parms, void *mconfig,
       const char *one, const char *two, const char *three)


TAKE23

The directive takes two or three arguments, as in Redirect. Missing arguments are passed to the directive handler as NULL.

Function prototype:

static const char *cmd_take23
      (cmd_parms *parms, void *mconfig,
       const char *one, const char *two, const char *three)


TAKE123

The directive takes one, two, or three arguments. Missing arguments are passed to the directive handler as NULL.

Function prototype:

static const char *cmd_take123
      (cmd_parms *parms, void *mconfig,
       const char *one, const char *two, const char *three)


TAKE13

Continuing in the same vein, directives with this syntax take either one or three arguments, but not two. Any missing arguments are passed as NULL.

Function prototype:

static const char *cmd_take13
      (cmd_parms *parms, void *mconfig,
       const char *one, const char *two, const char *three)


RAW_ARGS

This last constant is used for complex directives that the server won't be able to parse on its own. Your module must implement the parsing itself. The corresponding directive handler will be passed everything to the right of the directive name as an unparsed string. It can then use ap_getword() to process the string a word at a time.

The function prototype for RAW_ARGS directive handlers looks like this:

const char *cmd_raw_args
      (cmd_parms *parms, void *mconfig, const char *args)

RAW_ARGS can also be used to implement new container-style directives like <Limit> and <Location> by reading directly from the configuration file using the config_file field of the parms argument. See Section 11.2" later in this chapter for details on reading from this field.

11.1.6. The cmd_parms Structure

A cmd_parms structure is the first argument passed to all directive handlers. It contains a miscellaneous collection of information about the server configuration process. You may never actually need to use this argument, but it is available for certain advanced configuration tasks, such as implementing new container directives.

Example 11.2 gives the cmd_parms typedef, copied from http_config.h. The extensive (and sometimes wry) comments have been condensed to save some space.

Example 11.2. The cmd_parms Structure (from http_config.h)
typedef struct {
   void *info;                /* argument to command from cmd table */
   int override;              /* same as req_override */
   int limited;               /* which methods are <Limit>ed */
   configfile_t *config_file; /* filehandle for reading from config stream */
   pool *pool;                /* long-term resource pool */
   pool *temp_pool;           /* short-term resource pool */
   server_rec *server;        /* server record */
   char *path;                /* directive path information */
   const command_rec *cmd;    /* copy of command_rec entry */
   const char *end_token;     /* end token for container directives */
} cmd_parms;

Here is a brief description of each of the fields in this structure:


void *info

This field contains a copy of the cmd_data field in the current directive's command record. It is typically used for passing static information to the directive handler.


int override

The override field contains a copy of the args_how field in the current directive's command record.


int limited

If the directive is contained within a <Limit> section, this field contains a bit mask representing the method numbers that the section applies to. This bit mask is constructed from the method numbers in the same way as described in Section 10.7.6.


configfile_t *config_ file

This is a filehandle-like data type from which you can read raw text from the current configuration file. See Section 11.2" later in this chapter for details on using this field.


pool *pool

This is a resource pool that persists for the lifetime of the server. It is only destroyed when the server is restarted or shutdown. If you wish to allocate truly long-term configuration information, this is the pool to use.


pool *temp_pool

In contrast, this pool pointer is available only within the configuration phase during server startup. It is destroyed before the first request is served. It is handy for allocating space for scratch data that your module won't need after configuration is completed.


server_rec *server

This field contains a pointer to the server_rec for the current (virtual) host. You will need to use it when processing server-specific configuration directives in order to retrieve the server-specific configuration record.


char *path

When the handler is called to process a directory-specific directive, the path will contain whatever is the argument of the enclosing <Directory>, <Location>, or <Files> section. For <Directory> and <Location>, this will be the path of the current directory. For <Files>, it will be the text of the regular expression or glob match. If the handler is being called to process a directive located in an access control file, path will contain the path to the directory containing the .htaccess file.

If the directive is called in a server context (either in the main part of a configuration file or a <VirtualHost> section), path will be an empty string.

The path field is used by two frequent idioms. One idiom is used when you want a directive to be available only in a per-directory context, such as a .htaccess file. This effect is achieved by the following fragment of a directive-processing routine:

static const char *foo_cmd(cmd_parms *parms, void *mconfig, ...)
{
    foo_dir_config *cfg = (foo_dir_config *)mconfig;
    if (parms->path == NULL || cfg == NULL) {
       return "foo: only valid in per-directory context";
    }
    ...

The other idiom is used when you want a directive to be valid for processing directives located both inside and outside of <Directory> sections and to operate on the per-server configuration record when outside a directory context but on the per-directory record when inside a directory context:

static const char *foo_cmd(cmd_parms *parms, void  *mconfig, ...)
{
   foo_dir_conf *dconf = (foo_dir_conf *)mconfig;
   foo_srv_conf *sconf = (foo_srv_conf *)
        ap_get_module_config(parms->server->module_config, &foo_module);

   if (parms->path == NULL) {
        ...configure sconf...
   }
   else {
       ...configure dconf...
   }
}


const command_rec *cmd

This field points back to the command_rec entry that describes the directive that the current handler is responsible for.


const char *end_token

When Apache is processing the contents of a container section such as <Directory>, end_token contains the character string that will terminate the section, e.g., </Directory>. end_token is used internally by Apache's ap_srm_command_loop( ) function (described later in this chapter) but is rarely, if ever, needed by modules.

11.1.7. Accessing Module Configuration Data

The last piece in the puzzle is a way for modules to get access to their configuration data at request time, from within a transaction phase handler. This need is satisfied by the ap_get_module_config() call, and its rarely used sibling, ap_set_module_config().


void * ap_get_module_config (void *conf_vector, module *m)

Modules can use ap_get_module_config() to fetch both per-directory and per-server configuration data. To fetch per-directory data, pass the function the contents of the request record's per_dir_config field as the first argument, and the address of the module's own module structure as the second:

hello_dir_config *cfg = (hello_dir_config *)
        ap_get_module_config(r->per_dir_config, &hello_module);

The function result is a void*. For clarity you should cast it to correct type in order to access the configuration data structure's fields, although technically many C compilers allow you to assign void pointers to typed variables without complaining. You'll see examples of both styles in the standard Apache modules.

Do not make the mistake of using the request record's request_config field here. The request_config is a spare (and usually empty) field that a module can use to pass configuration information to subrequests. We'll touch on this shortly.

To fetch per-server data, use the configuration vector stored in the server record's module_config field as the first argument:

traffic_server_config *cfg = (traffic_server_config *)
    ap_get_module_config(r->server->module_config, &traffic_module);

In case you're wondering, and module_config fields are actually pointers to a private Apache type known as the "configuration vector." However, this data type doesn't contain any user-serviceable parts and so is presented to the visible part of the API as an opaque void pointer.


void ap_set_module_config (void *conf_vector, module *m, void *val)

Modules don't often call this function directly, as it is called for them by the internal configuration mechanism. When a new per-directory or per-server module configuration is created, Apache saves a pointer to it in a vector of configuration records, indexed by the address of your module. A copy of this vector eventually appears in the server record's module_config field or in the request record's per_dir_config field. Given a configuration vector, a module pointer, and the configuration data block, ap_set_module_config() appends the configuration information to the vector for later retrieval by ap_get_module_config().

Some modules, such as mod_negotiation, don't bother with a per-server config creator because their entire configuration consists of an "on" or "off" Boolean. Instead, the directive handlers for these modules simply call ap_set_module_config() to set their configuration block to NULL when their state is off or non-NULL when their state is on. This is not a recommended practice!

Another use for ap_set_module_config() is to pass per-request configuration data to subrequests via the request record's request_config field. This field usually points to an empty configuration vector, but handlers are free to append their own configuration data to the vector. The information is then available for use by subrequests and by handlers for later phases of the transaction. Any information stored in request_config is cleared out at the end of the current transaction.

Example:

ap_set_module_config(r->request_config, &my_module, cfg_ptr);

To see some practical examples of the request_config field, examine the source code for mod_include and mod_mime_magic, where the request_config vector is used to stash information passed to subrequests.

To pass simple string messages between different phases and between requests and subrequests, you might consider using the notes table instead.

11.1.8. "Hello World" with All the Bells and Whistles

To show you how custom configuration directives work in practice, let's go ahead and add a directive handler table to the mod_hello example that we introduced long, long ago in Chapter 2.

We start simply by adding the ability for users to configure mod_hello to say hello to something other than "world," which you are surely tired of by now. Once we are done making the required modifications to mod_hello.c, the message "Hello world" can be changed to "Hello Dolly" by adding this line to any configuration file:

HelloTo Dolly

The complete source code for the modified mod_hello.c is shown in Example 11.3.

The first change over the original version is to declare the module structure at the top of the source file. This is to allow the C compiler to handle forward references to the structure within the calls to ap_get_module_config( ). The new line immediately follows the #include lines :

module hello_module;

Next, we declare a new data type to hold our per-directory configuration data, hello_dir_config. Its definition has a single field only, a char* named to, which will hold the argument of the HelloTo directive:

typedef struct {
    char *to;
} hello_dir_config;

Now we need to add a function to create a new per-directory structure. This will be called each time Apache notices one of the module's directives in a directory or location configuration section. Our function simply allocates a new hello_dir_config structure and initializes the to field to contain the default string world:

static void *hello_create_dir_config(pool *p, char *path)
{
   hello_dir_config *cfg =
     (hello_dir_config *)ap_pcalloc(p, sizeof(hello_dir_config));
   cfg->to = "world";
   return (void *)cfg;
}

Now we must modify the module structure so that the per-directory config creator slot is occupied by our new per-directory config creator function:

hello_create_dir_config,  /* per-directory config creator  */

In this case, our configuration data is so simple that there's no need to write a directory config merge function. In the absence of a merge function, Apache will use the most specific configuration record, giving us the most recent value of HelloTo. This is exactly what we want.

What's next? We need a function to actually handle the directive. Once Apache hits the HelloTo directive, it will call this function, passing it a cmd_parms pointer, a pointer to our newly initialized hello_dir_config structure, and the directive argument. The hello_cmd_to() directive handling function is nice and simple. It makes a copy of the argument and stores it into the configuration structure. We return NULL to indicate that all went well:

static const char *hello_cmd_to(cmd_parms *parms,
                                void *mconfig, char *to)
{
    hello_dir_config *cfg = (hello_dir_config *)mconfig;
    cfg->to = (char*)ap_pstrdup(parms->pool, to);
    return NULL;
}

In order for Apache to know about our new directive, we need to create a command_rec table to register it with the module structure. The table declares a single directive named HelloTo whose command handler is hello_cmd_to(). The directive will be available anywhere in the configuration files and will take a single argument. There's no static information to pass to the handler, so this field is NULL:

static command_rec hello_cmds[] =
{
    {
        "HelloTo",                   /* directive name */
        hello_cmd_to,                /* config action routine */
        NULL,                        /* argument to include in call */
        OR_ALL,                      /* where available */
        TAKE1,                       /* arguments */
        "Who we say hello to, default is 'world'" /* description */
    },
    {NULL}
};

Notice that the command_rec table is terminated by a NULL record.

We can now add the hello_cmds array to the command table slot of the module structure. The complete module structure looks like this:

module MODULE_VAR_EXPORT hello_module =
{
    STANDARD_MODULE_STUFF,
    NULL,               /* module initializer                 */
    hello_create_dir_config,  /* per-directory config creator       */
    NULL,               /* dir config merger                  */
    NULL,               /* server config creator              */
    NULL,               /* server config merger               */
    hello_cmds,         /* command table                      */
    hello_handlers,     /* [9]  content handlers              */
    NULL,               /* [2]  URI-to-filename translation   */
    NULL,               /* [5]  check/validate user_id        */
    NULL,               /* [6]  check user_id is valid *here* */
    NULL,               /* [4]  check access by host address  */
    NULL,               /* [7]  MIME type checker/setter      */
    NULL,               /* [8]  fixups                        */
    NULL,               /* [10] logger                        */
    NULL,               /* [3]  header parser                 */
    NULL,               /* process initialization             */
    NULL,               /* process exit/cleanup               */
    NULL                /* [1]  post read_request handling    */
};

The last thing we need to do is to actually put the configuration data to use. In the content handler function hello_handler(), we add the following line to retrieve the configuration structure:

hello_dir_config *cfg =  (hello_dir_config *)
       ap_get_module_config(r->per_dir_config, &hello_module);

Now we change the call to rputs(), where we used to print out "Hello world", into a call to rprintf() that uses the configuration information to print out a customized message:

rprintf(r, "say "hello %s"?
", cfg->to);

Recompile the module, restart the server, and start saying "Hello" to whomever you choose!

Example 11.3. mod_hello with a Custom Configuration Directive
/* file: mod_hello.c */

#include "httpd.h"
#include "http_config.h"
#include "http_core.h"
#include "http_log.h"
#include "http_protocol.h"

/* Forward declaration so that ap_get_module_config() can find us. */
module hello_module;

/* Here's our per-directory configuration data */
typedef struct {
    char *to;
} hello_dir_config;

/* This function is called to create the default per-directory
   configuration */
static void *hello_create_dir_config(pool *p, char *path)
{
    hello_dir_config *cfg =
        (hello_dir_config *)ap_pcalloc(p, sizeof(hello_dir_config));
    cfg->to = "world";
    return (void *)cfg;
}

/* This is the handler for the HelloTo directive */
static const char *hello_cmd_to(cmd_parms *parms, void *mconfig, char *to)
{
    hello_dir_config *cfg = (hello_dir_config *)mconfig;
    cfg->to = (char *)ap_pstrdup(parms->pool, to);
    return NULL;
}

/* Make the name of the content handler known to Apache */
static command_rec hello_cmds[] =
{
    {
        "HelloTo",              /* directive name */
        hello_cmd_to,           /* config action routine */
        NULL,                   /* argument to include in call */
        OR_ALL,                 /* where available */
        TAKE1,                  /* arguments */
        "Who we say hello to, default is 'world'" /* description */
    },
    {NULL}
};

/* here's the content handler */
static int hello_handler(request_rec *r) {
  const char* hostname;
  hello_dir_config *cfg;

  r->content_type = "text/html";
  ap_send_http_header(r);
  hostname = ap_get_remote_host(r->connection,
                                r->per_dir_config, REMOTE_NAME);
  cfg = (hello_dir_config *)
           ap_get_module_config(r->per_dir_config, &hello_module);

  ap_rputs("<HTML>
", r);
  ap_rputs("<HEAD>
", r);
  ap_rputs("<TITLE>Hello There</TITLE>
", r);
  ap_rputs("</HEAD>
", r);
  ap_rputs("<BODY>
", r);
  ap_rprintf(r, "<H1>Hello %s</H1>
", hostname);
  ap_rputs("Here we go again...", r);
  ap_rprintf(r, ""Hello %s"!
", cfg->to);
  ap_rputs("</BODY>
", r);
  ap_rputs("</HTML>
", r);

  return OK;
}

/* Make the name of the content handler known to Apache */
static handler_rec hello_handlers[] =
{
    {"hello-handler", hello_handler},
    {NULL}
};

/* Tell Apache what phases of the transaction we handle */
module MODULE_VAR_EXPORT hello_module =
{
    STANDARD_MODULE_STUFF,
    NULL,               /* module initializer                 */
    hello_create_dir_config,  /* per-directory config creator       */
    NULL,               /* dir config merger                  */
    NULL,               /* server config creator              */
    NULL,               /* server config merger               */
    hello_cmds,         /* command table                      */
    hello_handlers,     /* [9]  content handlers              */
    NULL,               /* [2]  URI-to-filename translation   */
    NULL,               /* [5]  check/validate user_id        */
    NULL,               /* [6]  check user_id is valid *here* */
    NULL,               /* [4]  check access by host address  */
    NULL,               /* [7]  MIME type checker/setter      */
    NULL,               /* [8]  fixups                        */
    NULL,               /* [10] logger                        */
    NULL,               /* [3]  header parser                 */
    NULL,               /* process initialization             */
    NULL,               /* process exit/cleanup               */
    NULL                /* [1]  post read_request handling    */
};
						

11.1.9. Handy Built-in Directive Handlers

It is often the case that a configuration directive will end up simply setting the value of a structure field without doing any additional work. There are a few directive handlers built into the Apache API to handle such common cases.

Since it isn't possible for a built-in function to know anything about the structure of a module-specific data type, these functions work by writing directly into the module's configuration data using pointer arithmetic. You calculate the correct offset into the structure using the XtOffsetOf( ) macro[1] and place this offset into the command table's cmd_data field.

[1] The name XtOffsetOf( ) betrays this macro's origins. It was cut and pasted from the X Windows source code!

For example, in Example 11.3 the HelloTo directive simply sets a string pointer in the to field of the hello_dir_config struct. Instead of writing our own handler to accomplish this task, we can use the generic ap_set_string_slot() call, providing the handler with the offset of the field:

static command_rec hello_cmds[] =
{
    {
        "HelloTo",
        ap_set_string_slot,
        (void *)XtOffsetOf(hello_dir_config, to),
        OR_ALL,
        TAKE1,
        "Who we say hello to, default is 'world'"
    },
    {NULL}
};

The generic directive handlers and the XtOffsetOf() macro are declared in ap_config.h. The following generic directive handlers are available:


const char *ap_set_string_slot (cmd_parms *parms, char *ptr, char *arg)

This handler is used with the TAKE1 prototype to set a string in a configuration structure. The provided offset must point to a char* field. See the previous code snippet for an example of its usage.


const char *ap_set_string_slot_lower (cmd_parms *parms, char *ptr, char *arg)

This function works just the same as ap_set_string_slot() but changes the value of the directive's argument to lowercase before setting the configuration field.


const char *ap_set_ flag_slot (cmd_parms *parms, char *ptr, int flag)

This function is intended to be used with a FLAG prototype. The structure offset should point to an integer field. For example, if we wanted the ability to turn off our "Hello world" message entirely, we could add a new int helloOn field to the hello_dir_config struct and toggle it on and off with a SayHello directive. An appropriate slot in the command table would then look like this:

{
        "SayHello",
        ap_set_flag_slot,
        (void *)XtOffsetOf(hello_dir_config, helloOn),
        OR_ALL,
        FLAG,
        "Should we say Hello, On or Off",
    },

The content handler could now test cfg->helloOn to determine whether to print out that annoyingly repetitive message or not.


const char *ap_set_ file_slot (cmd_parms *parms, char *ptr, char *file)

The last goodie is a built-in handler that works much like ap_set_string_slot() but assumes the argument is a filename. If the filename is not absolute, it is first resolved relative to the configured ServerRoot directory.

For example, let's say we wanted to read our "Hello" message from a file stored on disk. We could add a char* to_file field to the configuration struct and set it using a HelloToFile directive described by this table entry:

{
        "HelloToFile",
        ap_set_file_slot,
        (void *)XtOffsetOf(hello_dir_config, to_file),
        OR_ALL,
        TAKE1,
        "File containing hello message, absolute or server root relative."
    },

With this setup, both HelloToFile /etc/motd and HelloToFile conf/hello.conf would work in a manner consistent with other Apache directives.

11.1.10. Accessing Other Modules' Configuration Information

Although it violates the principles of code encapsulation, there's no reason that one module can't access another module's configuration information. The module simply calls ap_get_module_config( ) with the address of the other module's module table in order to obtain the desired configuration information. You'll need to know the correct data type for the configuration data in order to do anything useful with it, of course.

If you happen to have a C module that needs to tap into the PerlSetVar configuration, you can do so by following this example:

#include "modules/perl/mod_perl.h"

perl_dir_config *c = (perl_dir_config *)
         ap_get_module_config(r->per_dir_config, &perl_module);
table *perl_vars = c->vars;

mod_perl's per-directory configuration data is simply an Apache table. You can access the PerlSetVar keys and values with ap_table_get() :

char *value = ap_table_get(perl_vars, "GuestbookFile");

Before interacting with another module, it is wise to determine if the module has been configured with the server. There are a few functions that can be used to find out if a module is accessible:


module *ap_ find_linked_module (const char *name)

This function will walk the internal list of loaded modules, comparing name with the name field of each module structure. If a match is found, a pointer to the module structure is returned, NULL otherwise. The IfModule configuration directive is implemented using this function. Example:

if(ap_find_linked_module("mod_proxy.c")) {
    /* mod_proxy is loaded */
}


int ap_exists_config_define (char *name)

Apache Version 1.3.1 added a -D command line switch that can be used to pass the server parameter names for conditional configuration with the IfDefine directive. These names exist for the lifetime of the server and can be accessed at any time using the ap_exists_config_define() function. For example, both Stronghold and mod_ssl 's module structures are defined in a file named mod_ssl.c, so ap_ find_linked_module() cannot be used to differentiate between the two. However, mod_ssl passes a -DSSL parameter to the server which can be tested instead:

if(ap_exists_config_define("SSL")) { 
    /* mod_ssl started the server with -DSSL */ 
} 
else { 
   ... 
}

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.117.103.219