dcsimg

Filtering I/O in Apache 2.0: Part 2

By Ryan Bloom (Send Email)
Posted Oct 23, 2000


Last month, I reviewed some of the basic concepts surrounding filtering in Apache 2.0. This month, I will continue to explore filtered I/O by writing a simple filter to add a header and/or footer to every page that the server sends. This filter will not explore all of the power of the filtered design in 2.0, but it is a good start. Ryan Bloom continues his exploration of filtered I/O by passing along a simple filter to add a header and/or footer to every page that the server sends.

Rather than just review the filtering code, I am going to go over the entire module, so that we can all see how everything fits together. The idea behind this filter is that many sites want to add a small piece of text to the top or bottom of every page that is served, with Apache 1.3, this is very difficult to do, but with filtering this becomes very simple. This module will actually offer two methods for adding text to the top and bottom of each page. The first option is to use a file from the disk, and the second is to specify a text string that will be inserted directly into the page.

This module starts with a module specific data structure that is used to store the name of the header and footer files:

typedef struct header_footer_rec {
    const char *headerf;
    const char *headert;
    const char *footerf;
    const char *footert;
} header_footer_rec;                                                               

This structure stores the names of the files and the text that are to be added to each page. For simplicity, this module will allow people to add both text and a file to the same page. The next step in creating this module, is to allow administrators to define files and strings to be added. This is done with a command table and four functions as folows:

static const char *add_header_file(cmd_parms *cmd, void *dummy, const char *arg)
{
    header_footer_rec *d = dummy;
 
    d->headerf = apr_pstrdup(cmd->pool, arg);
    return NULL;
}
 
static const char *add_footer_file(cmd_parms *cmd, void *dummy, const char *arg)

{
    header_footer_rec *d = dummy;
 
    d->footerf = apr_pstrdup(cmd->pool, arg);
    return NULL;
}
 
static const char *add_header_text(cmd_parms *cmd, void *dummy, const char *arg)
{
    header_footer_rec *d = dummy;
 
    d->headert = apr_pstrdup(cmd->pool, arg);
    return NULL;
}
 
static const char *add_footer_text(cmd_parms *cmd, void *dummy, const char *arg)
{
    header_footer_rec *d = dummy;
 
    d->footert = apr_pstrdup(cmd->pool, arg);
    return NULL;
}
 
static const command_rec dir_cmds[] =
{
    AP_INIT_TAKE1("FooterFile", add_footer_file, NULL, ACCESS_CONF || OR_FILEINFO,
                  "a file name"),
    AP_INIT_TAKE1("HeaderFile", add_header_file, NULL, ACCESS_CONF || OR_FILEINFO,
                  "a file name"),
    AP_INIT_TAKE1("FooterText", add_footer_text, NULL, ACCESS_CONF || OR_FILEINFO,
                  "a file name"),
    AP_INIT_TAKE1("HeaderText", add_header_text, NULL, ACCESS_CONF || OR_FILEINFO,
                  "a file name"),
    {NULL}
};                                                                                 

That's all of the bookkeeping we need to do in order to make the module work. Now, we can get down to the filter itself. The first step in creating the filter is to register the function. This is done in the register_hook phase, where we announce to Apache that there is a hook known as HEADERFOOTER that is a content filter and is implemented with the hf_filter function:

static void hf_register_hook(void)
{
    ap_register_output_filter("HEADERFOOTER", hf_filter, AP_FTYPE_CONTENT);
}

Now, we have to actually write the filter function. This is done in a few steps. The first part of the filter is the filter context structure. This structure will be stored in the ctx pointer in the ap_filter_t structure. In our module, this is:

Page 1 of 4


Comment and Contribute

Your name/nickname

Your email

(Maximum characters: 1200). You have characters left.