842ae4bd224140319ae7feec1872b93dfd491143fielding/* Licensed to the Apache Software Foundation (ASF) under one or more
842ae4bd224140319ae7feec1872b93dfd491143fielding * contributor license agreements. See the NOTICE file distributed with
842ae4bd224140319ae7feec1872b93dfd491143fielding * this work for additional information regarding copyright ownership.
842ae4bd224140319ae7feec1872b93dfd491143fielding * The ASF licenses this file to You under the Apache License, Version 2.0
842ae4bd224140319ae7feec1872b93dfd491143fielding * (the "License"); you may not use this file except in compliance with
842ae4bd224140319ae7feec1872b93dfd491143fielding * the License. You may obtain a copy of the License at
ce9621257ef9e54c1bbe5ad8a5f445a1f211c2dcnd * Unless required by applicable law or agreed to in writing, software
ce9621257ef9e54c1bbe5ad8a5f445a1f211c2dcnd * distributed under the License is distributed on an "AS IS" BASIS,
ce9621257ef9e54c1bbe5ad8a5f445a1f211c2dcnd * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
ce9621257ef9e54c1bbe5ad8a5f445a1f211c2dcnd * See the License for the specific language governing permissions and
ce9621257ef9e54c1bbe5ad8a5f445a1f211c2dcnd * limitations under the License.
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * mod_headers.c: Add/append/remove HTTP response headers
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * Written by Paul Sutton, paul@ukweb.com, 1 Oct 1996
ba4c566c200c2436dae841b7c811807c80cd712afielding * The Header directive can be used to add/replace/remove HTTP headers
ba4c566c200c2436dae841b7c811807c80cd712afielding * within the response message. The RequestHeader directive can be used
ba4c566c200c2436dae841b7c811807c80cd712afielding * to add/replace/remove HTTP headers before a request message is processed.
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * Valid in both per-server and per-dir configurations.
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * Syntax is:
ba4c566c200c2436dae841b7c811807c80cd712afielding * Header action header value
ba4c566c200c2436dae841b7c811807c80cd712afielding * RequestHeader action header value
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * Where action is one of:
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * set - set this header, replacing any old value
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * add - add this header, possible resulting in two or more
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * headers with the same name
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * append - append this text onto any existing header of this same
22a7cd38c192adb811c7ab9bcba7b9261bf1c9edchrisd * merge - merge this text onto any existing header of this same,
22a7cd38c192adb811c7ab9bcba7b9261bf1c9edchrisd * avoiding duplicate values
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * unset - remove this header
22a7cd38c192adb811c7ab9bcba7b9261bf1c9edchrisd * edit - transform the header value according to a regexp
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * Where action is unset, the third argument (value) should not be given.
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * The header name can include the colon, or not.
ba4c566c200c2436dae841b7c811807c80cd712afielding * The Header and RequestHeader directives can only be used where allowed
ba4c566c200c2436dae841b7c811807c80cd712afielding * by the FileInfo override.
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * When the request is processed, the header directives are processed in
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * this order: firstly, the main server, then the virtual server handling
e8f95a682820a599fe41b22977010636be5c2717jim * this request (if any), then any <Directory> sections (working downwards
e8f95a682820a599fe41b22977010636be5c2717jim * from the root dir), then an <Location> sections (working down from
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * shortest URL component), the any <File> sections. This order is
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * important if any 'set' or 'unset' actions are used. For example,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * the following two directives have different effect if applied in
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * the reverse order:
ba4c566c200c2436dae841b7c811807c80cd712afielding * Header append Author "John P. Doe"
ba4c566c200c2436dae841b7c811807c80cd712afielding * Header unset Author
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * Examples:
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * To set the "Author" header, use
ba4c566c200c2436dae841b7c811807c80cd712afielding * Header add Author "John P. Doe"
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * To remove a header:
ba4c566c200c2436dae841b7c811807c80cd712afielding * Header unset Author
77f0db50b7e6636f6422de76ffb2a0af7acaed6djorton#include "mod_ssl.h" /* for the ssl_var_lookup optional function defn */
fd0075570654d8f3473f12c47f507c8b3c59a8e4stoddard/* format_tag_hash is initialized during pre-config */
0f081398cf0eef8cc7c66a535d450110a92dc8aefieldingtypedef enum {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding hdr_add = 'a', /* add header (could mean multiple hdrs) */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding hdr_append = 'm', /* append (merge into any old value) */
22a7cd38c192adb811c7ab9bcba7b9261bf1c9edchrisd hdr_merge = 'g', /* merge (merge, but avoid duplicates) */
13c7ff50f27aefa2594d33089fcff6ceb9796fe7niq hdr_echo = 'e', /* echo headers from request to response */
64dbb5532fba398c5e81efeb21c7fd50c05819d7niq hdr_edit = 'r', /* change value by regexp, match once */
4b3f656d2ad030be85d219e02fdc11546ddecb5ccovener hdr_edit_r = 'R', /* change value by regexp, everymatch */
4b3f656d2ad030be85d219e02fdc11546ddecb5ccovener hdr_setifempty = 'i', /* set value if header not already present*/
08eb8303a91265264085e646f5937c76ae1e0c5bnd * magic cmd->info values
d24345ec3173e01df72469ded862084c98ae4d61covenerstatic char hdr_out_onsuccess = '1'; /* Header onsuccess */
26f56d4a3c12077d605362e97490e34522fa4814covenerstatic char hdr_out_always = '2'; /* Header always */
3b60bc6cafbb662cb3edc70c1df81c8deb31175ajorton/* Callback function type. */
3b60bc6cafbb662cb3edc70c1df81c8deb31175ajortontypedef const char *format_tag_fn(request_rec *r, char *a);
e8f95a682820a599fe41b22977010636be5c2717jim * There is an array of struct format_tag per Header/RequestHeader
fd0075570654d8f3473f12c47f507c8b3c59a8e4stoddard * config directive
fd0075570654d8f3473f12c47f507c8b3c59a8e4stoddardtypedef struct {
cf82d17373559b6163dbd6c844c1af82cab56883niq/* 'Magic' condition_var value to run action in post_read_request */
fd0075570654d8f3473f12c47f507c8b3c59a8e4stoddard * There is one "header_entry" per Header/RequestHeader config directive
0f081398cf0eef8cc7c66a535d450110a92dc8aefieldingtypedef struct {
fd0075570654d8f3473f12c47f507c8b3c59a8e4stoddard apr_array_header_t *ta; /* Array of format_tag structs */
fd0075570654d8f3473f12c47f507c8b3c59a8e4stoddard/* echo_do is used for Header echo to iterate through the request headers*/
3bc407b46a67691f3e5fd4f5f5ead4e1eff09998stoddardtypedef struct {
6951fc02abfd7642e45333902c14855836717fadrpluem/* edit_do is used for Header edit to iterate through the request headers */
6951fc02abfd7642e45333902c14855836717fadrpluemtypedef struct {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * headers_conf is our per-module configuration. This is used as both
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * a per-dir and per-server config
0f081398cf0eef8cc7c66a535d450110a92dc8aefieldingtypedef struct {
77f0db50b7e6636f6422de76ffb2a0af7acaed6djorton/* Pointer to ssl_var_lookup, if available. */
77f0db50b7e6636f6422de76ffb2a0af7acaed6djortonstatic APR_OPTIONAL_FN_TYPE(ssl_var_lookup) *header_ssl_lookup = NULL;
fd0075570654d8f3473f12c47f507c8b3c59a8e4stoddard * Tag formatting functions
fd0075570654d8f3473f12c47f507c8b3c59a8e4stoddardstatic const char *constant_item(request_rec *r, char *stuff)
fd0075570654d8f3473f12c47f507c8b3c59a8e4stoddardstatic const char *header_request_duration(request_rec *r, char *a)
fd0075570654d8f3473f12c47f507c8b3c59a8e4stoddardstatic const char *header_request_time(request_rec *r, char *a)
0329db7881b698897213e816552b0ab31f8d4d56trawick return apr_psprintf(r->pool, "t=%" APR_TIME_T_FMT, r->request_time);
77f0db50b7e6636f6422de76ffb2a0af7acaed6djorton/* unwrap_header returns HDR with any newlines converted into
77f0db50b7e6636f6422de76ffb2a0af7acaed6djorton * whitespace if necessary. */
77f0db50b7e6636f6422de76ffb2a0af7acaed6djortonstatic const char *unwrap_header(apr_pool_t *p, const char *hdr)
77f0db50b7e6636f6422de76ffb2a0af7acaed6djorton if (ap_strchr_c(hdr, APR_ASCII_LF) || ap_strchr_c(hdr, APR_ASCII_CR)) {
77f0db50b7e6636f6422de76ffb2a0af7acaed6djorton } while (*ptr++);
ed4b039edaff2a734bd8da9c33e43e2fb8dd0db9ianhstatic const char *header_request_env_var(request_rec *r, char *a)
54449e92dcdd62884ea83c3e0fb0ced57fb65801jwoolley const char *s = apr_table_get(r->subprocess_env,a);
ed4b039edaff2a734bd8da9c33e43e2fb8dd0db9ianh return "(null)";
77f0db50b7e6636f6422de76ffb2a0af7acaed6djortonstatic const char *header_request_ssl_var(request_rec *r, char *name)
77f0db50b7e6636f6422de76ffb2a0af7acaed6djorton return "(null)";
77f0db50b7e6636f6422de76ffb2a0af7acaed6djorton return "(null)";
0b1e2711d8332fb10ca0a889f17dba261758e893jimstatic const char *header_request_loadavg(request_rec *r, char *a)
414a70fb459ec63b1196d6467b4d8bc2a290883djim return apr_psprintf(r->pool, "l=%.2f/%.2f/%.2f", t.loadavg,
0b1e2711d8332fb10ca0a889f17dba261758e893jimstatic const char *header_request_idle(request_rec *r, char *a)
0b1e2711d8332fb10ca0a889f17dba261758e893jimstatic const char *header_request_busy(request_rec *r, char *a)
fd0075570654d8f3473f12c47f507c8b3c59a8e4stoddard * Config routines
08eb8303a91265264085e646f5937c76ae1e0c5bndstatic void *create_headers_dir_config(apr_pool_t *p, char *d)
ea92d0ffcb30b186010a2c8ca2c80d2ac09e34dastoddard conf->fixup_in = apr_array_make(p, 2, sizeof(header_entry));
ea92d0ffcb30b186010a2c8ca2c80d2ac09e34dastoddard conf->fixup_out = apr_array_make(p, 2, sizeof(header_entry));
71f3601de4983bc2a6aaffcf37dc1d35c8674a34coar conf->fixup_err = apr_array_make(p, 2, sizeof(header_entry));
1ccd992d37d62c8cb2056126f2234f64ec189bfddougmstatic void *merge_headers_config(apr_pool_t *p, void *basev, void *overridesv)
a6b9ed64fdf548c61de9714e2cfb999ec59d149cgstein headers_conf *newconf = apr_pcalloc(p, sizeof(*newconf));
08eb8303a91265264085e646f5937c76ae1e0c5bnd newconf->fixup_out = apr_array_append(p, base->fixup_out,
71f3601de4983bc2a6aaffcf37dc1d35c8674a34coar newconf->fixup_err = apr_array_append(p, base->fixup_err,
fd0075570654d8f3473f12c47f507c8b3c59a8e4stoddardstatic char *parse_misc_string(apr_pool_t *p, format_tag *tag, const char **sa)
fd0075570654d8f3473f12c47f507c8b3c59a8e4stoddard const char *s;
fd0075570654d8f3473f12c47f507c8b3c59a8e4stoddard while (*s && *s != '%') {
fd0075570654d8f3473f12c47f507c8b3c59a8e4stoddard * This might allocate a few chars extra if there's a backslash
fd0075570654d8f3473f12c47f507c8b3c59a8e4stoddard * escape in the format string.
fd0075570654d8f3473f12c47f507c8b3c59a8e4stoddard while (*s && *s != '%') {
a47a28784ca46876076471d2a0b45c11f800bffestoddard if (*s != '\\') {
a47a28784ca46876076471d2a0b45c11f800bffestoddard *d++ = *s++;
a47a28784ca46876076471d2a0b45c11f800bffestoddard switch (*s) {
a47a28784ca46876076471d2a0b45c11f800bffestoddard *d++ = '\\';
a47a28784ca46876076471d2a0b45c11f800bffestoddard *d++ = '\r';
a47a28784ca46876076471d2a0b45c11f800bffestoddard *d++ = '\n';
a47a28784ca46876076471d2a0b45c11f800bffestoddard *d++ = '\t';
a47a28784ca46876076471d2a0b45c11f800bffestoddard /* copy verbatim */
a47a28784ca46876076471d2a0b45c11f800bffestoddard *d++ = '\\';
a47a28784ca46876076471d2a0b45c11f800bffestoddard * Allow the loop to deal with this *s in the normal
a47a28784ca46876076471d2a0b45c11f800bffestoddard * fashion so that it handles end of string etc.
a47a28784ca46876076471d2a0b45c11f800bffestoddard * properly.
fd0075570654d8f3473f12c47f507c8b3c59a8e4stoddardstatic char *parse_format_tag(apr_pool_t *p, format_tag *tag, const char **sa)
fd0075570654d8f3473f12c47f507c8b3c59a8e4stoddard const char *s = *sa;
fd0075570654d8f3473f12c47f507c8b3c59a8e4stoddard /* Handle string literal/conditionals */
fd0075570654d8f3473f12c47f507c8b3c59a8e4stoddard if (*s != '%') {
fd0075570654d8f3473f12c47f507c8b3c59a8e4stoddard s++; /* skip the % */
07a4fd7c4750c999c907e624575045180c50c742niq /* Pass through %% or % at end of string as % */
ed4b039edaff2a734bd8da9c33e43e2fb8dd0db9ianh /* grab the argument if there is one */
ed4b039edaff2a734bd8da9c33e43e2fb8dd0db9ianh if (*s == '{') {
58ecd4abb0bc207016069618e7d2b9cb640046c4trawick tag_handler = (const char * (*)(request_rec *,char *))apr_hash_get(format_tag_hash, s++, 1);
56cefde0af6b8db6fda0f1d95d8cdca54f397cd0nd return apr_pstrcat(p, "Unrecognized header format %", dummy, NULL);
e8f95a682820a599fe41b22977010636be5c2717jim * A format string consists of white space, text and optional format
e8f95a682820a599fe41b22977010636be5c2717jim * tags in any order. E.g.,
fd0075570654d8f3473f12c47f507c8b3c59a8e4stoddard * Header add MyHeader "Free form text %D %t more text"
fd0075570654d8f3473f12c47f507c8b3c59a8e4stoddard * Decompose the format string into its tags. Each tag (struct format_tag)
e8f95a682820a599fe41b22977010636be5c2717jim * contains a pointer to the function used to format the tag. Then save each
fd0075570654d8f3473f12c47f507c8b3c59a8e4stoddard * tag in the tag array anchored in the header_entry.
81849cd8925f6ffaf57412aaaac8a6df0d33cbb6covenerstatic char *parse_format_string(cmd_parms *cmd, header_entry *hdr, const char *s)
08eb8303a91265264085e646f5937c76ae1e0c5bnd /* No string to parse with unset and echo commands */
88fa154e9a87c35cf4ee74d46f095f66fe897d0edruggeri if (hdr->action == hdr_unset || hdr->action == hdr_echo) {
88fa154e9a87c35cf4ee74d46f095f66fe897d0edruggeri /* Tags are in the replacement value for edit */
88fa154e9a87c35cf4ee74d46f095f66fe897d0edruggeri else if (hdr->action == hdr_edit || hdr->action == hdr_edit_r ) {
fd0075570654d8f3473f12c47f507c8b3c59a8e4stoddard hdr->ta = apr_array_make(p, 10, sizeof(format_tag));
fd0075570654d8f3473f12c47f507c8b3c59a8e4stoddard while (*s) {
fd0075570654d8f3473f12c47f507c8b3c59a8e4stoddard if ((res = parse_format_tag(p, (format_tag *) apr_array_push(hdr->ta), &s))) {
ba4c566c200c2436dae841b7c811807c80cd712afielding/* handle RequestHeader and Header directive */
08eb8303a91265264085e646f5937c76ae1e0c5bndstatic APR_INLINE const char *header_inout_cmd(cmd_parms *cmd,
08eb8303a91265264085e646f5937c76ae1e0c5bnd const char *action,
08eb8303a91265264085e646f5937c76ae1e0c5bnd const char *hdr,
08eb8303a91265264085e646f5937c76ae1e0c5bnd const char *value,
13c7ff50f27aefa2594d33089fcff6ceb9796fe7niq const char *subs,
13c7ff50f27aefa2594d33089fcff6ceb9796fe7niq const char *envclause)
d24345ec3173e01df72469ded862084c98ae4d61covener ? dirconf->fixup_in : (cmd->info == &hdr_out_always)
45dffe6c346dd73571ccaead10295fc7d53b59a6covener return "first argument must be 'add', 'set', 'setifempty', 'append', 'merge', "
4b3f656d2ad030be85d219e02fdc11546ddecb5ccovener "'unset', 'echo', 'note', 'edit', or 'edit*'.";
64dbb5532fba398c5e81efeb21c7fd50c05819d7niq if (new->action == hdr_edit || new->action == hdr_edit_r) {
13c7ff50f27aefa2594d33089fcff6ceb9796fe7niq return "Header edit requires a match and a substitution";
13c7ff50f27aefa2594d33089fcff6ceb9796fe7niq new->regex = ap_pregcomp(cmd->pool, value, AP_REG_EXTENDED);
13c7ff50f27aefa2594d33089fcff6ceb9796fe7niq return "Header edit regex could not be compiled";
13c7ff50f27aefa2594d33089fcff6ceb9796fe7niq /* there's no subs, so envclause is really that argument */
13c7ff50f27aefa2594d33089fcff6ceb9796fe7niq return "Too many arguments to directive";
41369ed0bc7f2db6272278c27025f6aabf97fe63nd return "header unset takes two arguments";
41369ed0bc7f2db6272278c27025f6aabf97fe63nd return "Header echo takes two arguments";
d24345ec3173e01df72469ded862084c98ae4d61covener if (cmd->info != &hdr_out_onsuccess && cmd->info != &hdr_out_always)
174a8f105b1c11aa50a05993ea8ba2d117d3df6end return "Header echo only valid on Header "
496f8f3966319d43455675630a849bae019d2a32nd "directives";
ef5650b61a8e35f3cc93ec07e73efc17ea329894jorton regex = ap_pregcomp(cmd->pool, hdr, AP_REG_EXTENDED | AP_REG_NOSUB);
3bc407b46a67691f3e5fd4f5f5ead4e1eff09998stoddard return "Header echo regex could not be compiled";
08eb8303a91265264085e646f5937c76ae1e0c5bnd return "Header requires three arguments";
fd709745f1226d683c57ad9bbcdd05971d214d0cstoddard /* Handle the envclause on Header */
cf82d17373559b6163dbd6c844c1af82cab56883niq return "error: missing environment variable name. "
cf82d17373559b6163dbd6c844c1af82cab56883niq "envclause should be in the form env=envar ";
c07f5b18040b0d39b077666ad6fbbd28fe0eb5f1sf expr = ap_expr_parse_cmd(cmd, envclause + 5, 0, &err, NULL);
c07f5b18040b0d39b077666ad6fbbd28fe0eb5f1sf return apr_pstrcat(cmd->pool, "Unknown parameter: ", envclause,
89ea31761658f422cf21cd3b0224dc5fe95cccd3nd/* Handle all (xxx)Header directives */
ea92d0ffcb30b186010a2c8ca2c80d2ac09e34dastoddardstatic const char *header_cmd(cmd_parms *cmd, void *indirconf,
fd709745f1226d683c57ad9bbcdd05971d214d0cstoddard const char *args)
13c7ff50f27aefa2594d33089fcff6ceb9796fe7niq subs = *args ? ap_getword_conf(cmd->pool, &args) : NULL;
08eb8303a91265264085e646f5937c76ae1e0c5bnd envclause = *args ? ap_getword_conf(cmd->pool, &args) : NULL;
13c7ff50f27aefa2594d33089fcff6ceb9796fe7niq return header_inout_cmd(cmd, indirconf, action, hdr, val, subs, envclause);
e8f95a682820a599fe41b22977010636be5c2717jim * Process the tags in the format string. Tags may be format specifiers
fd0075570654d8f3473f12c47f507c8b3c59a8e4stoddard * (%D, %t, etc.), whitespace or text strings. For each tag, run the handler
fd0075570654d8f3473f12c47f507c8b3c59a8e4stoddard * (formatter) specific to the tag. Handlers return text strings.
e8f95a682820a599fe41b22977010636be5c2717jim * Concatenate the return from each handler into one string that is
fd0075570654d8f3473f12c47f507c8b3c59a8e4stoddard * returned from this call.
81849cd8925f6ffaf57412aaaac8a6df0d33cbb6covener * If the original value was prefixed with "expr=", processing is
81849cd8925f6ffaf57412aaaac8a6df0d33cbb6covener * handled instead by ap_expr.
3becbd2611ffb2e8391a8eacce765b43dcb1c669wrowestatic char* process_tags(header_entry *hdr, request_rec *r)
fd0075570654d8f3473f12c47f507c8b3c59a8e4stoddard const char *s;
81849cd8925f6ffaf57412aaaac8a6df0d33cbb6covener ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02557)
13c7ff50f27aefa2594d33089fcff6ceb9796fe7niqstatic const char *process_regexp(header_entry *hdr, const char *value,
465bb7463b2334971514d5bc5df37de7ce88b151sf if (ap_regexec(hdr->regex, value, AP_MAX_REG_MATCH, pmatch, 0)) {
13c7ff50f27aefa2594d33089fcff6ceb9796fe7niq /* no match, nothing to do */
88fa154e9a87c35cf4ee74d46f095f66fe897d0edruggeri /* Process tags in the input string rather than the resulting
88fa154e9a87c35cf4ee74d46f095f66fe897d0edruggeri * substitution to avoid surprises
88fa154e9a87c35cf4ee74d46f095f66fe897d0edruggeri subs = ap_pregsub(r->pool, process_tags(hdr, r), value, AP_MAX_REG_MATCH, pmatch);
13c7ff50f27aefa2594d33089fcff6ceb9796fe7niq diffsz = strlen(subs) - (pmatch[0].rm_eo - pmatch[0].rm_so);
64dbb5532fba398c5e81efeb21c7fd50c05819d7niq else { /* recurse to edit multiple matches if applicable */
88fa154e9a87c35cf4ee74d46f095f66fe897d0edruggeri remainder = process_regexp(hdr, value + pmatch[0].rm_eo, r);
64dbb5532fba398c5e81efeb21c7fd50c05819d7niq diffsz += strlen(remainder) - strlen(value + pmatch[0].rm_eo);
88fa154e9a87c35cf4ee74d46f095f66fe897d0edruggeri ret = apr_palloc(r->pool, strlen(value) + 1 + diffsz);
3bc407b46a67691f3e5fd4f5f5ead4e1eff09998stoddardstatic int echo_header(echo_do *v, const char *key, const char *val)
e8f95a682820a599fe41b22977010636be5c2717jim /* If the input header (key) matches the regex, echo it intact to
3bc407b46a67691f3e5fd4f5f5ead4e1eff09998stoddard * r->headers_out.
6951fc02abfd7642e45333902c14855836717fadrpluemstatic int edit_header(void *v, const char *key, const char *val)
88fa154e9a87c35cf4ee74d46f095f66fe897d0edruggeri const char *repl = process_regexp(ed->hdr, val, ed->r);
6951fc02abfd7642e45333902c14855836717fadrpluemstatic int add_them_all(void *v, const char *key, const char *val)
51254470cbee1458031e364c8126e75ff07d225fsfstatic int do_headers_fixup(request_rec *r, apr_table_t *headers,
ea92d0ffcb30b186010a2c8ca2c80d2ac09e34dastoddard header_entry *hdr = &((header_entry *) (fixup->elts))[i];
43c3e6a4b559b76b750c245ee95e2782c15b4296jim /* ignore early headers in late calls */
43c3e6a4b559b76b750c245ee95e2782c15b4296jim /* ignore late headers in early calls */
87e0bf269cc3386ee8e6ab561ff00770151f4f53niq /* Do we have an expression to evaluate? */
185aa71728867671e105178b4c66fbc22b65ae26sf ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01501)
8fae12696bce44be9ce4c56888690cad8ac7b8f9sf "Failed to evaluate expression (%s) - ignoring",
87e0bf269cc3386ee8e6ab561ff00770151f4f53niq else if (!eval) {
fd709745f1226d683c57ad9bbcdd05971d214d0cstoddard /* Have any conditional envar-controlled Header processing to do? */
fd709745f1226d683c57ad9bbcdd05971d214d0cstoddard if (apr_table_get(r->subprocess_env, envar) == NULL)
fd709745f1226d683c57ad9bbcdd05971d214d0cstoddard if (apr_table_get(r->subprocess_env, &envar[1]) != NULL)
3becbd2611ffb2e8391a8eacce765b43dcb1c669wrowe apr_table_addn(headers, hdr->header, process_tags(hdr, r));
3becbd2611ffb2e8391a8eacce765b43dcb1c669wrowe apr_table_mergen(headers, hdr->header, process_tags(hdr, r));
3becbd2611ffb2e8391a8eacce765b43dcb1c669wrowe apr_table_addn(headers, hdr->header, process_tags(hdr, r));
22a7cd38c192adb811c7ab9bcba7b9261bf1c9edchrisd /* modified version of logic in ap_get_token() */
3becbd2611ffb2e8391a8eacce765b43dcb1c669wrowe apr_table_setn(headers, hdr->header, process_tags(hdr, r));
45dffe6c346dd73571ccaead10295fc7d53b59a6covener apr_table_setn(headers, hdr->header, process_tags(hdr, r));
e8f95a682820a599fe41b22977010636be5c2717jim apr_table_do((int (*) (void *, const char *, const char *))
3a183ee5b8f8129f6d3ec493be51abacda7c6ea7niq if (!strcasecmp(hdr->header, "Content-Type") && r->content_type) {
88fa154e9a87c35cf4ee74d46f095f66fe897d0edruggeri const char *repl = process_regexp(hdr, r->content_type, r);
6951fc02abfd7642e45333902c14855836717fadrpluem apr_table_do(add_them_all, (void *) headers, ed.t, NULL);
4b3f656d2ad030be85d219e02fdc11546ddecb5ccovener apr_table_setn(r->notes, process_tags(hdr, r), apr_table_get(headers, hdr->header));
ea92d0ffcb30b186010a2c8ca2c80d2ac09e34dastoddardstatic void ap_headers_insert_output_filter(request_rec *r)
ea92d0ffcb30b186010a2c8ca2c80d2ac09e34dastoddard headers_conf *dirconf = ap_get_module_config(r->per_dir_config,
08eb8303a91265264085e646f5937c76ae1e0c5bnd if (dirconf->fixup_out->nelts || dirconf->fixup_err->nelts) {
a47a28784ca46876076471d2a0b45c11f800bffestoddard ap_add_output_filter("FIXUP_HEADERS_OUT", NULL, r, r->connection);
71f3601de4983bc2a6aaffcf37dc1d35c8674a34coar * Make sure our error-path filter is in place.
71f3601de4983bc2a6aaffcf37dc1d35c8674a34coarstatic void ap_headers_insert_error_filter(request_rec *r)
71f3601de4983bc2a6aaffcf37dc1d35c8674a34coar headers_conf *dirconf = ap_get_module_config(r->per_dir_config,
71f3601de4983bc2a6aaffcf37dc1d35c8674a34coar ap_add_output_filter("FIXUP_HEADERS_ERR", NULL, r, r->connection);
ea92d0ffcb30b186010a2c8ca2c80d2ac09e34dastoddardstatic apr_status_t ap_headers_output_filter(ap_filter_t *f,
ea92d0ffcb30b186010a2c8ca2c80d2ac09e34dastoddard headers_conf *dirconf = ap_get_module_config(f->r->per_dir_config,
5f311c280b145c6a435cddb9ab98c9e87a17ce94covener ap_log_error(APLOG_MARK, APLOG_TRACE2, 0, f->r->server, APLOGNO(01502)
a47a28784ca46876076471d2a0b45c11f800bffestoddard "headers: ap_headers_output_filter()");
ea92d0ffcb30b186010a2c8ca2c80d2ac09e34dastoddard /* do the fixup */
cf82d17373559b6163dbd6c844c1af82cab56883niq do_headers_fixup(f->r, f->r->err_headers_out, dirconf->fixup_err, 0);
cf82d17373559b6163dbd6c844c1af82cab56883niq do_headers_fixup(f->r, f->r->headers_out, dirconf->fixup_out, 0);
ea92d0ffcb30b186010a2c8ca2c80d2ac09e34dastoddard /* remove ourselves from the filter chain */
ea92d0ffcb30b186010a2c8ca2c80d2ac09e34dastoddard /* send the data up the stack */
174a8f105b1c11aa50a05993ea8ba2d117d3df6end * Make sure we propagate any "Header always" settings on the error
71f3601de4983bc2a6aaffcf37dc1d35c8674a34coar * path through http_protocol.c.
71f3601de4983bc2a6aaffcf37dc1d35c8674a34coarstatic apr_status_t ap_headers_error_filter(ap_filter_t *f,
185aa71728867671e105178b4c66fbc22b65ae26sf ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, f->r->server, APLOGNO(01503)
71f3601de4983bc2a6aaffcf37dc1d35c8674a34coar "headers: ap_headers_error_filter()");
174a8f105b1c11aa50a05993ea8ba2d117d3df6end * Add any header fields defined by "Header always" to r->err_headers_out.
71f3601de4983bc2a6aaffcf37dc1d35c8674a34coar * Server-wide first, then per-directory to allow overriding.
cf82d17373559b6163dbd6c844c1af82cab56883niq do_headers_fixup(f->r, f->r->err_headers_out, dirconf->fixup_err, 0);
71f3601de4983bc2a6aaffcf37dc1d35c8674a34coar * We've done our bit; remove ourself from the filter chain so there's
71f3601de4983bc2a6aaffcf37dc1d35c8674a34coar * no possibility we'll be called again.
71f3601de4983bc2a6aaffcf37dc1d35c8674a34coar * Pass the buck. (euro?)
ea92d0ffcb30b186010a2c8ca2c80d2ac09e34dastoddardstatic apr_status_t ap_headers_fixup(request_rec *r)
a6b9ed64fdf548c61de9714e2cfb999ec59d149cgstein headers_conf *dirconf = ap_get_module_config(r->per_dir_config,
ea92d0ffcb30b186010a2c8ca2c80d2ac09e34dastoddard /* do the fixup */
cf82d17373559b6163dbd6c844c1af82cab56883niq do_headers_fixup(r, r->headers_in, dirconf->fixup_in, 0);
cf82d17373559b6163dbd6c844c1af82cab56883niq headers_conf *dirconf = ap_get_module_config(r->per_dir_config,
cf82d17373559b6163dbd6c844c1af82cab56883niq /* do the fixup */
51254470cbee1458031e364c8126e75ff07d225fsf if (!do_headers_fixup(r, r->headers_in, dirconf->fixup_in, 1))
51254470cbee1458031e364c8126e75ff07d225fsf if (!do_headers_fixup(r, r->err_headers_out, dirconf->fixup_err, 1))
51254470cbee1458031e364c8126e75ff07d225fsf if (!do_headers_fixup(r, r->headers_out, dirconf->fixup_out, 1))
185aa71728867671e105178b4c66fbc22b65ae26sf ap_log_rerror(APLOG_MARK, APLOG_CRIT, 0, r, APLOGNO(01504)
51254470cbee1458031e364c8126e75ff07d225fsf "Regular expression replacement failed (replacement too long?)");
26f56d4a3c12077d605362e97490e34522fa4814covener AP_INIT_RAW_ARGS("Header", header_cmd, &hdr_out_onsuccess, OR_FILEINFO,
174a8f105b1c11aa50a05993ea8ba2d117d3df6end "an optional condition, an action, header and value "
174a8f105b1c11aa50a05993ea8ba2d117d3df6end "followed by optional env clause"),
08eb8303a91265264085e646f5937c76ae1e0c5bnd AP_INIT_RAW_ARGS("RequestHeader", header_cmd, &hdr_in, OR_FILEINFO,
89ea31761658f422cf21cd3b0224dc5fe95cccd3nd "an action, header and value followed by optional env "
89ea31761658f422cf21cd3b0224dc5fe95cccd3nd "clause"),
417f504d4d11631c0d062be85347f82a26c88677aaronstatic int header_pre_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp)
3b60bc6cafbb662cb3edc70c1df81c8deb31175ajorton register_format_tag_handler("D", header_request_duration);
3b60bc6cafbb662cb3edc70c1df81c8deb31175ajorton register_format_tag_handler("t", header_request_time);
3b60bc6cafbb662cb3edc70c1df81c8deb31175ajorton register_format_tag_handler("e", header_request_env_var);
3b60bc6cafbb662cb3edc70c1df81c8deb31175ajorton register_format_tag_handler("s", header_request_ssl_var);
0b1e2711d8332fb10ca0a889f17dba261758e893jim register_format_tag_handler("l", header_request_loadavg);
77f0db50b7e6636f6422de76ffb2a0af7acaed6djortonstatic int header_post_config(apr_pool_t *pconf, apr_pool_t *plog,
77f0db50b7e6636f6422de76ffb2a0af7acaed6djorton header_ssl_lookup = APR_RETRIEVE_OPTIONAL_FN(ssl_var_lookup);
71f3601de4983bc2a6aaffcf37dc1d35c8674a34coar ap_register_output_filter("FIXUP_HEADERS_OUT", ap_headers_output_filter,
71f3601de4983bc2a6aaffcf37dc1d35c8674a34coar ap_register_output_filter("FIXUP_HEADERS_ERR", ap_headers_error_filter,
fd0075570654d8f3473f12c47f507c8b3c59a8e4stoddard ap_hook_pre_config(header_pre_config,NULL,NULL,APR_HOOK_MIDDLE);
77f0db50b7e6636f6422de76ffb2a0af7acaed6djorton ap_hook_post_config(header_post_config,NULL,NULL,APR_HOOK_MIDDLE);
ea92d0ffcb30b186010a2c8ca2c80d2ac09e34dastoddard ap_hook_insert_filter(ap_headers_insert_output_filter, NULL, NULL, APR_HOOK_LAST);
71f3601de4983bc2a6aaffcf37dc1d35c8674a34coar ap_hook_insert_error_filter(ap_headers_insert_error_filter,
ea92d0ffcb30b186010a2c8ca2c80d2ac09e34dastoddard ap_hook_fixups(ap_headers_fixup, NULL, NULL, APR_HOOK_LAST);
cf82d17373559b6163dbd6c844c1af82cab56883niq ap_hook_post_read_request(ap_headers_early, NULL, NULL, APR_HOOK_FIRST);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding create_headers_dir_config, /* dir config creater */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding merge_headers_config, /* dir merger --- default is to override */