mod_setenvif.c revision 48dd659ac15d9054061ddce8f3cd24fa07e0e0dd
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.
0f60998368b493f90120180a93fc2e1e74490872covener * Set environment variables based on matching request headers or
0f60998368b493f90120180a93fc2e1e74490872covener * attributes against regex strings
0f60998368b493f90120180a93fc2e1e74490872covener * Paul Sutton <paul@ukweb.com> 27 Oct 1996
87587593f1a53030e840acc0dec6cc881022ea40covener * 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
0568280364eb026393be492ebc732795c4934643jorton * SetEnvIf name regex var ...
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 * 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)
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 * To set the enviroment variable LOCALHOST if the client is the local
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * SetEnvIf remote_addr 127.0.0.1 LOCALHOST
8113dac419143273351446c3ad653f3fe5ba5cfdwrowe * To set LOCAL if the client is the local host, or within our company's
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * domain (192.168.10):
e8f95a682820a599fe41b22977010636be5c2717jim * SetEnvIf remote_addr 192.168.10. LOCAL
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe * SetEnvIf remote_addr 127.0.0.1 LOCALHOST
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * This could be written as:
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * SetEnvIf remote_addr (127.0.0.1|192.168.10.) LOCAL
f43b67c5a9d29b572eac916f8335cedc80c908bebnicholestypedef struct {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes apr_table_t *features; /* env vars to set (or unset) */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes enum special special_type; /* is it a "special" header ? */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholestypedef struct {
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).
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;
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovenerstatic void *create_setenvif_config_svr(apr_pool_t *p, server_rec *dummy)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesstatic void *create_setenvif_config_dir(apr_pool_t *p, char *dummy)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesstatic void *merge_setenvif_config(apr_pool_t *p, void *basev, void *overridesv)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes 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,
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener * 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,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes const char *feature;
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.
f43b67c5a9d29b572eac916f8335cedc80c908bebnicholes : (sei_cfg_rec *) ap_get_module_config(cmd->server->module_config,
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener /* get regex */
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener return apr_pstrcat(cmd->pool, "Missing regular expression for ",
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 /* if the last entry has an identical headername and regex then
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener * merge with it
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener /* no match, create a new entry */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes else if (!strcasecmp(fname, "request_protocol")) {
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes for ( ; ; ) {
513b324e774c559b579896df131fd7c8471ed529rederpj return apr_pstrcat(cmd->pool, "Missing envariable expression for ",
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholesstatic const char *add_setenvif(cmd_parms *cmd, void *mconfig,
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes const char *args)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* get header name */
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes return apr_pstrcat(cmd->pool, "Missing header-field name for ",
9ad7b260be233be7d7b5576979825cac72e15498rederpj return add_setenvif_core(cmd, mconfig, fname, args);
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.
9ad7b260be233be7d7b5576979825cac72e15498rederpjstatic 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."),
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 * 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.
9ad7b260be233be7d7b5576979825cac72e15498rederpj const char *val;
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,
128a5d93141a86e3afa151e921035a07297c9833rederpj sconf = (sei_cfg_rec *) ap_get_module_config(r->per_dir_config,
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 switch (b->special_type) {
9ad7b260be233be7d7b5576979825cac72e15498rederpj val = ap_get_remote_host(r->connection, r->per_dir_config,
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 apr_array_header_t *arr = apr_table_elts(b->features);
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes apr_table_setn(r->subprocess_env, elts[j].key, elts[j].val);
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 create_setenvif_config_dir, /* dir config creater */
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes merge_setenvif_config, /* dir merger --- default is to override */