threebit.NET Tutorial Two
[threebit.net] [tutorial home]

This tutorial guides the reader through the portions of the Apache API that are used by modules to control their configuration. For the moment, we will introduce the handling of a single server-wide configuration directive.

This module builds on Tutorial 1 by allowing the message that is written to the error log to be customized. Again, this is a trivial task, but I hope that is makes for a clear example of how to use the API to perform a task, without confusing the topic by doing something actually usefull (that's left to you! haa ha!).

# Throughout the tutorial, look for links to Apache's
# LXR website http://lxr.webperf.org/
# For example, clink on AP_MODULE_DECLARE_DATA below.
module AP_MODULE_DECLARE_DATA tut2_module;

Preparation

If you do not plan to compile and run the code presented here, you can skip this step. Otherwise, complete the preparation step from Tutorial One. After doing so the following should be true:

mod_tut2.c

The source code for this module is contained in one file (source code). The other files included with mod_tut2 were explained during Tutorial 1 and I will not duplicate their explanation here. Those portions of this module's source code that have not been changed since Tutorial 1 will also not be explained here.
#ifndef DEFAULT_MODTUT2_STRING
#define DEFAULT_MODTUT2_STRING "apache2_mod_tut2: A request was made."
#endif
Here we define the default string that will be written to the error log if the module has been loaded but the ModuleTutorialString configuration directive was not detected in httpd.conf.
module AP_MODULE_DECLARE_DATA tut2_module;
The AP_MODULE_DECLARE_DATA macro is used by a module to declare itself to the httpd core. The apache convention for naming the identifier is to use UNIQUE_NAME-module. That said, most people refer to a module by the reverse - hence, I call this module mod_tut2. I haven't been around long enough to know why this developed but somehow it did. In case you don't believe me, Auto Index is called mod_autoindex, but it's module identifier is autoindex_module.
typedef struct {
  char *string;
} modtut2_config;
We will need to store the customizable string somewhere - this struct will be used to do so. It is silly to use a struct to hold a single string but we may as well start of with a struct because it won't be long until our module needs a richer configuration.
static void *create_modtut2_config(apr_pool_t *p, server_rec *s)
{
  // This module's configuration structure.
  modtut2_config *newcfg;

  // Allocate memory from the provided pool.
  newcfg = (modtut2_config *) apr_pcalloc(p, sizeof(modtut2_config));

  // Set the string to a default value.
  newcfg->string = DEFAULT_MODTUT2_STRING;

  // Return the created configuration struct.
  return (void *) newcfg;
}
This function will be called once by the httpd core to create the initial module configuration. This is accomplished by allocating space for the struct from the provided apr_pool_t. A malloc function provided by APR is used so that it is impossible to leak memory during Apache's runtime - in other words, this module does not need to worry about freeing any memory in the future because when the pool is released, the memory allocated to this module's configuration is also automatically released. This pattern is used extensively throughout Apache.
static const command_rec mod_tut2_cmds[] =
{
  AP_INIT_TAKE1(
    "ModuleTutorialString",
    set_modtut2_string,
    NULL,
    RSRC_CONF,
    "ModTut2String (string) The error_log string."
  ),
  {NULL}
};
This httpd core is responsible for reading and parsing the httpd.conf configuration file. By default, Apache knows how to handle the default configuration directives. The array of command_rec structures above is passed to the httpd core by this module to declare a new configuration directive.

AP_INIT_TAKE1 - This macro declares a configuration directive that takes only one argument. The httpd core will take care of guaranteeing that the configuration is valid (a minimum and maximum of one argument) before bothering to call the provided function. This reduces alot of duplication within each module. There are several options here depending on the purpose of the configuration directive (AP_INIT_NO_ARGS, AP_INIT_RAW_ARGS, AP_INIT_TAKE2, etc etc).

"ModuleTutorialString" - The configuration directive that may now appear in httpd.conf. I haven't looked it up, but I imagine there is a best-practices guide for creating configuration directives.

set_modtut2_string - This is the function that will be called by the httpd core when the configuration directive is detected (assuming it is properly formatted. This function is covered in detail below.

NULL - I don't know what this is for yet. :)

Update (2003.10.26) Maurizio Codogno contributes via email:
In Tutorial 2 you write that you don't yet know the meaning of the fourth field in macro AP_INIT_TAKE1 and similar, which usually is set as NULL. If I read the source correctly, this is used as a structure to send further data to the initializing function - the second parameter, "void *mconfig", when it is called.

RSRC_CONF - This field is used to state where the configuration directive may appear. By using RSRC_CONF we have stated that it can only appear outside of a <Directive> or <Location> scope. I *think* that means it can only be used globally, but you should confirm that.

Usage Message - In case of syntax errors, the httpd core will return this message to the user.

{NULL} - This is just a null placeholder in the array of command_rec structs. It is used to signal the end of new configuration directives.

static const char *set_modtut2_string(cmd_parms *parms,
  void *mconfig, const char *arg)
{
  modtut2_config *s_cfg = ap_get_module_config(
    parms->server->module_config, &tut2_module);

  s_cfg->string = (char *) arg;

  return NULL;
}
This function will be called by the httpd core when the configuration directive we specify later on is encountered in httpd.conf. Notice that it does not malloc space to hold the new configuration. Instead, the ap_get_module_config function is used to obtain it - somehow the httpd core will end up calling create_modtut2_config for us if it hasn't already.

Once the configuration has been obtained, we set the value of the string member to that of the provided argument. We do not need to make a copy of the argument because it is safe to use as is (I read that in the source somewhere, but I have lost the reference to it.)

Finally, we return NULL for success. We could have returned a (char*) containing an error message; httpd will return the string to the user in such a case.

static int mod_tut2_method_handler (request_rec *r)
{
  // Get the module configuration
  modtut2_config *s_cfg = ap_get_module_config(
    r->server->module_config, &tut2_module);

  // Send a message to the log file.
  // [thanks to Min Xu for the security suggestion]
  fprintf(stderr,"%s",s_cfg->string);

  // [deleted - trying to be brief]
}
And finally, the real workhorse. This function is called for each HTTP request. Again, we use ap_get_module_config to obtain the module configuration, though this time we do so by referencing it from the request record. The configured string is written to the error_log stream.
module AP_MODULE_DECLARE_DATA tut2_module =
{
  STANDARD20_MODULE_STUFF,
  NULL,
  NULL,
  create_modtut2_config,
  NULL,
  mod_tut2_cmds,
  mod_tut2_register_hooks,
};
And now we make another call to AP_MODULE_DECLARE_DATA to re-declare the module along with more information. This time around we provide two more details:

create_modtut2_config - Here we tell the httpd core what function should be called when the module configuration data needs to be created/allocated.

mot_tut2_cmds - Here we pass in the list of new configuration directives.

mod_tut2_register_hooks and STANDARD20_MODULE_STUFF are unchanged from the previous module.

Compile, Install, Run

Now it is time to compile and install the module. See the previous tutorial for an explanation of what's going on here.
cd $TUTORIAL_HOME/apache2_modules/tut2
aclocal
autoconf
automake -a
./configure --with-apache=$TUTORIAL_HOME/apache2
make
$TUTORIAL_HOME/apache2/bin/apxs -i -a -n tut2 libmodtut2.la
This module has not been installed. You may want to confirm that only mod_tut2 is enabled if you ran mod_tut1 previously.
# LoadModule tut1_module        modules/libmodtut1.so
LoadModule tut2_module        modules/libmodtut2.so
Also, if you want to customize the string then add the ModuleTutorialString directive to httpd.conf too. The last line in httpd.conf should be okay for this.
ModuleTutorialString "You need to put quotes around multiple words."
Restart Apache so mod_tut2 get's loaded. It's always a good idea to check the configuration first too.
# check the configuration then restart apache
cd $TUTORIAL_HOME/apache2
bin/apachectl configtest
bin/apachectl stop
bin/apachectl start
# make a request to cause a message to be written
lynx --source http://localhost:21000 | grep success
# look for the message in the error log.
tail -100l logs/error_log 

$Id: tutorial2.html,v 1.12 2004/01/29 05:02:59 kevino Exp $