mod_setenvif.c revision 5116c0fd82197f5bf0bbe33155cd36a452fcf6ce
842ae4bd224140319ae7feec1872b93dfd491143fielding/* ====================================================================
842ae4bd224140319ae7feec1872b93dfd491143fielding * The Apache Software License, Version 1.1
842ae4bd224140319ae7feec1872b93dfd491143fielding * Copyright (c) 2000-2001 The Apache Software Foundation. All rights
842ae4bd224140319ae7feec1872b93dfd491143fielding * reserved.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * Redistribution and use in source and binary forms, with or without
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * modification, are permitted provided that the following conditions
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * 1. Redistributions of source code must retain the above copyright
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * notice, this list of conditions and the following disclaimer.
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.
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 * 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 * 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 * 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 * 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 * 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.
0568280364eb026393be492ebc732795c4934643jorton * Set environment variables based on matching request headers or
0568280364eb026393be492ebc732795c4934643jorton * attributes against regex strings
0568280364eb026393be492ebc732795c4934643jorton * Paul Sutton <paul@ukweb.com> 27 Oct 1996
0568280364eb026393be492ebc732795c4934643jorton * Based on mod_browser by Alexei Kosut <akosut@organic.com>
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
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * SetEnvIf name regex var ...
796e4a7141265d8ed7036e4628161c6eafb2a789jorton * where name is either a HTTP request header name, or one of the
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * special values (see below). The 'value' of the header (or the
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * value of the special value from below) are compared against the
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * regex argument. If this is a simple string, a simple sub-string
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * match is performed. Otherwise, a request expression match is
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * 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 * Normally the strings are compared with regard to case. To ignore
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * case, use the directive SetEnvIfNoCase instead.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * Special values for 'name' are:
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * remote_host Remote host name (if available)
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe * remote_addr Remote IP address
e8f95a682820a599fe41b22977010636be5c2717jim * remote_user Remote authenticated user (if any)
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe * request_method Request method (GET, POST, etc)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * request_uri Requested URI
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * To set the enviroment variable LOCALHOST if the client is the local
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * SetEnvIf remote_addr 127.0.0.1 LOCALHOST
713a2b68bac4aeb1e9c48785006c0732451039depquerna * To set LOCAL if the client is the local host, or within our company's
713a2b68bac4aeb1e9c48785006c0732451039depquerna * domain (192.168.10):
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * SetEnvIf remote_addr 192.168.10. LOCAL
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * SetEnvIf remote_addr 127.0.0.1 LOCALHOST
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * This could be written as:
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe * SetEnvIf remote_addr (127.0.0.1|192.168.10.) LOCAL
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholestypedef struct {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes apr_table_t *features; /* env vars to set (or unset) */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes enum special special_type; /* is it a "special" header ? */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholestypedef struct {
8113dac419143273351446c3ad653f3fe5ba5cfdwrowe * These routines, the create- and merge-config functions, are called
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * for both the server-wide and the per-directory contexts. This is
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * because the different definitions are used at different times; the
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * server-wide ones are used in the post-read-request phase, and the
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * per-directory ones are used during the header-parse phase (after
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * the URI has been mapped to a file and we have anything from the
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * .htaccess file and <Directory> and <Files> containers).
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes sei_cfg_rec *new = (sei_cfg_rec *) apr_palloc(p, sizeof(sei_cfg_rec));
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes new->conditionals = apr_array_make(p, 20, sizeof(sei_entry));
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes return (void *) new;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesstatic void *create_setenvif_config_svr(apr_pool_t *p, server_rec *dummy)
8113dac419143273351446c3ad653f3fe5ba5cfdwrowestatic void *create_setenvif_config_dir(apr_pool_t *p, char *dummy)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesstatic void *merge_setenvif_config(apr_pool_t *p, void *basev, void *overridesv)
f43b67c5a9d29b572eac916f8335cedc80c908bebnicholes sei_cfg_rec *a = apr_pcalloc(p, sizeof(sei_cfg_rec));
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes sei_cfg_rec *base = basev, *overrides = overridesv;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes a->conditionals = apr_array_append(p, base->conditionals,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * any non-NULL magic constant will do... used to indicate if REG_ICASE should
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesstatic const char *add_setenvif_core(cmd_parms *cmd, void *mconfig,
68d5e906a21c3abe1ebd0da30d2f0e8e4c2ad28cjim const char *feature;
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes * Determine from our context into which record to put the entry.
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes * cmd->path == NULL means we're in server-wide context; otherwise,
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes * we're dealing with a per-directory setting.
ebe5305f8b22507374358f32b74d12fb50c05a25covener : (sei_cfg_rec *) ap_get_module_config(cmd->server->module_config,
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes entries = (sei_entry *) sconf->conditionals->elts;
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes /* get regex */
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes return apr_pstrcat(cmd->pool, "Missing regular expression for ",
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * If we've already got a sei_entry with the same name we want to
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * just copy the name pointer... so that later on we can compare
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes * two header names just by comparing the pointers.
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes for (i = 0; i < sconf->conditionals->nelts; ++i) {
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes /* if the last entry has an identical headername and regex then
54d22ed1c429b903b029bbd62621f11a9e286137minfrin * merge with it
54d22ed1c429b903b029bbd62621f11a9e286137minfrin /* no match, create a new entry */
7add8f7fb048534390571801b7794f71cd9e127abnicholes else if (!strcasecmp(fname, "request_protocol")) {
7add8f7fb048534390571801b7794f71cd9e127abnicholes for ( ; ; ) {
e8f95a682820a599fe41b22977010636be5c2717jim return apr_pstrcat(cmd->pool, "Missing envariable expression for ",
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholesstatic const char *add_setenvif(cmd_parms *cmd, void *mconfig,
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes const char *args)
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes /* get header name */
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes return apr_pstrcat(cmd->pool, "Missing header-field name for ",
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes return add_setenvif_core(cmd, mconfig, fname, args);
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes * This routine handles the BrowserMatch* directives. It simply turns around
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes * and feeds them, with the appropriate embellishments, to the general-purpose
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes * command handler.
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholesstatic const char *add_browser(cmd_parms *cmd, void *mconfig, const char *args)
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes return add_setenvif_core(cmd, mconfig, "User-Agent", args);
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes OR_FILEINFO, "A header-name, regex and a list of variables."),
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes AP_INIT_RAW_ARGS("SetEnvIfNoCase", add_setenvif, ICASE_MAGIC,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes OR_FILEINFO, "a header-name, regex and a list of variables."),
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes AP_INIT_RAW_ARGS("BrowserMatch", add_browser, NULL,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes OR_FILEINFO, "A browser regex and a list of variables."),
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes AP_INIT_RAW_ARGS("BrowserMatchNoCase", add_browser, ICASE_MAGIC,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes OR_FILEINFO, "A browser regex and a list of variables."),
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * This routine gets called at two different points in request processing:
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * once before the URI has been translated (during the post-read-request
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * phase) and once after (during the header-parse phase). We use different
54d22ed1c429b903b029bbd62621f11a9e286137minfrin * config records for the two different calls to reduce overhead (by not
54d22ed1c429b903b029bbd62621f11a9e286137minfrin * re-doing the server-wide settings during directory processing), and
54d22ed1c429b903b029bbd62621f11a9e286137minfrin * signal which call it is by having the earlier one pass a flag to the
54d22ed1c429b903b029bbd62621f11a9e286137minfrin * later one.
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes const char *val;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (apr_table_get(r->notes, SEI_MAGIC_HEIRLOOM) == NULL) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes apr_table_set(r->notes, SEI_MAGIC_HEIRLOOM, "post-read done");
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes sconf = (sei_cfg_rec *) ap_get_module_config(r->server->module_config,
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes sconf = (sei_cfg_rec *) ap_get_module_config(r->per_dir_config,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes entries = (sei_entry *) sconf->conditionals->elts;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes for (i = 0; i < sconf->conditionals->nelts; ++i) {
54d22ed1c429b903b029bbd62621f11a9e286137minfrin /* Optimize the case where a bunch of directives in a row use the
54d22ed1c429b903b029bbd62621f11a9e286137minfrin * same header. Remember we don't need to strcmp the two header
54d22ed1c429b903b029bbd62621f11a9e286137minfrin * names because we made sure the pointers were equal during
54d22ed1c429b903b029bbd62621f11a9e286137minfrin * configuration.
54d22ed1c429b903b029bbd62621f11a9e286137minfrin switch (b->special_type) {
54d22ed1c429b903b029bbd62621f11a9e286137minfrin val = ap_get_remote_host(r->connection, r->per_dir_config,
54d22ed1c429b903b029bbd62621f11a9e286137minfrin * A NULL value indicates that the header field or special entity
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * wasn't present or is undefined. Represent that as an empty string
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * so that REs like "^$" will work and allow envariable setting
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * based on missing or empty field.
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe apr_array_header_t *arr = apr_table_elts(b->features);
54d22ed1c429b903b029bbd62621f11a9e286137minfrin apr_table_setn(r->subprocess_env, elts[j].key, elts[j].val);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ap_hook_header_parser(match_headers, NULL, NULL, APR_HOOK_MIDDLE);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ap_hook_post_read_request(match_headers, NULL, NULL, APR_HOOK_MIDDLE);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes create_setenvif_config_dir, /* dir config creater */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes merge_setenvif_config, /* dir merger --- default is to override */