mod_setenvif.c revision 48dd659ac15d9054061ddce8f3cd24fa07e0e0dd
842ae4bd224140319ae7feec1872b93dfd491143fielding/* ====================================================================
842ae4bd224140319ae7feec1872b93dfd491143fielding * The Apache Software License, Version 1.1
842ae4bd224140319ae7feec1872b93dfd491143fielding *
842ae4bd224140319ae7feec1872b93dfd491143fielding * Copyright (c) 2000-2001 The Apache Software Foundation. All rights
842ae4bd224140319ae7feec1872b93dfd491143fielding * reserved.
842ae4bd224140319ae7feec1872b93dfd491143fielding *
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * Redistribution and use in source and binary forms, with or without
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * modification, are permitted provided that the following conditions
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * are met:
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes *
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * 1. Redistributions of source code must retain the above copyright
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * notice, this list of conditions and the following disclaimer.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes *
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * 2. Redistributions in binary form must reproduce the above copyright
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * notice, this list of conditions and the following disclaimer in
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * the documentation and/or other materials provided with the
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * distribution.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes *
e8f95a682820a599fe41b22977010636be5c2717jim * 3. The end-user documentation included with the redistribution,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * if any, must include the following acknowledgment:
e8f95a682820a599fe41b22977010636be5c2717jim * "This product includes software developed by the
1747d30b98aa1bdbc43994c02cd46ab4cb9319e4fielding * Apache Software Foundation (http://www.apache.org/)."
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * Alternately, this acknowledgment may appear in the software itself,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * if and wherever such third-party acknowledgments normally appear.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes *
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * 4. The names "Apache" and "Apache Software Foundation" must
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * not be used to endorse or promote products derived from this
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * software without prior written permission. For written
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * permission, please contact apache@apache.org.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes *
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * 5. Products derived from this software may not be called "Apache",
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * nor may "Apache" appear in their name, without prior written
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * permission of the Apache Software Foundation.
5c0419d51818eb02045cf923a9fe456127a44c60wrowe *
5c0419d51818eb02045cf923a9fe456127a44c60wrowe * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
d266c3777146d36a4c23c17aad6f153aebea1bf4jorton * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
d266c3777146d36a4c23c17aad6f153aebea1bf4jorton * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
d266c3777146d36a4c23c17aad6f153aebea1bf4jorton * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
d266c3777146d36a4c23c17aad6f153aebea1bf4jorton * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * SUCH DAMAGE.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * ====================================================================
22f8da8087791fcb95b836c8a81937c5a9bba202bnicholes *
22f8da8087791fcb95b836c8a81937c5a9bba202bnicholes * This software consists of voluntary contributions made by many
22f8da8087791fcb95b836c8a81937c5a9bba202bnicholes * individuals on behalf of the Apache Software Foundation. For more
22f8da8087791fcb95b836c8a81937c5a9bba202bnicholes * information on the Apache Software Foundation, please see
22f8da8087791fcb95b836c8a81937c5a9bba202bnicholes * <http://www.apache.org/>.
22f8da8087791fcb95b836c8a81937c5a9bba202bnicholes *
22f8da8087791fcb95b836c8a81937c5a9bba202bnicholes * Portions of this software are based upon public domain software
cd3bbd6d2df78d6c75e5d159a81ef8bdd5f70df9trawick * originally written at the National Center for Supercomputing Applications,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * University of Illinois, Urbana-Champaign.
0f60998368b493f90120180a93fc2e1e74490872covener */
0f60998368b493f90120180a93fc2e1e74490872covener
0f60998368b493f90120180a93fc2e1e74490872covener/*
0f60998368b493f90120180a93fc2e1e74490872covener * mod_setenvif.c
0f60998368b493f90120180a93fc2e1e74490872covener * Set environment variables based on matching request headers or
0f60998368b493f90120180a93fc2e1e74490872covener * attributes against regex strings
0f60998368b493f90120180a93fc2e1e74490872covener *
0f60998368b493f90120180a93fc2e1e74490872covener * Paul Sutton <paul@ukweb.com> 27 Oct 1996
87587593f1a53030e840acc0dec6cc881022ea40covener * Based on mod_browser by Alexei Kosut <akosut@organic.com>
87587593f1a53030e840acc0dec6cc881022ea40covener */
87587593f1a53030e840acc0dec6cc881022ea40covener
87587593f1a53030e840acc0dec6cc881022ea40covener/*
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * Used to set environment variables based on the incoming request headers,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * or some selected other attributes of the request (e.g., the remote host
0568280364eb026393be492ebc732795c4934643jorton * name).
0568280364eb026393be492ebc732795c4934643jorton *
0568280364eb026393be492ebc732795c4934643jorton * Usage:
0568280364eb026393be492ebc732795c4934643jorton *
0568280364eb026393be492ebc732795c4934643jorton * SetEnvIf name regex var ...
0568280364eb026393be492ebc732795c4934643jorton *
0568280364eb026393be492ebc732795c4934643jorton * where name is either a HTTP request header name, or one of the
0568280364eb026393be492ebc732795c4934643jorton * special values (see below). The 'value' of the header (or the
0568280364eb026393be492ebc732795c4934643jorton * value of the special value from below) are compared against the
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * regex argument. If this is a simple string, a simple sub-string
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener * match is performed. Otherwise, a request expression match is
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener * done. If the value matches the string or regular expression, the
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * environment variables listed as var ... are set. Each var can
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * be in one of three formats: var, which sets the named variable
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * (the value value "1"); var=value, which sets the variable to
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * the given value; or !var, which unsets the variable is it has
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * been previously set.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes *
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * Normally the strings are compared with regard to case. To ignore
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * case, use the directive SetEnvIfNoCase instead.
796e4a7141265d8ed7036e4628161c6eafb2a789jorton *
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * Special values for 'name' are:
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes *
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * remote_host Remote host name (if available)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * remote_addr Remote IP address
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * remote_user Remote authenticated user (if any)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * request_method Request method (GET, POST, etc)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * request_uri Requested URI
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes *
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * Examples:
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes *
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * To set the enviroment variable LOCALHOST if the client is the local
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * machine:
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes *
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * SetEnvIf remote_addr 127.0.0.1 LOCALHOST
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes *
8113dac419143273351446c3ad653f3fe5ba5cfdwrowe * To set LOCAL if the client is the local host, or within our company's
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * domain (192.168.10):
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe *
e8f95a682820a599fe41b22977010636be5c2717jim * SetEnvIf remote_addr 192.168.10. LOCAL
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe * SetEnvIf remote_addr 127.0.0.1 LOCALHOST
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes *
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * This could be written as:
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes *
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * SetEnvIf remote_addr (127.0.0.1|192.168.10.) LOCAL
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes#include "apr.h"
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes#include "apr_strings.h"
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
a1790fb35c4b352dab721370985c623a9f8f5062rpluem#define APR_WANT_STRFUNC
713a2b68bac4aeb1e9c48785006c0732451039depquerna#include "apr_want.h"
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes#include "ap_config.h"
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes#include "httpd.h"
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes#include "http_config.h"
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes#include "http_core.h"
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe#include "http_log.h"
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe#include "http_protocol.h"
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesenum special {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes SPECIAL_NOT,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes SPECIAL_REMOTE_ADDR,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes SPECIAL_REMOTE_HOST,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes SPECIAL_REMOTE_USER,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes SPECIAL_REQUEST_URI,
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener SPECIAL_REQUEST_METHOD,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes SPECIAL_REQUEST_PROTOCOL
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes};
f43b67c5a9d29b572eac916f8335cedc80c908bebnicholestypedef struct {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes char *name; /* header name */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes char *regex; /* regex to match against */
8113dac419143273351446c3ad653f3fe5ba5cfdwrowe regex_t *preg; /* compiled regex */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes apr_table_t *features; /* env vars to set (or unset) */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes enum special special_type; /* is it a "special" header ? */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes int icase; /* ignoring case? */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes} sei_entry;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholestypedef struct {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes apr_array_header_t *conditionals;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes} sei_cfg_rec;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesmodule AP_MODULE_DECLARE_DATA setenvif_module;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes/*
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * These routines, the create- and merge-config functions, are called
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener * for both the server-wide and the per-directory contexts. This is
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener * because the different definitions are used at different times; the
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener * server-wide ones are used in the post-read-request phase, and the
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener * per-directory ones are used during the header-parse phase (after
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener * the URI has been mapped to a file and we have anything from the
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * .htaccess file and <Directory> and <Files> containers).
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesstatic void *create_setenvif_config(apr_pool_t *p)
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener{
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes sei_cfg_rec *new = (sei_cfg_rec *) apr_palloc(p, sizeof(sei_cfg_rec));
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes new->conditionals = apr_array_make(p, 20, sizeof(sei_entry));
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes return (void *) new;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes}
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovenerstatic void *create_setenvif_config_svr(apr_pool_t *p, server_rec *dummy)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes{
8113dac419143273351446c3ad653f3fe5ba5cfdwrowe return create_setenvif_config(p);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes}
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesstatic void *create_setenvif_config_dir(apr_pool_t *p, char *dummy)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes{
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes return create_setenvif_config(p);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes}
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesstatic void *merge_setenvif_config(apr_pool_t *p, void *basev, void *overridesv)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes{
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes sei_cfg_rec *a = apr_pcalloc(p, sizeof(sei_cfg_rec));
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes sei_cfg_rec *base = basev, *overrides = overridesv;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes a->conditionals = apr_array_append(p, base->conditionals,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes overrides->conditionals);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes return a;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes}
1f299703465bd9975d94e9f229f76af807442de2covener
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener/*
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener * any non-NULL magic constant will do... used to indicate if REG_ICASE should
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener * be used
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes */
8113dac419143273351446c3ad653f3fe5ba5cfdwrowe#define ICASE_MAGIC ((void *)(&setenvif_module))
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes#define SEI_MAGIC_HEIRLOOM "setenvif-phase-flag"
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesstatic const char *add_setenvif_core(cmd_parms *cmd, void *mconfig,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes char *fname, const char *args)
9ad7b260be233be7d7b5576979825cac72e15498rederpj{
9ad7b260be233be7d7b5576979825cac72e15498rederpj char *regex;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes const char *feature;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes sei_cfg_rec *sconf;
f43b67c5a9d29b572eac916f8335cedc80c908bebnicholes sei_entry *new;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes sei_entry *entries;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes char *var;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes int i;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes int beenhere = 0;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes unsigned icase;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /*
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * Determine from our context into which record to put the entry.
3e6d7277b90d3011db832139afc20efb5f17e203rederpj * cmd->path == NULL means we're in server-wide context; otherwise,
3e6d7277b90d3011db832139afc20efb5f17e203rederpj * we're dealing with a per-directory setting.
3e6d7277b90d3011db832139afc20efb5f17e203rederpj */
3e6d7277b90d3011db832139afc20efb5f17e203rederpj sconf = (cmd->path != NULL)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ? (sei_cfg_rec *) mconfig
f43b67c5a9d29b572eac916f8335cedc80c908bebnicholes : (sei_cfg_rec *) ap_get_module_config(cmd->server->module_config,
e8f95a682820a599fe41b22977010636be5c2717jim &setenvif_module);
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener entries = (sei_entry *) sconf->conditionals->elts;
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener /* get regex */
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener regex = ap_getword_conf(cmd->pool, &args);
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener if (!*regex) {
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener return apr_pstrcat(cmd->pool, "Missing regular expression for ",
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener cmd->cmd->name, NULL);
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener }
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener /*
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener * If we've already got a sei_entry with the same name we want to
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener * just copy the name pointer... so that later on we can compare
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener * two header names just by comparing the pointers.
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener */
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener for (i = 0; i < sconf->conditionals->nelts; ++i) {
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener new = &entries[i];
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener if (!strcasecmp(new->name, fname)) {
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener fname = new->name;
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener break;
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener }
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener }
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener /* if the last entry has an identical headername and regex then
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener * merge with it
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener */
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener i = sconf->conditionals->nelts - 1;
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener icase = cmd->info == ICASE_MAGIC;
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener if (i < 0
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener || entries[i].name != fname
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener || entries[i].icase != icase
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener || strcmp(entries[i].regex, regex)) {
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener /* no match, create a new entry */
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener new = apr_array_push(sconf->conditionals);
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener new->name = fname;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes new->regex = regex;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes new->icase = icase;
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener new->preg = ap_pregcomp(cmd->pool, regex,
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener (REG_EXTENDED | REG_NOSUB
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener | (icase ? REG_ICASE : 0)));
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener if (new->preg == NULL) {
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener return apr_pstrcat(cmd->pool, cmd->cmd->name,
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener " regex could not be compiled.", NULL);
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener }
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener new->features = apr_table_make(cmd->pool, 2);
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener if (!strcasecmp(fname, "remote_addr")) {
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener new->special_type = SPECIAL_REMOTE_ADDR;
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener }
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener else if (!strcasecmp(fname, "remote_host")) {
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener new->special_type = SPECIAL_REMOTE_HOST;
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener }
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener else if (!strcasecmp(fname, "remote_user")) {
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener new->special_type = SPECIAL_REMOTE_USER;
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener }
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener else if (!strcasecmp(fname, "request_uri")) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes new->special_type = SPECIAL_REQUEST_URI;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes else if (!strcasecmp(fname, "request_method")) {
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes new->special_type = SPECIAL_REQUEST_METHOD;
0e05808dc59a321566303084c84b9826a4353cefrederpj }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes else if (!strcasecmp(fname, "request_protocol")) {
b08925593f214f621161742925dcf074a8047e0acovener new->special_type = SPECIAL_REQUEST_PROTOCOL;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
54d22ed1c429b903b029bbd62621f11a9e286137minfrin else {
465bb68501690d7a47bfd2a6129580047d76d8f1rederpj new->special_type = SPECIAL_NOT;
3dfeb02cfb853d8717ca0cc259b59fea610173f5bnicholes }
465bb68501690d7a47bfd2a6129580047d76d8f1rederpj }
e8f95a682820a599fe41b22977010636be5c2717jim else {
3dfeb02cfb853d8717ca0cc259b59fea610173f5bnicholes new = &entries[i];
3dfeb02cfb853d8717ca0cc259b59fea610173f5bnicholes }
54d22ed1c429b903b029bbd62621f11a9e286137minfrin
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes for ( ; ; ) {
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes feature = ap_getword_conf(cmd->pool, &args);
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes if (!*feature) {
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes break;
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes }
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes beenhere++;
ebe5305f8b22507374358f32b74d12fb50c05a25covener
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes var = ap_getword(cmd->pool, &feature, '=');
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes if (*feature) {
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes apr_table_setn(new->features, var, feature);
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes else if (*var == '!') {
513b324e774c559b579896df131fd7c8471ed529rederpj apr_table_setn(new->features, var + 1, "!");
513b324e774c559b579896df131fd7c8471ed529rederpj }
513b324e774c559b579896df131fd7c8471ed529rederpj else {
513b324e774c559b579896df131fd7c8471ed529rederpj apr_table_setn(new->features, var, "1");
513b324e774c559b579896df131fd7c8471ed529rederpj }
513b324e774c559b579896df131fd7c8471ed529rederpj }
513b324e774c559b579896df131fd7c8471ed529rederpj
513b324e774c559b579896df131fd7c8471ed529rederpj if (!beenhere) {
513b324e774c559b579896df131fd7c8471ed529rederpj return apr_pstrcat(cmd->pool, "Missing envariable expression for ",
513b324e774c559b579896df131fd7c8471ed529rederpj cmd->cmd->name, NULL);
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes return NULL;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes}
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholesstatic const char *add_setenvif(cmd_parms *cmd, void *mconfig,
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes const char *args)
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes{
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes char *fname;
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* get header name */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes fname = ap_getword_conf(cmd->pool, &args);
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes if (!*fname) {
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes return apr_pstrcat(cmd->pool, "Missing header-field name for ",
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes cmd->cmd->name, NULL);
9ad7b260be233be7d7b5576979825cac72e15498rederpj }
9ad7b260be233be7d7b5576979825cac72e15498rederpj return add_setenvif_core(cmd, mconfig, fname, args);
9ad7b260be233be7d7b5576979825cac72e15498rederpj}
9ad7b260be233be7d7b5576979825cac72e15498rederpj
9ad7b260be233be7d7b5576979825cac72e15498rederpj/*
9ad7b260be233be7d7b5576979825cac72e15498rederpj * This routine handles the BrowserMatch* directives. It simply turns around
9ad7b260be233be7d7b5576979825cac72e15498rederpj * and feeds them, with the appropriate embellishments, to the general-purpose
9ad7b260be233be7d7b5576979825cac72e15498rederpj * command handler.
9ad7b260be233be7d7b5576979825cac72e15498rederpj */
9ad7b260be233be7d7b5576979825cac72e15498rederpjstatic const char *add_browser(cmd_parms *cmd, void *mconfig, const char *args)
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes{
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes return add_setenvif_core(cmd, mconfig, "User-Agent", args);
54d22ed1c429b903b029bbd62621f11a9e286137minfrin}
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholesstatic const command_rec setenvif_module_cmds[] =
ebe5305f8b22507374358f32b74d12fb50c05a25covener{
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes AP_INIT_RAW_ARGS("SetEnvIf", add_setenvif, NULL,
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes OR_FILEINFO, "A header-name, regex and a list of variables."),
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes AP_INIT_RAW_ARGS("SetEnvIfNoCase", add_setenvif, ICASE_MAGIC,
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes OR_FILEINFO, "a header-name, regex and a list of variables."),
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes AP_INIT_RAW_ARGS("BrowserMatch", add_browser, NULL,
54d22ed1c429b903b029bbd62621f11a9e286137minfrin OR_FILEINFO, "A browser regex and a list of variables."),
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes AP_INIT_RAW_ARGS("BrowserMatchNoCase", add_browser, ICASE_MAGIC,
54d22ed1c429b903b029bbd62621f11a9e286137minfrin OR_FILEINFO, "A browser regex and a list of variables."),
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes { NULL },
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes};
ebe5305f8b22507374358f32b74d12fb50c05a25covener
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes/*
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes * This routine gets called at two different points in request processing:
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes * once before the URI has been translated (during the post-read-request
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes * phase) and once after (during the header-parse phase). We use different
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes * config records for the two different calls to reduce overhead (by not
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * re-doing the server-wide settings during directory processing), and
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes * signal which call it is by having the earlier one pass a flag to the
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * later one.
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes */
b08925593f214f621161742925dcf074a8047e0acovenerstatic int match_headers(request_rec *r)
b08925593f214f621161742925dcf074a8047e0acovener{
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes sei_cfg_rec *sconf;
9ad7b260be233be7d7b5576979825cac72e15498rederpj sei_entry *entries;
9ad7b260be233be7d7b5576979825cac72e15498rederpj apr_table_entry_t *elts;
9ad7b260be233be7d7b5576979825cac72e15498rederpj const char *val;
128a5d93141a86e3afa151e921035a07297c9833rederpj int i, j;
9ad7b260be233be7d7b5576979825cac72e15498rederpj char *last_name;
9ad7b260be233be7d7b5576979825cac72e15498rederpj
128a5d93141a86e3afa151e921035a07297c9833rederpj if (apr_table_get(r->notes, SEI_MAGIC_HEIRLOOM) == NULL) {
128a5d93141a86e3afa151e921035a07297c9833rederpj apr_table_set(r->notes, SEI_MAGIC_HEIRLOOM, "post-read done");
9ad7b260be233be7d7b5576979825cac72e15498rederpj sconf = (sei_cfg_rec *) ap_get_module_config(r->server->module_config,
9ad7b260be233be7d7b5576979825cac72e15498rederpj &setenvif_module);
9ad7b260be233be7d7b5576979825cac72e15498rederpj }
9ad7b260be233be7d7b5576979825cac72e15498rederpj else {
128a5d93141a86e3afa151e921035a07297c9833rederpj sconf = (sei_cfg_rec *) ap_get_module_config(r->per_dir_config,
9ad7b260be233be7d7b5576979825cac72e15498rederpj &setenvif_module);
9ad7b260be233be7d7b5576979825cac72e15498rederpj }
9ab21648975dff7e1b680daf8aea627227ba28f7trawick entries = (sei_entry *) sconf->conditionals->elts;
9ad7b260be233be7d7b5576979825cac72e15498rederpj last_name = NULL;
9ad7b260be233be7d7b5576979825cac72e15498rederpj val = NULL;
9ad7b260be233be7d7b5576979825cac72e15498rederpj for (i = 0; i < sconf->conditionals->nelts; ++i) {
9ad7b260be233be7d7b5576979825cac72e15498rederpj sei_entry *b = &entries[i];
87587593f1a53030e840acc0dec6cc881022ea40covener
87587593f1a53030e840acc0dec6cc881022ea40covener /* Optimize the case where a bunch of directives in a row use the
9ad7b260be233be7d7b5576979825cac72e15498rederpj * same header. Remember we don't need to strcmp the two header
9ad7b260be233be7d7b5576979825cac72e15498rederpj * names because we made sure the pointers were equal during
9ad7b260be233be7d7b5576979825cac72e15498rederpj * configuration.
9ad7b260be233be7d7b5576979825cac72e15498rederpj */
9ad7b260be233be7d7b5576979825cac72e15498rederpj if (b->name != last_name) {
9ad7b260be233be7d7b5576979825cac72e15498rederpj last_name = b->name;
9ad7b260be233be7d7b5576979825cac72e15498rederpj switch (b->special_type) {
9ad7b260be233be7d7b5576979825cac72e15498rederpj case SPECIAL_REMOTE_ADDR:
9ad7b260be233be7d7b5576979825cac72e15498rederpj val = r->connection->remote_ip;
9ad7b260be233be7d7b5576979825cac72e15498rederpj break;
9ad7b260be233be7d7b5576979825cac72e15498rederpj case SPECIAL_REMOTE_HOST:
9ad7b260be233be7d7b5576979825cac72e15498rederpj val = ap_get_remote_host(r->connection, r->per_dir_config,
9ad7b260be233be7d7b5576979825cac72e15498rederpj REMOTE_NAME);
9ab21648975dff7e1b680daf8aea627227ba28f7trawick break;
9ad7b260be233be7d7b5576979825cac72e15498rederpj case SPECIAL_REMOTE_USER:
9ad7b260be233be7d7b5576979825cac72e15498rederpj val = r->user;
9ad7b260be233be7d7b5576979825cac72e15498rederpj break;
9ad7b260be233be7d7b5576979825cac72e15498rederpj case SPECIAL_REQUEST_URI:
9ad7b260be233be7d7b5576979825cac72e15498rederpj val = r->uri;
7add8f7fb048534390571801b7794f71cd9e127abnicholes break;
7add8f7fb048534390571801b7794f71cd9e127abnicholes case SPECIAL_REQUEST_METHOD:
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem val = r->method;
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem break;
7add8f7fb048534390571801b7794f71cd9e127abnicholes case SPECIAL_REQUEST_PROTOCOL:
7add8f7fb048534390571801b7794f71cd9e127abnicholes val = r->protocol;
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes break;
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes case SPECIAL_NOT:
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes val = apr_table_get(r->headers_in, b->name);
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes if (val == NULL) {
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes val = apr_table_get(r->subprocess_env, b->name);
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes }
7add8f7fb048534390571801b7794f71cd9e127abnicholes break;
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes }
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes }
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes /*
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes * A NULL value indicates that the header field or special entity
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes * wasn't present or is undefined. Represent that as an empty string
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes * so that REs like "^$" will work and allow envariable setting
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes * based on missing or empty field.
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes */
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes if (val == NULL) {
7add8f7fb048534390571801b7794f71cd9e127abnicholes val = "";
7add8f7fb048534390571801b7794f71cd9e127abnicholes }
141e1368614dc7564e1627671361b01b4869b491bnicholes
3dfeb02cfb853d8717ca0cc259b59fea610173f5bnicholes if (!ap_regexec(b->preg, val, 0, NULL, 0)) {
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes apr_array_header_t *arr = apr_table_elts(b->features);
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes elts = (apr_table_entry_t *) arr->elts;
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes
e8f95a682820a599fe41b22977010636be5c2717jim for (j = 0; j < arr->nelts; ++j) {
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes if (!strcmp(elts[j].val, "!")) {
ebe5305f8b22507374358f32b74d12fb50c05a25covener apr_table_unset(r->subprocess_env, elts[j].key);
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes }
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes else {
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes apr_table_setn(r->subprocess_env, elts[j].key, elts[j].val);
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes }
3dfeb02cfb853d8717ca0cc259b59fea610173f5bnicholes }
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes }
3dfeb02cfb853d8717ca0cc259b59fea610173f5bnicholes }
3dfeb02cfb853d8717ca0cc259b59fea610173f5bnicholes
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes return DECLINED;
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes}
e8f95a682820a599fe41b22977010636be5c2717jim
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholesstatic void register_hooks(apr_pool_t *p)
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes{
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes ap_hook_header_parser(match_headers, NULL, NULL, APR_HOOK_MIDDLE);
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes ap_hook_post_read_request(match_headers, NULL, NULL, APR_HOOK_MIDDLE);
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes}
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholesmodule AP_MODULE_DECLARE_DATA setenvif_module =
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes{
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes STANDARD20_MODULE_STUFF,
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes create_setenvif_config_dir, /* dir config creater */
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes merge_setenvif_config, /* dir merger --- default is to override */
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes create_setenvif_config_svr, /* server config */
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes merge_setenvif_config, /* merge server configs */
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes setenvif_module_cmds, /* command apr_table_t */
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes register_hooks /* register hooks */
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes};
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes