Per-Directory Merger
void *module_dir_merge(pool *pPool, void *base_conf, void *new_conf)
Like the per-server merger, this
is called once for each virtual host (not for each directory). It is
handed the per-server document root per-directory Config (that is,
the one that was created with a NULL
directory
name).
Whenever a request is processed, this function merges all relevant
<Directory>
sections and then merges
.htacess files (interleaved, starting at the
root and working downward), then <File>
and
<Location>
sections, in that order.
Unlike the per-server merger, per-directory merger is called as the
server runs, possibly with different combinations of directory,
location, and file configurations for each request, so it is
important that it copies the configuration (in
new_conf
) if it is going to change it.
Now the reason we chose mod_rewrite.c for the per-directory creator becomes apparent, as it is a little more interesting than most. See Example 21-5.
Example 21-5. mod_rewrite.c
static void *config_perdir_merge(pool *p, void *basev, void *overridesv) { rewrite_perdir_conf *a, *base, *overrides; a = (rewrite_perdir_conf *)pcalloc(p, sizeof(rewrite_perdir_conf)); base = (rewrite_perdir_conf *)basev; overrides = (rewrite_perdir_conf *)overridesv; a->state = overrides->state; a->options = overrides->options; a->directory = overrides->directory; a->baseurl = overrides->baseurl; if (a->options & OPTION_INHERIT) { a->rewriteconds = append_arrays(p, overrides->rewriteconds, base->rewriteconds); a->rewriterules = append_arrays(p, overrides->rewriterules, base->rewriterules); } else { a->rewriteconds = overrides->rewriteconds; a->rewriterules = overrides->rewriterules; } return (void *)a; }
As you can see, this merges the configuration from the base
conditionally, depending on whether the new configuration specified
an INHERIT
option.
Once more, the only change in 2.0 is that pool
has
become apr_pool_t
. See Example 21-6 for an excerpt from
mod_env.c.
Example 21-6. mod_env.c
static void *merge_env_dir_configs(pool *p, void *basev, void *addv) { env_dir_config_rec *base = (env_dir_config_rec *) basev; env_dir_config_rec *add = (env_dir_config_rec *) addv; env_dir_config_rec *new = (env_dir_config_rec *) ap_palloc(p, sizeof(env_dir_config_rec)); table *new_table; table_entry *elts; array_header *arr; int i; const char *uenv, *unset; new_table = ap_copy_table(p, base->vars); arr = ap_table_elts(add->vars); elts = (table_entry *)arr->elts; for (i = 0; i < arr->nelts; ++i) { ap_table_setn(new_table, elts[i].key, elts[i].val); } unset = add->unsetenv; uenv = ap_getword_conf(p, &unset); while (uenv[0] != '\0') { ap_table_unset(new_table, uenv); uenv = ap_getword_conf(p, &unset); } new->vars = new_table; new->vars_present = base->vars_present || add->vars_present; return new; }
This function creates a new configuration into which it then copies
the base
vars
table (a table of
environment variable names and values). It then runs through the
individual entries of the addv
vars
table, setting them in the new table. It does
this rather than use overlay_tables()
because
overlay_tables()
does not deal with duplicated
keys. Then the addv
configuration’s unsetenv
(which
is a space-separated list of environment variables to unset) unsets
any variables specified to be unset for addv
’s server.
The 2.0 version of this function has a number of alterations, but on close inspection is actually very much the same, allowing for differences in function names and some rather radical restructuring:
static void *merge_env_dir_configs(apr_pool_t *p, void *basev, void *addv) { env_dir_config_rec *base = basev; env_dir_config_rec *add = addv; env_dir_config_rec *res = apr_palloc(p, sizeof(*res)); const apr_table_entry_t *elts; const apr_array_header_t *arr; int i; res->vars = apr_table_copy(p, base->vars); res->unsetenv = NULL; arr = apr_table_elts(add->unsetenv); elts = (const apr_table_entry_t *)arr->elts; for (i = 0; i < arr->nelts; ++i) { apr_table_unset(res->vars, elts[i].key); } arr = apr_table_elts(add->vars); elts = (const apr_table_entry_t *)arr->elts; for (i = 0; i < arr->nelts; ++i) { apr_table_setn(res->vars, elts[i].key, elts[i].val); } return res; }