Show Contents Previous Page Next Page
Chapter 10 - C API Reference Guide, Part I The Table API In this section... Introduction Show Contents Go to Top Previous Page Next Page Apache provides a general API for creating and maintaining
lookup tables. Apache tables are ubiquitous, used for everything
from storing the current request's outgoing HTTP headers to
maintaining the list of environment variables passed to subprocesses.
Tables are similar to Perl hashes in that they are lists of key/value pairs.
However, unlike a Perl hash, keys are case-insensitive, and a single key may
correspond to a list of several values.2 In addition,
Apache table keys and values are always strings; arbitrary data types cannot
be used. The table and table_entry Data Types Show Contents Go to Top Previous Page Next Page Currently, a table is an Apache array containing array elements
of the table_entry data type (defined in include/alloc.h):
typedef struct {
char *key; /* the key */
char *val; /* the value */
} table_entry;
When fetching or setting the value of a key, Apache searches
for the key using a simple linear search. Since most tables
are short, this usually doesn't impose a significant overhead.
You will usually not want to access the table_entry
directly, but use API function calls to manipulate the keys
and values for you. If you do read directly from the table_entry ,
a note in the include file indicates that you should check
the key for null. This is because the table_entry
may be made part of a more sophisticated hash table in the
future. The table structure itself is a private data
type intended to be accessed via an opaque table * . If you want to peek at its definition, you
can find it in include/alloc.c. It is equally straightforward:
struct table {
array_header a;
#ifdef MAKE_TABLE_PROFILE
void *creator;
#endif
};
The MAKE_TABLE_PROFILE define is part of Apache's
debugging code and is usually undefined, so table
is really just an array header. Creating and Copying Tables Show Contents Go to Top Previous Page Next Page If you need a table of key/value pairs that is private to
your own module, you can use these API routines to create
it. You can either create a new empty table or start with
one that is already defined and make a copy of it. These functions
are defined in the include/alloc.h file, which is
automatically included when you bring in include/httpd.h.
table *ap_make_table (pool *p, int nelts)
ap_make_table() creates a new empty table, given
a resource pool pointer and an estimate of the number of
elements you expect to add. If the nelts argument
is nonzero, that number of table_entry tables will be pre-allocated for efficiency. Regardless
of its initial size, the table grows as necessary to accommodate
new entries and table merging operations.
Accessitable *my_table = ap_make_table(p, 25);
table *ap_copy_table (pool *p, const table *t)
This function takes a resource pool and an existing table
and makes a replica of the table, returning a pointer to
the copy. You can then change the contents of the copy without
modifying the original. In this example, we make a copy
of the headers_in table:
table *my_headers = ap_copy_table(r->pool, r->headers_in);
Getting and Setting Table Values Show Contents Go to Top Previous Page Next Page These routines allow you to add new entries to the table,
to change existing ones, and to retrieve entries. const char *ap_table_get (const table *t, const char *key)
Given a table pointer and a key, ap_table_get()
returns the value of the entry at that key as a char * . If there are multiple values for that particular
key, the function will only return the first one it finds,
which will be the first entry added. In this example, we recover the string value of the incoming
User-agent header:
const char *ua = ap_table_get(r->headers_in, "User-agent");
To iterate through the multiple values for the same key, use
the ap_table_do() function described later in this
section.
void ap_table_set (table *t, const char *key, const char *val)
ap_table_set() sets the entry named by key
to the character string in val. If an entry with
the same key already exists, its value is replaced. Otherwise,
a new entry is created. If more than one entry has the same
key, the extraneous ones are deleted, making the key single-valued.
Internally, Apache calls ap_pstrdup() on the key
and the value and stores copies of them in the table. This means
that you are able to change or dispose of the original variables
without worrying about disrupting the table. Here's an example of using this function to set the outgoing
headers field Location to the string http://www.modperl.com/.
Because Location is a single-valued field, ap_table_set()
is the correct call to use:
ap_table_set(r->headers_out, "Location", "http://www.modperl.com/");
void ap_table_setn (table *t, const char *key, const char *val)
This function behaves the same as ap_table_set(),
but the character strings for key and val are
not copied with ap_pstrdup(). You must ensure that the
strings remain valid for the lifetime of the table. The previous
example is a good candidate for ap_table_setn(),
as it uses static strings for both the key and value.
void ap_table_add (table *t, const char *key, const char *val)
This function is similar to ap_table_set(), but existing
entries with the same key are not replaced. Instead, the new entry
is added to the end of the list, making the key multivalued. Internally, Apache calls ap_pstrdup() on the key and
the value, allowing you to change or dispose of the original variables
without worrying about disrupting the table. This example adds several Set-cookie fields to the outgoing
HTTP headers table:
for(i=0; cookies[i]; i++) {
ap_table_add(r->headers_out, "Set-cookie", cookies[i]);
}
void ap_table_addn (table *t, const char *key, const char *val)
This function behaves like ap_table_add(), but key
and val are not duplicated before storing them into the table.
This function saves a little time and memory if you are working with
static strings.
void ap_table_merge (table *t, const char *key, const char *val)
ap_table_merge() merges a new key value into the existing
entry by appending it to what's already there. This is used for comma-delimited
header fields such as Content-language. For example, this
series of calls will result in a value of en, fr, sp in the Content-language field:
ap_table_merge(r->headers_out, "Content-language", "en");
ap_table_merge(r->headers_out, "Content-language", "fr");
ap_table_merge(r->headers_out, "Content-language", "sp");
Like ap_table_set(), the key and value are copied using ap_pstrdup()
before moving them into the table.
void ap_table_mergen (table *t, const char *key, const char *val)
This function is the same as ap_table_merge, but the key
and val arguments are not copied with ap_pstrdup()
before entering them into the table.
void ap_table_unset (table *t, const char *key)
ap_table_unset() deletes all entries having the indicated key.
This example removes the Referer field from the incoming headers,
possibly in preparation for making an anonymous proxy request (see Chapter 7):
ap_table_unset(r->headers_in, "Referer");
void ap_table_do (int (*comp)(void *, const char *, const char *),
void *rec, const table *t,...); ap_table_get() and ap_table_getn() work well for single-valued
keys, but there are a few instances in which keys are not unique. To access
all the values of these keys, you will have to use ap_table_do() to
iterate over the table.
As its prototype indicates, this function is more complicated than
the ones we've seen before. The function's first argument is a pointer
to a callback function that will be called during the iteration process.
The second argument is a void * that can be
used to pass some arbitrary information to the callback. The third argument
is the table * itself. This is followed by
a variable number of char * key arguments,
terminated by a null. ap_ table_do() will iterate over the
table, invoking the callback routine only when a table entries' key
matches a key in the given list. If no keys are given, the function
will invoke the callback routine for all of the table entries. The callback function should have this function prototype:
int callback(void *rec, const char *key, const char *value);
The first argument corresponds to the void *
argument passed to ap_table_do(), and the second and third arguments
are the key and value of the current table entry. The callback should do
whatever work it needs to do (for example, copying the value into an Apache
array), and return a true value. The callback can return 0 in order to abort
ap_table_do() prematurely. Here's a callback that simply prints out the key name and value without
performing further processing:
static int header_trace(void *data, const char *key, const char *val)
{
request_rec *r = (request_rec *)data;
ap_rprintf(r, "Header Field `%s' == `%s'\n", key, val);
return TRUE;
}
Here's how the callback can be used to print out the contents of the outgoing
headers table:
ap_table_do(header_trace, r, r->headers_out, NULL);
And in this example, the callback is only invoked for the Content-type
and Content-length fields:
ap_table_do(header_trace, (void*)r, r->headers_out,
"Content-type", "Content-length", NULL);
Show Contents Go to Top Previous Page Next Page Copyright © 1999 by O'Reilly & Associates, Inc. |