Pages

Iterating over an Apache apr_table_t

A common data structure that is very useful to have at hand when working with a web server, is an associative array where both key and value are strings. If Apache httpd was developed in C++, they would have probably used an STL unordered_map, but here we are dealing with pure C, so an internal data structure named apr_table_t has been designed expressly for this scope, with a bunch of associated functions for manage it.

Here I am going to write an example that uses apr_table_do() to loop over all the elements in an Apache table.

What I want to do is writing an Apache2 module that generates as output an HTML page listing all the properties in the request header.

If we have a look to the apr_tables.h, we'll find this couple of interesting lines:
typedef int (apr_table_do_callback_fn_t)(
    void* rec, const char* key, const char* value);

int apr_table_do(apr_table_do_callback_fn_t* comp,
    void* rec, const apr_table_t* t, ...);
The apr_table_do() gets as first parameter a callback function, then the module request record, and the Apache table we want to loop on. Finally we specify which tables elements we are interested in, or a NULL if we want to go through all of them.

Here is the function I want to use as callback, a simple output of the current key-value pair:
int print(void* rec, const char* key, const char* value)
{
    request_rec* r = static_cast<request_rec*>(rec); // 1
    ap_rprintf(r, "%s: %s<br />\n", key, value); // 2

    return 1; // 3
}
1. Tiny nuisance, the request_rec is seen by the callback prototype as a void pointer - to allow more flexibility, I reckon - so we need to cast it back to its original type. I was about to check the cast result, but in the end I decided that was a bit too paranoid for such a basic example.
2. Dump the pair to the HTML response that the module is generating.
3. And finally return a non-zero value, to mean success.

In the handler, I'll have something like:
int handler(request_rec* r)
{
    // ...
    apr_table_do(print, r, r->headers_in, NULL);

    // ...
    return OK;
}
The full C++ source code is on github. You should compile it, possibly using a make file like the one showed in the previous post, and make the resulting shared object available to Apache.

In the httpd configuration file, we should explain to Apache how to map a request to the server to a call for our module, and how to load the module:
<Location /info>
    SetHandler info
</Location>

# ...

LoadModule info_module modules/mod_info.so
And what it is left to do, to have the new module available, it is just stop and start your Apache server.

No comments:

Post a Comment