mod_headers.c revision 89ea31761658f422cf21cd3b0224dc5fe95cccd3
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein/* Copyright 1999-2004 The Apache Software Foundation
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein *
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * Licensed under the Apache License, Version 2.0 (the "License");
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * you may not use this file except in compliance with the License.
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * You may obtain a copy of the License at
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein *
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * http://www.apache.org/licenses/LICENSE-2.0
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein *
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * Unless required by applicable law or agreed to in writing, software
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * distributed under the License is distributed on an "AS IS" BASIS,
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * See the License for the specific language governing permissions and
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * limitations under the License.
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein */
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein/*
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * mod_headers.c: Add/append/remove HTTP response headers
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * Written by Paul Sutton, paul@ukweb.com, 1 Oct 1996
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein *
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * The Header directive can be used to add/replace/remove HTTP headers
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * within the response message. The RequestHeader directive can be used
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * to add/replace/remove HTTP headers before a request message is processed.
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * Valid in both per-server and per-dir configurations.
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein *
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * Syntax is:
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein *
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * Header action header value
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * RequestHeader action header value
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein *
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * Where action is one of:
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * set - set this header, replacing any old value
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * add - add this header, possible resulting in two or more
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * headers with the same name
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * append - append this text onto any existing header of this same
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * unset - remove this header
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein *
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * Where action is unset, the third argument (value) should not be given.
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * The header name can include the colon, or not.
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein *
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * The Header and RequestHeader directives can only be used where allowed
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * by the FileInfo override.
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein *
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * When the request is processed, the header directives are processed in
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * this order: firstly, the main server, then the virtual server handling
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * this request (if any), then any <Directory> sections (working downwards
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * from the root dir), then an <Location> sections (working down from
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * shortest URL component), the any <File> sections. This order is
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * important if any 'set' or 'unset' actions are used. For example,
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * the following two directives have different effect if applied in
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * the reverse order:
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein *
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * Header append Author "John P. Doe"
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * Header unset Author
f4c310fd2555c6faca1f980f00b161eadb089023gstein *
f4c310fd2555c6faca1f980f00b161eadb089023gstein * Examples:
f4c310fd2555c6faca1f980f00b161eadb089023gstein *
f4c310fd2555c6faca1f980f00b161eadb089023gstein * To set the "Author" header, use
f4c310fd2555c6faca1f980f00b161eadb089023gstein * Header add Author "John P. Doe"
cccd31fa4a72fe23cc3249c06db181b274a55a69gstein *
1f6e6566a4ce31a0b95d5400c36d0aaff7a6e94agstein * To remove a header:
8a46775d163c06a8c51d1b0a3f2edfde945cb1d8stoddard * Header unset Author
f5ec9b038bb9db933072ba2c0a8e7bb2a3cedbdagstein *
cccd31fa4a72fe23cc3249c06db181b274a55a69gstein */
cccd31fa4a72fe23cc3249c06db181b274a55a69gstein
cccd31fa4a72fe23cc3249c06db181b274a55a69gstein#include "apr.h"
cccd31fa4a72fe23cc3249c06db181b274a55a69gstein#include "apr_lib.h"
f4c310fd2555c6faca1f980f00b161eadb089023gstein#include "apr_strings.h"
f4c310fd2555c6faca1f980f00b161eadb089023gstein#include "apr_buckets.h"
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein#include "apr_hash.h"
f4c310fd2555c6faca1f980f00b161eadb089023gstein#define APR_WANT_STRFUNC
1a9d922232824a7cc008d4f74e48bd82adf5bdedgstein#include "apr_want.h"
f5ec9b038bb9db933072ba2c0a8e7bb2a3cedbdagstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein#include "httpd.h"
f4c310fd2555c6faca1f980f00b161eadb089023gstein#include "http_config.h"
f4c310fd2555c6faca1f980f00b161eadb089023gstein#include "http_request.h"
f4c310fd2555c6faca1f980f00b161eadb089023gstein#include "http_log.h"
f4c310fd2555c6faca1f980f00b161eadb089023gstein#include "util_filter.h"
f4c310fd2555c6faca1f980f00b161eadb089023gstein#include "http_protocol.h"
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein#include "mod_ssl.h" /* for the ssl_var_lookup optional function defn */
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein/* format_tag_hash is initialized during pre-config */
1ccd992d37d62c8cb2056126f2234f64ec189bfddougmstatic apr_hash_t *format_tag_hash;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
1ccd992d37d62c8cb2056126f2234f64ec189bfddougmtypedef enum {
f4c310fd2555c6faca1f980f00b161eadb089023gstein hdr_add = 'a', /* add header (could mean multiple hdrs) */
f4c310fd2555c6faca1f980f00b161eadb089023gstein hdr_set = 's', /* set (replace old value) */
f4c310fd2555c6faca1f980f00b161eadb089023gstein hdr_append = 'm', /* append (merge into any old value) */
f4c310fd2555c6faca1f980f00b161eadb089023gstein hdr_unset = 'u', /* unset header */
52c1d304b1bd8e05da40a7cded2ecb9f0ba614c5gstein hdr_echo = 'e' /* echo headers from request to response */
52c1d304b1bd8e05da40a7cded2ecb9f0ba614c5gstein} hdr_actions;
52c1d304b1bd8e05da40a7cded2ecb9f0ba614c5gstein
52c1d304b1bd8e05da40a7cded2ecb9f0ba614c5gsteintypedef enum {
52c1d304b1bd8e05da40a7cded2ecb9f0ba614c5gstein hdr_in = 0, /* RequestHeader */
f4c310fd2555c6faca1f980f00b161eadb089023gstein hdr_out = 1, /* Header */
f4c310fd2555c6faca1f980f00b161eadb089023gstein hdr_err = 2 /* ErrorHeader */
f4c310fd2555c6faca1f980f00b161eadb089023gstein} hdr_inout;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
707ecf9559338ec06b24334bc9abcca670325cc4gstein/*
f4c310fd2555c6faca1f980f00b161eadb089023gstein * There is an array of struct format_tag per Header/RequestHeader
707ecf9559338ec06b24334bc9abcca670325cc4gstein * config directive
707ecf9559338ec06b24334bc9abcca670325cc4gstein */
707ecf9559338ec06b24334bc9abcca670325cc4gsteintypedef struct {
707ecf9559338ec06b24334bc9abcca670325cc4gstein const char* (*func)(request_rec *r,char *arg);
52c1d304b1bd8e05da40a7cded2ecb9f0ba614c5gstein char *arg;
f4c310fd2555c6faca1f980f00b161eadb089023gstein} format_tag;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein/*
f4c310fd2555c6faca1f980f00b161eadb089023gstein * There is one "header_entry" per Header/RequestHeader config directive
707ecf9559338ec06b24334bc9abcca670325cc4gstein */
707ecf9559338ec06b24334bc9abcca670325cc4gsteintypedef struct {
707ecf9559338ec06b24334bc9abcca670325cc4gstein hdr_actions action;
707ecf9559338ec06b24334bc9abcca670325cc4gstein char *header;
707ecf9559338ec06b24334bc9abcca670325cc4gstein apr_array_header_t *ta; /* Array of format_tag structs */
707ecf9559338ec06b24334bc9abcca670325cc4gstein regex_t *regex;
707ecf9559338ec06b24334bc9abcca670325cc4gstein const char *condition_var;
707ecf9559338ec06b24334bc9abcca670325cc4gstein} header_entry;
707ecf9559338ec06b24334bc9abcca670325cc4gstein
707ecf9559338ec06b24334bc9abcca670325cc4gstein/* echo_do is used for Header echo to iterate through the request headers*/
707ecf9559338ec06b24334bc9abcca670325cc4gsteintypedef struct {
707ecf9559338ec06b24334bc9abcca670325cc4gstein request_rec *r;
707ecf9559338ec06b24334bc9abcca670325cc4gstein header_entry *hdr;
707ecf9559338ec06b24334bc9abcca670325cc4gstein} echo_do;
707ecf9559338ec06b24334bc9abcca670325cc4gstein
707ecf9559338ec06b24334bc9abcca670325cc4gstein/*
707ecf9559338ec06b24334bc9abcca670325cc4gstein * headers_conf is our per-module configuration. This is used as both
707ecf9559338ec06b24334bc9abcca670325cc4gstein * a per-dir and per-server config
707ecf9559338ec06b24334bc9abcca670325cc4gstein */
707ecf9559338ec06b24334bc9abcca670325cc4gsteintypedef struct {
707ecf9559338ec06b24334bc9abcca670325cc4gstein apr_array_header_t *fixup_in;
707ecf9559338ec06b24334bc9abcca670325cc4gstein apr_array_header_t *fixup_out;
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_array_header_t *fixup_err;
f4c310fd2555c6faca1f980f00b161eadb089023gstein} headers_conf;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gsteinmodule AP_MODULE_DECLARE_DATA headers_module;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein/* Pointer to ssl_var_lookup, if available. */
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic APR_OPTIONAL_FN_TYPE(ssl_var_lookup) *header_ssl_lookup = NULL;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein/*
f4c310fd2555c6faca1f980f00b161eadb089023gstein * Tag formatting functions
f4c310fd2555c6faca1f980f00b161eadb089023gstein */
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic const char *constant_item(request_rec *r, char *stuff)
f4c310fd2555c6faca1f980f00b161eadb089023gstein{
f4c310fd2555c6faca1f980f00b161eadb089023gstein return stuff;
f4c310fd2555c6faca1f980f00b161eadb089023gstein}
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic const char *header_request_duration(request_rec *r, char *a)
f4c310fd2555c6faca1f980f00b161eadb089023gstein{
f4c310fd2555c6faca1f980f00b161eadb089023gstein return apr_psprintf(r->pool, "D=%" APR_TIME_T_FMT,
f4c310fd2555c6faca1f980f00b161eadb089023gstein (apr_time_now() - r->request_time));
f4c310fd2555c6faca1f980f00b161eadb089023gstein}
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic const char *header_request_time(request_rec *r, char *a)
f4c310fd2555c6faca1f980f00b161eadb089023gstein{
f4c310fd2555c6faca1f980f00b161eadb089023gstein return apr_psprintf(r->pool, "t=%" APR_TIME_T_FMT, r->request_time);
f4c310fd2555c6faca1f980f00b161eadb089023gstein}
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein/* unwrap_header returns HDR with any newlines converted into
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein * whitespace if necessary. */
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic const char *unwrap_header(apr_pool_t *p, const char *hdr)
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein{
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (ap_strchr_c(hdr, APR_ASCII_LF) || ap_strchr_c(hdr, APR_ASCII_CR)) {
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein char *ptr;
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein hdr = ptr = apr_pstrdup(p, hdr);
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein do {
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein if (*ptr == APR_ASCII_LF || *ptr == APR_ASCII_CR)
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein *ptr = APR_ASCII_BLANK;
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein } while (*ptr++);
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein }
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein return hdr;
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein}
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gsteinstatic const char *header_request_env_var(request_rec *r, char *a)
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein{
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein const char *s = apr_table_get(r->subprocess_env,a);
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein if (s)
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein return unwrap_header(r->pool, s);
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein else
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein return "(null)";
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein}
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gsteinstatic const char *header_request_ssl_var(request_rec *r, char *name)
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein{
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (header_ssl_lookup) {
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein const char *val = header_ssl_lookup(r->pool, r->server,
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein r->connection, r, name);
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein if (val && val[0])
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein return unwrap_header(r->pool, val);
956f4b1551215610a57f3b52822dbac6f41a8aa9gstein else
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein return "(null)";
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein else {
f4c310fd2555c6faca1f980f00b161eadb089023gstein return "(null)";
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein}
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein/*
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein * Config routines
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein */
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gsteinstatic void *create_headers_config(apr_pool_t *p, server_rec *s)
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein{
f4c310fd2555c6faca1f980f00b161eadb089023gstein headers_conf *conf = apr_pcalloc(p, sizeof(*conf));
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein conf->fixup_in = apr_array_make(p, 2, sizeof(header_entry));
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm conf->fixup_out = apr_array_make(p, 2, sizeof(header_entry));
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm conf->fixup_err = apr_array_make(p, 2, sizeof(header_entry));
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein return conf;
f4c310fd2555c6faca1f980f00b161eadb089023gstein}
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f94aab38f6ee899f463f0118ea395291f7c5b4cegsteinstatic void *create_headers_dir_config(apr_pool_t *p, char *d)
f94aab38f6ee899f463f0118ea395291f7c5b4cegstein{
707ecf9559338ec06b24334bc9abcca670325cc4gstein return create_headers_config(p, NULL);
707ecf9559338ec06b24334bc9abcca670325cc4gstein}
707ecf9559338ec06b24334bc9abcca670325cc4gstein
707ecf9559338ec06b24334bc9abcca670325cc4gsteinstatic void *merge_headers_config(apr_pool_t *p, void *basev, void *overridesv)
f4c310fd2555c6faca1f980f00b161eadb089023gstein{
f4c310fd2555c6faca1f980f00b161eadb089023gstein headers_conf *newconf = apr_pcalloc(p, sizeof(*newconf));
f4c310fd2555c6faca1f980f00b161eadb089023gstein headers_conf *base = basev;
f4c310fd2555c6faca1f980f00b161eadb089023gstein headers_conf *overrides = overridesv;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm newconf->fixup_in = apr_array_append(p, base->fixup_in, overrides->fixup_in);
f4c310fd2555c6faca1f980f00b161eadb089023gstein newconf->fixup_out = apr_array_append(p, base->fixup_out, overrides->fixup_out);
f4c310fd2555c6faca1f980f00b161eadb089023gstein newconf->fixup_err = apr_array_append(p, base->fixup_err,
f4c310fd2555c6faca1f980f00b161eadb089023gstein overrides->fixup_err);
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein return newconf;
f4c310fd2555c6faca1f980f00b161eadb089023gstein}
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic char *parse_misc_string(apr_pool_t *p, format_tag *tag, const char **sa)
f4c310fd2555c6faca1f980f00b161eadb089023gstein{
f4c310fd2555c6faca1f980f00b161eadb089023gstein const char *s;
f4c310fd2555c6faca1f980f00b161eadb089023gstein char *d;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein tag->func = constant_item;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein s = *sa;
f4c310fd2555c6faca1f980f00b161eadb089023gstein while (*s && *s != '%') {
f4c310fd2555c6faca1f980f00b161eadb089023gstein s++;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein /*
f4c310fd2555c6faca1f980f00b161eadb089023gstein * This might allocate a few chars extra if there's a backslash
f4c310fd2555c6faca1f980f00b161eadb089023gstein * escape in the format string.
f4c310fd2555c6faca1f980f00b161eadb089023gstein */
f4c310fd2555c6faca1f980f00b161eadb089023gstein tag->arg = apr_palloc(p, s - *sa + 1);
49bf4df23d9e5281abcd83005550bda818b17b08wrowe
f4c310fd2555c6faca1f980f00b161eadb089023gstein d = tag->arg;
f4c310fd2555c6faca1f980f00b161eadb089023gstein s = *sa;
f4c310fd2555c6faca1f980f00b161eadb089023gstein while (*s && *s != '%') {
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (*s != '\\') {
f4c310fd2555c6faca1f980f00b161eadb089023gstein *d++ = *s++;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein else {
f4c310fd2555c6faca1f980f00b161eadb089023gstein s++;
f4c310fd2555c6faca1f980f00b161eadb089023gstein switch (*s) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein case '\\':
f4c310fd2555c6faca1f980f00b161eadb089023gstein *d++ = '\\';
f4c310fd2555c6faca1f980f00b161eadb089023gstein s++;
f4c310fd2555c6faca1f980f00b161eadb089023gstein break;
f4c310fd2555c6faca1f980f00b161eadb089023gstein case 'r':
f4c310fd2555c6faca1f980f00b161eadb089023gstein *d++ = '\r';
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm s++;
f4c310fd2555c6faca1f980f00b161eadb089023gstein break;
53dafcfda483886730db8e57bf6f94cff36f0047stoddard case 'n':
f71d4ec448449837beefe21cf7c9f8d9b6bd4654gstein *d++ = '\n';
f71d4ec448449837beefe21cf7c9f8d9b6bd4654gstein s++;
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm break;
f4c310fd2555c6faca1f980f00b161eadb089023gstein case 't':
f4c310fd2555c6faca1f980f00b161eadb089023gstein *d++ = '\t';
f4c310fd2555c6faca1f980f00b161eadb089023gstein s++;
f4c310fd2555c6faca1f980f00b161eadb089023gstein break;
f4c310fd2555c6faca1f980f00b161eadb089023gstein default:
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* copy verbatim */
f71d4ec448449837beefe21cf7c9f8d9b6bd4654gstein *d++ = '\\';
f71d4ec448449837beefe21cf7c9f8d9b6bd4654gstein /*
f4c310fd2555c6faca1f980f00b161eadb089023gstein * Allow the loop to deal with this *s in the normal
f4c310fd2555c6faca1f980f00b161eadb089023gstein * fashion so that it handles end of string etc.
f4c310fd2555c6faca1f980f00b161eadb089023gstein * properly.
f4c310fd2555c6faca1f980f00b161eadb089023gstein */
f4c310fd2555c6faca1f980f00b161eadb089023gstein break;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
10a4cdd68ef1ca0e54af296fe1d08ac00150c90bwrowe *d = '\0';
10a4cdd68ef1ca0e54af296fe1d08ac00150c90bwrowe
f71d4ec448449837beefe21cf7c9f8d9b6bd4654gstein *sa = s;
f71d4ec448449837beefe21cf7c9f8d9b6bd4654gstein return NULL;
f4c310fd2555c6faca1f980f00b161eadb089023gstein}
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic char *parse_format_tag(apr_pool_t *p, format_tag *tag, const char **sa)
f4c310fd2555c6faca1f980f00b161eadb089023gstein{
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm const char *s = *sa;
f4c310fd2555c6faca1f980f00b161eadb089023gstein const char * (*tag_handler)(request_rec *,char *);
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* Handle string literal/conditionals */
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (*s != '%') {
f4c310fd2555c6faca1f980f00b161eadb089023gstein return parse_misc_string(p, tag, sa);
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm }
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm s++; /* skip the % */
f4c310fd2555c6faca1f980f00b161eadb089023gstein tag->arg = '\0';
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* grab the argument if there is one */
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (*s == '{') {
f4c310fd2555c6faca1f980f00b161eadb089023gstein ++s;
f4c310fd2555c6faca1f980f00b161eadb089023gstein tag->arg = ap_getword(p,&s,'}');
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm
1f6e6566a4ce31a0b95d5400c36d0aaff7a6e94agstein tag_handler = (const char * (*)(request_rec *,char *))apr_hash_get(format_tag_hash, s++, 1);
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (!tag_handler) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein char dummy[2];
f4c310fd2555c6faca1f980f00b161eadb089023gstein dummy[0] = s[-1];
f4c310fd2555c6faca1f980f00b161eadb089023gstein dummy[1] = '\0';
f4c310fd2555c6faca1f980f00b161eadb089023gstein return apr_pstrcat(p, "Unrecognized Header or RequestHeader directive %",
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm dummy, NULL);
1f6e6566a4ce31a0b95d5400c36d0aaff7a6e94agstein }
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm tag->func = tag_handler;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein *sa = s;
f4c310fd2555c6faca1f980f00b161eadb089023gstein return NULL;
f4c310fd2555c6faca1f980f00b161eadb089023gstein}
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein/*
f4c310fd2555c6faca1f980f00b161eadb089023gstein * A format string consists of white space, text and optional format
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm * tags in any order. E.g.,
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm *
1f6e6566a4ce31a0b95d5400c36d0aaff7a6e94agstein * Header add MyHeader "Free form text %D %t more text"
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm *
1f6e6566a4ce31a0b95d5400c36d0aaff7a6e94agstein * Decompose the format string into its tags. Each tag (struct format_tag)
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm * contains a pointer to the function used to format the tag. Then save each
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm * tag in the tag array anchored in the header_entry.
1f6e6566a4ce31a0b95d5400c36d0aaff7a6e94agstein */
1ccd992d37d62c8cb2056126f2234f64ec189bfddougmstatic char *parse_format_string(apr_pool_t *p, header_entry *hdr, const char *s)
f4c310fd2555c6faca1f980f00b161eadb089023gstein{
f4c310fd2555c6faca1f980f00b161eadb089023gstein char *res;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* No string to parse with unset and copy commands */
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (hdr->action == hdr_unset ||
f4c310fd2555c6faca1f980f00b161eadb089023gstein hdr->action == hdr_echo) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein return NULL;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein hdr->ta = apr_array_make(p, 10, sizeof(format_tag));
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein while (*s) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein if ((res = parse_format_tag(p, (format_tag *) apr_array_push(hdr->ta), &s))) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein return res;
1f6e6566a4ce31a0b95d5400c36d0aaff7a6e94agstein }
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm }
f4c310fd2555c6faca1f980f00b161eadb089023gstein return NULL;
f4c310fd2555c6faca1f980f00b161eadb089023gstein}
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm/* handle RequestHeader and Header directive */
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic const char *header_inout_cmd(hdr_inout inout, cmd_parms *cmd,
cccd31fa4a72fe23cc3249c06db181b274a55a69gstein void *indirconf,
f4c310fd2555c6faca1f980f00b161eadb089023gstein const char *action, const char *inhdr,
f4c310fd2555c6faca1f980f00b161eadb089023gstein const char *value, const char* envclause)
f4c310fd2555c6faca1f980f00b161eadb089023gstein{
f4c310fd2555c6faca1f980f00b161eadb089023gstein headers_conf *dirconf = indirconf;
f4c310fd2555c6faca1f980f00b161eadb089023gstein const char *condition_var = NULL;
f4c310fd2555c6faca1f980f00b161eadb089023gstein char *colon;
f4c310fd2555c6faca1f980f00b161eadb089023gstein char *hdr = apr_pstrdup(cmd->pool, inhdr);
f4c310fd2555c6faca1f980f00b161eadb089023gstein header_entry *new;
f4c310fd2555c6faca1f980f00b161eadb089023gstein server_rec *s = cmd->server;
f4c310fd2555c6faca1f980f00b161eadb089023gstein headers_conf *serverconf = ap_get_module_config(s->module_config,
f4c310fd2555c6faca1f980f00b161eadb089023gstein &headers_module);
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_array_header_t *fixup = dirconf->fixup_out;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein switch (inout) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein case hdr_in:
f4c310fd2555c6faca1f980f00b161eadb089023gstein fixup = (cmd->path != NULL)
f4c310fd2555c6faca1f980f00b161eadb089023gstein ? dirconf->fixup_in
f4c310fd2555c6faca1f980f00b161eadb089023gstein : serverconf->fixup_in;
f4c310fd2555c6faca1f980f00b161eadb089023gstein break;
1f6e6566a4ce31a0b95d5400c36d0aaff7a6e94agstein case hdr_out:
1f6e6566a4ce31a0b95d5400c36d0aaff7a6e94agstein fixup = (cmd->path != NULL)
1f6e6566a4ce31a0b95d5400c36d0aaff7a6e94agstein ? dirconf->fixup_out
f4c310fd2555c6faca1f980f00b161eadb089023gstein : serverconf->fixup_out;
f4c310fd2555c6faca1f980f00b161eadb089023gstein break;
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm case hdr_err:
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm fixup = (cmd->path != NULL)
f4c310fd2555c6faca1f980f00b161eadb089023gstein ? dirconf->fixup_err
f4c310fd2555c6faca1f980f00b161eadb089023gstein : serverconf->fixup_err;
f4c310fd2555c6faca1f980f00b161eadb089023gstein break;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein new = (header_entry *) apr_array_push(fixup);
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (!strcasecmp(action, "set"))
f4c310fd2555c6faca1f980f00b161eadb089023gstein new->action = hdr_set;
f4c310fd2555c6faca1f980f00b161eadb089023gstein else if (!strcasecmp(action, "add"))
f4c310fd2555c6faca1f980f00b161eadb089023gstein new->action = hdr_add;
f4c310fd2555c6faca1f980f00b161eadb089023gstein else if (!strcasecmp(action, "append"))
f4c310fd2555c6faca1f980f00b161eadb089023gstein new->action = hdr_append;
f4c310fd2555c6faca1f980f00b161eadb089023gstein else if (!strcasecmp(action, "unset"))
f4c310fd2555c6faca1f980f00b161eadb089023gstein new->action = hdr_unset;
f4c310fd2555c6faca1f980f00b161eadb089023gstein else if (!strcasecmp(action, "echo"))
f4c310fd2555c6faca1f980f00b161eadb089023gstein new->action = hdr_echo;
f4c310fd2555c6faca1f980f00b161eadb089023gstein else
f4c310fd2555c6faca1f980f00b161eadb089023gstein return "first argument must be add, set, append, unset or echo.";
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (new->action == hdr_unset) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (value)
f4c310fd2555c6faca1f980f00b161eadb089023gstein return "header unset takes two arguments";
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein else if (new->action == hdr_echo) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein regex_t *regex;
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (value)
f4c310fd2555c6faca1f980f00b161eadb089023gstein return "Header echo takes two arguments";
f4c310fd2555c6faca1f980f00b161eadb089023gstein else if (inout != hdr_out)
f4c310fd2555c6faca1f980f00b161eadb089023gstein return "Header echo only valid on Header directive";
f4c310fd2555c6faca1f980f00b161eadb089023gstein else {
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm regex = ap_pregcomp(cmd->pool, hdr, REG_EXTENDED | REG_NOSUB);
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (regex == NULL) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein return "Header echo regex could not be compiled";
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm new->regex = regex;
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm }
4c449c30215bd5e8bad122a4118f5a7b0e995472wrowe else if (!value)
f4c310fd2555c6faca1f980f00b161eadb089023gstein return "header requires three arguments";
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* Handle the envclause on Header */
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (envclause != NULL) {
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm if (strncasecmp(envclause, "env=", 4) != 0) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein return "error: envclause should be in the form env=envar";
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm if ((envclause[4] == '\0')
f4c310fd2555c6faca1f980f00b161eadb089023gstein || ((envclause[4] == '!') && (envclause[5] == '\0'))) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein return "error: missing environment variable name. "
f4c310fd2555c6faca1f980f00b161eadb089023gstein "envclause should be in the form env=envar ";
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm condition_var = apr_pstrdup(cmd->pool, &envclause[4]);
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein if ((colon = strchr(hdr, ':')))
f4c310fd2555c6faca1f980f00b161eadb089023gstein *colon = '\0';
4c449c30215bd5e8bad122a4118f5a7b0e995472wrowe
4c449c30215bd5e8bad122a4118f5a7b0e995472wrowe new->header = hdr;
33397e35239f202a595837571561468f02b2e806gstein new->condition_var = condition_var;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein return parse_format_string(cmd->pool, new, value);
f4c310fd2555c6faca1f980f00b161eadb089023gstein}
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein/* Handle all (xxx)Header directives */
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic const char *header_cmd(cmd_parms *cmd, void *indirconf,
f4c310fd2555c6faca1f980f00b161eadb089023gstein const char *args)
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm{
f4c310fd2555c6faca1f980f00b161eadb089023gstein const char *s;
f4c310fd2555c6faca1f980f00b161eadb089023gstein const char *action;
f4c310fd2555c6faca1f980f00b161eadb089023gstein const char *hdr;
f4c310fd2555c6faca1f980f00b161eadb089023gstein const char *val;
f4c310fd2555c6faca1f980f00b161eadb089023gstein const char *envclause;
f4c310fd2555c6faca1f980f00b161eadb089023gstein hdr_inout outbl;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f5ec9b038bb9db933072ba2c0a8e7bb2a3cedbdagstein s = apr_pstrdup(cmd->pool, args);
f4c310fd2555c6faca1f980f00b161eadb089023gstein action = ap_getword_conf(cmd->pool, &s);
f4c310fd2555c6faca1f980f00b161eadb089023gstein hdr = ap_getword_conf(cmd->pool, &s);
f4c310fd2555c6faca1f980f00b161eadb089023gstein val = *s ? ap_getword_conf(cmd->pool, &s) : NULL;
f4c310fd2555c6faca1f980f00b161eadb089023gstein envclause = *s ? ap_getword_conf(cmd->pool, &s) : NULL;
f4c310fd2555c6faca1f980f00b161eadb089023gstein outbl = (hdr_inout)cmd->info;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein return header_inout_cmd(outbl, cmd, indirconf, action, hdr, val, envclause);
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm}
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein/*
5646ba89a25a695006edae46de226fb57a2e6270gstein * Process the tags in the format string. Tags may be format specifiers
f4c310fd2555c6faca1f980f00b161eadb089023gstein * (%D, %t, etc.), whitespace or text strings. For each tag, run the handler
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm * (formatter) specific to the tag. Handlers return text strings.
f4c310fd2555c6faca1f980f00b161eadb089023gstein * Concatenate the return from each handler into one string that is
f4c310fd2555c6faca1f980f00b161eadb089023gstein * returned from this call.
f4c310fd2555c6faca1f980f00b161eadb089023gstein */
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic char* process_tags(header_entry *hdr, request_rec *r)
f4c310fd2555c6faca1f980f00b161eadb089023gstein{
f5ec9b038bb9db933072ba2c0a8e7bb2a3cedbdagstein int i;
f5ec9b038bb9db933072ba2c0a8e7bb2a3cedbdagstein const char *s;
f4c310fd2555c6faca1f980f00b161eadb089023gstein char *str = NULL;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein format_tag *tag = (format_tag*) hdr->ta->elts;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein for (i = 0; i < hdr->ta->nelts; i++) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein s = tag[i].func(r, tag[i].arg);
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (str == NULL)
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm str = apr_pstrdup(r->pool, s);
f4c310fd2555c6faca1f980f00b161eadb089023gstein else
f4c310fd2555c6faca1f980f00b161eadb089023gstein str = apr_pstrcat(r->pool, str, s, NULL);
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein return str;
f4c310fd2555c6faca1f980f00b161eadb089023gstein}
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic int echo_header(echo_do *v, const char *key, const char *val)
f4c310fd2555c6faca1f980f00b161eadb089023gstein{
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* If the input header (key) matches the regex, echo it intact to
f4c310fd2555c6faca1f980f00b161eadb089023gstein * r->headers_out.
f4c310fd2555c6faca1f980f00b161eadb089023gstein */
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (!ap_regexec(v->hdr->regex, key, 0, NULL, 0)) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_table_add(v->r->headers_out, key, val);
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein return 1;
f4c310fd2555c6faca1f980f00b161eadb089023gstein}
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic void do_headers_fixup(request_rec *r, hdr_inout inout,
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_array_header_t *fixup)
f4c310fd2555c6faca1f980f00b161eadb089023gstein{
f4c310fd2555c6faca1f980f00b161eadb089023gstein int i;
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_table_t *headers = r->headers_out;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein switch (inout) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein case hdr_in:
f4c310fd2555c6faca1f980f00b161eadb089023gstein headers = r->headers_in;
f4c310fd2555c6faca1f980f00b161eadb089023gstein break;
f4c310fd2555c6faca1f980f00b161eadb089023gstein case hdr_out:
f4c310fd2555c6faca1f980f00b161eadb089023gstein headers = r->headers_out;
f4c310fd2555c6faca1f980f00b161eadb089023gstein break;
f4c310fd2555c6faca1f980f00b161eadb089023gstein case hdr_err:
f4c310fd2555c6faca1f980f00b161eadb089023gstein headers = r->err_headers_out;
f4c310fd2555c6faca1f980f00b161eadb089023gstein break;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein for (i = 0; i < fixup->nelts; ++i) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein header_entry *hdr = &((header_entry *) (fixup->elts))[i];
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* Have any conditional envar-controlled Header processing to do? */
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (hdr->condition_var) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein const char *envar = hdr->condition_var;
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (*envar != '!') {
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (apr_table_get(r->subprocess_env, envar) == NULL)
f4c310fd2555c6faca1f980f00b161eadb089023gstein continue;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein else {
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (apr_table_get(r->subprocess_env, &envar[1]) != NULL)
f4c310fd2555c6faca1f980f00b161eadb089023gstein continue;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein switch (hdr->action) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein case hdr_add:
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_table_addn(headers, hdr->header, process_tags(hdr, r));
f4c310fd2555c6faca1f980f00b161eadb089023gstein break;
f4c310fd2555c6faca1f980f00b161eadb089023gstein case hdr_append:
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm apr_table_mergen(headers, hdr->header, process_tags(hdr, r));
f4c310fd2555c6faca1f980f00b161eadb089023gstein break;
f4c310fd2555c6faca1f980f00b161eadb089023gstein case hdr_set:
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_table_setn(headers, hdr->header, process_tags(hdr, r));
f4c310fd2555c6faca1f980f00b161eadb089023gstein break;
f4c310fd2555c6faca1f980f00b161eadb089023gstein case hdr_unset:
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_table_unset(headers, hdr->header);
f4c310fd2555c6faca1f980f00b161eadb089023gstein break;
f4c310fd2555c6faca1f980f00b161eadb089023gstein case hdr_echo:
f4c310fd2555c6faca1f980f00b161eadb089023gstein {
f4c310fd2555c6faca1f980f00b161eadb089023gstein echo_do v;
f4c310fd2555c6faca1f980f00b161eadb089023gstein v.r = r;
f4c310fd2555c6faca1f980f00b161eadb089023gstein v.hdr = hdr;
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm apr_table_do((int (*) (void *, const char *, const char *))
f4c310fd2555c6faca1f980f00b161eadb089023gstein echo_header, (void *) &v, r->headers_in, NULL);
f4c310fd2555c6faca1f980f00b161eadb089023gstein break;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein}
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic void ap_headers_insert_output_filter(request_rec *r)
f4c310fd2555c6faca1f980f00b161eadb089023gstein{
f4c310fd2555c6faca1f980f00b161eadb089023gstein headers_conf *serverconf = ap_get_module_config(r->server->module_config,
f4c310fd2555c6faca1f980f00b161eadb089023gstein &headers_module);
f4c310fd2555c6faca1f980f00b161eadb089023gstein headers_conf *dirconf = ap_get_module_config(r->per_dir_config,
f4c310fd2555c6faca1f980f00b161eadb089023gstein &headers_module);
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (serverconf->fixup_out->nelts || dirconf->fixup_out->nelts
f4c310fd2555c6faca1f980f00b161eadb089023gstein || serverconf->fixup_err->nelts || dirconf->fixup_err->nelts) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_add_output_filter("FIXUP_HEADERS_OUT", NULL, r, r->connection);
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein}
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein/*
f4c310fd2555c6faca1f980f00b161eadb089023gstein * Make sure our error-path filter is in place.
f4c310fd2555c6faca1f980f00b161eadb089023gstein */
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic void ap_headers_insert_error_filter(request_rec *r)
f4c310fd2555c6faca1f980f00b161eadb089023gstein{
f4c310fd2555c6faca1f980f00b161eadb089023gstein headers_conf *serverconf = ap_get_module_config(r->server->module_config,
f4c310fd2555c6faca1f980f00b161eadb089023gstein &headers_module);
f4c310fd2555c6faca1f980f00b161eadb089023gstein headers_conf *dirconf = ap_get_module_config(r->per_dir_config,
f4c310fd2555c6faca1f980f00b161eadb089023gstein &headers_module);
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (serverconf->fixup_err->nelts || dirconf->fixup_err->nelts) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_add_output_filter("FIXUP_HEADERS_ERR", NULL, r, r->connection);
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein}
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic apr_status_t ap_headers_output_filter(ap_filter_t *f,
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_bucket_brigade *in)
f4c310fd2555c6faca1f980f00b161eadb089023gstein{
f4c310fd2555c6faca1f980f00b161eadb089023gstein headers_conf *serverconf = ap_get_module_config(f->r->server->module_config,
33397e35239f202a595837571561468f02b2e806gstein &headers_module);
33397e35239f202a595837571561468f02b2e806gstein headers_conf *dirconf = ap_get_module_config(f->r->per_dir_config,
f4c310fd2555c6faca1f980f00b161eadb089023gstein &headers_module);
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, f->r->server,
f4c310fd2555c6faca1f980f00b161eadb089023gstein "headers: ap_headers_output_filter()");
f4c310fd2555c6faca1f980f00b161eadb089023gstein
49bf4df23d9e5281abcd83005550bda818b17b08wrowe /* do the fixup */
f4c310fd2555c6faca1f980f00b161eadb089023gstein do_headers_fixup(f->r, hdr_err, serverconf->fixup_err);
f4c310fd2555c6faca1f980f00b161eadb089023gstein do_headers_fixup(f->r, hdr_out, serverconf->fixup_out);
f4c310fd2555c6faca1f980f00b161eadb089023gstein do_headers_fixup(f->r, hdr_err, dirconf->fixup_err);
f4c310fd2555c6faca1f980f00b161eadb089023gstein do_headers_fixup(f->r, hdr_out, dirconf->fixup_out);
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* remove ourselves from the filter chain */
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_remove_output_filter(f);
ba2ad3b1bb4a729278ad8e8846d34ddd27b6551cgstein
ba2ad3b1bb4a729278ad8e8846d34ddd27b6551cgstein /* send the data up the stack */
ba2ad3b1bb4a729278ad8e8846d34ddd27b6551cgstein return ap_pass_brigade(f->next,in);
f4c310fd2555c6faca1f980f00b161eadb089023gstein}
f5ec9b038bb9db933072ba2c0a8e7bb2a3cedbdagstein
f5ec9b038bb9db933072ba2c0a8e7bb2a3cedbdagstein/*
f4c310fd2555c6faca1f980f00b161eadb089023gstein * Make sure we propagate any ErrorHeader settings on the error
f4c310fd2555c6faca1f980f00b161eadb089023gstein * path through http_protocol.c.
f4c310fd2555c6faca1f980f00b161eadb089023gstein */
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic apr_status_t ap_headers_error_filter(ap_filter_t *f,
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_bucket_brigade *in)
f4c310fd2555c6faca1f980f00b161eadb089023gstein{
f4c310fd2555c6faca1f980f00b161eadb089023gstein headers_conf *serverconf;
f4c310fd2555c6faca1f980f00b161eadb089023gstein headers_conf *dirconf;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein serverconf = ap_get_module_config(f->r->server->module_config,
f4c310fd2555c6faca1f980f00b161eadb089023gstein &headers_module);
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm dirconf = ap_get_module_config(f->r->per_dir_config,
f4c310fd2555c6faca1f980f00b161eadb089023gstein &headers_module);
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, f->r->server,
f4c310fd2555c6faca1f980f00b161eadb089023gstein "headers: ap_headers_error_filter()");
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein /*
f4c310fd2555c6faca1f980f00b161eadb089023gstein * Add any header fields defined by ErrorHeader to r->err_headers_out.
f4c310fd2555c6faca1f980f00b161eadb089023gstein * Server-wide first, then per-directory to allow overriding.
f4c310fd2555c6faca1f980f00b161eadb089023gstein */
f4c310fd2555c6faca1f980f00b161eadb089023gstein do_headers_fixup(f->r, hdr_err, serverconf->fixup_err);
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm do_headers_fixup(f->r, hdr_err, dirconf->fixup_err);
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein /*
f4c310fd2555c6faca1f980f00b161eadb089023gstein * We've done our bit; remove ourself from the filter chain so there's
ba2ad3b1bb4a729278ad8e8846d34ddd27b6551cgstein * no possibility we'll be called again.
f4c310fd2555c6faca1f980f00b161eadb089023gstein */
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_remove_output_filter(f);
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein /*
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm * Pass the buck. (euro?)
f4c310fd2555c6faca1f980f00b161eadb089023gstein */
f4c310fd2555c6faca1f980f00b161eadb089023gstein return ap_pass_brigade(f->next, in);
f4c310fd2555c6faca1f980f00b161eadb089023gstein}
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic apr_status_t ap_headers_fixup(request_rec *r)
f4c310fd2555c6faca1f980f00b161eadb089023gstein{
f4c310fd2555c6faca1f980f00b161eadb089023gstein headers_conf *serverconf = ap_get_module_config(r->server->module_config,
f5ec9b038bb9db933072ba2c0a8e7bb2a3cedbdagstein &headers_module);
f4c310fd2555c6faca1f980f00b161eadb089023gstein headers_conf *dirconf = ap_get_module_config(r->per_dir_config,
f5ec9b038bb9db933072ba2c0a8e7bb2a3cedbdagstein &headers_module);
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* do the fixup */
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (serverconf->fixup_in->nelts || dirconf->fixup_in->nelts) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein do_headers_fixup(r, hdr_in, serverconf->fixup_in);
f4c310fd2555c6faca1f980f00b161eadb089023gstein do_headers_fixup(r, hdr_in, dirconf->fixup_in);
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein return DECLINED;
f4c310fd2555c6faca1f980f00b161eadb089023gstein}
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic const command_rec headers_cmds[] =
f4c310fd2555c6faca1f980f00b161eadb089023gstein{
f4c310fd2555c6faca1f980f00b161eadb089023gstein AP_INIT_RAW_ARGS("Header", header_cmd, (void *)hdr_out, OR_FILEINFO,
f4c310fd2555c6faca1f980f00b161eadb089023gstein "an action, header and value followed by optional env "
f4c310fd2555c6faca1f980f00b161eadb089023gstein "clause"),
f4c310fd2555c6faca1f980f00b161eadb089023gstein AP_INIT_RAW_ARGS("RequestHeader", header_cmd, (void *)hdr_in, OR_FILEINFO,
f4c310fd2555c6faca1f980f00b161eadb089023gstein "an action, header and value followed by optional env "
f4c310fd2555c6faca1f980f00b161eadb089023gstein "clause"),
f4c310fd2555c6faca1f980f00b161eadb089023gstein AP_INIT_RAW_ARGS("ErrorHeader", header_cmd, (void *)hdr_err, OR_FILEINFO,
f4c310fd2555c6faca1f980f00b161eadb089023gstein "an action, header and value followed by optional env "
f4c310fd2555c6faca1f980f00b161eadb089023gstein "clause"),
f4c310fd2555c6faca1f980f00b161eadb089023gstein {NULL}
f4c310fd2555c6faca1f980f00b161eadb089023gstein};
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic void register_format_tag_handler(apr_pool_t *p, char *tag, void *tag_handler, int def)
f4c310fd2555c6faca1f980f00b161eadb089023gstein{
f4c310fd2555c6faca1f980f00b161eadb089023gstein const void *h = apr_palloc(p, sizeof(h));
f4c310fd2555c6faca1f980f00b161eadb089023gstein h = tag_handler;
f5ec9b038bb9db933072ba2c0a8e7bb2a3cedbdagstein apr_hash_set(format_tag_hash, tag, 1, h);
f4c310fd2555c6faca1f980f00b161eadb089023gstein}
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic int header_pre_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp)
f4c310fd2555c6faca1f980f00b161eadb089023gstein{
f4c310fd2555c6faca1f980f00b161eadb089023gstein format_tag_hash = apr_hash_make(p);
f4c310fd2555c6faca1f980f00b161eadb089023gstein register_format_tag_handler(p, "D", (void*) header_request_duration, 0);
f4c310fd2555c6faca1f980f00b161eadb089023gstein register_format_tag_handler(p, "t", (void*) header_request_time, 0);
f4c310fd2555c6faca1f980f00b161eadb089023gstein register_format_tag_handler(p, "e", (void*) header_request_env_var, 0);
f4c310fd2555c6faca1f980f00b161eadb089023gstein register_format_tag_handler(p, "s", (void*) header_request_ssl_var, 0);
f4c310fd2555c6faca1f980f00b161eadb089023gstein return OK;
f4c310fd2555c6faca1f980f00b161eadb089023gstein}
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic int header_post_config(apr_pool_t *pconf, apr_pool_t *plog,
f4c310fd2555c6faca1f980f00b161eadb089023gstein apr_pool_t *ptemp, server_rec *s)
f4c310fd2555c6faca1f980f00b161eadb089023gstein{
f4c310fd2555c6faca1f980f00b161eadb089023gstein header_ssl_lookup = APR_RETRIEVE_OPTIONAL_FN(ssl_var_lookup);
f4c310fd2555c6faca1f980f00b161eadb089023gstein return OK;
f4c310fd2555c6faca1f980f00b161eadb089023gstein}
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic void register_hooks(apr_pool_t *p)
f4c310fd2555c6faca1f980f00b161eadb089023gstein{
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_register_output_filter("FIXUP_HEADERS_OUT", ap_headers_output_filter,
f4c310fd2555c6faca1f980f00b161eadb089023gstein NULL, AP_FTYPE_CONTENT_SET);
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_register_output_filter("FIXUP_HEADERS_ERR", ap_headers_error_filter,
f4c310fd2555c6faca1f980f00b161eadb089023gstein NULL, AP_FTYPE_CONTENT_SET);
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_hook_pre_config(header_pre_config,NULL,NULL,APR_HOOK_MIDDLE);
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_hook_post_config(header_post_config,NULL,NULL,APR_HOOK_MIDDLE);
f4c310fd2555c6faca1f980f00b161eadb089023gstein ap_hook_insert_filter(ap_headers_insert_output_filter, NULL, NULL, APR_HOOK_LAST);
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm ap_hook_insert_error_filter(ap_headers_insert_error_filter,
ba2ad3b1bb4a729278ad8e8846d34ddd27b6551cgstein NULL, NULL, APR_HOOK_LAST);
ba2ad3b1bb4a729278ad8e8846d34ddd27b6551cgstein ap_hook_fixups(ap_headers_fixup, NULL, NULL, APR_HOOK_LAST);
f4c310fd2555c6faca1f980f00b161eadb089023gstein}
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gsteinmodule AP_MODULE_DECLARE_DATA headers_module =
f4c310fd2555c6faca1f980f00b161eadb089023gstein{
f4c310fd2555c6faca1f980f00b161eadb089023gstein STANDARD20_MODULE_STUFF,
f4c310fd2555c6faca1f980f00b161eadb089023gstein create_headers_dir_config, /* dir config creater */
f4c310fd2555c6faca1f980f00b161eadb089023gstein merge_headers_config, /* dir merger --- default is to override */
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm create_headers_config, /* server config */
f4c310fd2555c6faca1f980f00b161eadb089023gstein merge_headers_config, /* merge server configs */
f4c310fd2555c6faca1f980f00b161eadb089023gstein headers_cmds, /* command apr_table_t */
f4c310fd2555c6faca1f980f00b161eadb089023gstein register_hooks /* register hooks */
ba2ad3b1bb4a729278ad8e8846d34ddd27b6551cgstein};
f4c310fd2555c6faca1f980f00b161eadb089023gstein