1 /* ====================================================================
2 * The Apache Software License, Version 1.1
3 *
4 * Copyright (c) 2000-2003 The Apache Software Foundation. All rights
5 * reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 *
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in
16 * the documentation and/or other materials provided with the
17 * distribution.
18 *
19 * 3. The end-user documentation included with the redistribution,
20 * if any, must include the following acknowledgment:
21 * "This product includes software developed by the
22 * Apache Software Foundation (http://www.apache.org/)."
23 * Alternately, this acknowledgment may appear in the software itself,
24 * if and wherever such third-party acknowledgments normally appear.
25 *
26 * 4. The names "Apache" and "Apache Software Foundation" must
27 * not be used to endorse or promote products derived from this
28 * software without prior written permission. For written
29 * permission, please contact apache@apache.org.
30 *
31 * 5. Products derived from this software may not be called "Apache",
32 * nor may "Apache" appear in their name, without prior written
33 * permission of the Apache Software Foundation.
34 *
35 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
36 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
37 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
38 * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
39 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
42 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
43 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
44 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
45 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
46 * SUCH DAMAGE.
47 * ====================================================================
48 *
49 * This software consists of voluntary contributions made by many
50 * individuals on behalf of the Apache Software Foundation. For more
51 * information on the Apache Software Foundation, please see
52 * <http://www.apache.org/>.
53 *
54 * Portions of this software are based upon public domain software
55 * originally written at the National Center for Supercomputing Applications,
56 * University of Illinois, Urbana-Champaign.
57 */
58
59 /*
60 * mod_headers.c: Add/append/remove HTTP response headers
61 * Written by Paul Sutton, paul@ukweb.com, 1 Oct 1996
62 *
63 * New directive, Header, can be used to add/replace/remove HTTP headers.
64 * Valid in both per-server and per-dir configurations.
65 *
66 * Syntax is:
67 *
68 * Header action header value
69 *
70 * Where action is one of:
71 * set - set this header, replacing any old value
72 * add - add this header, possible resulting in two or more
73 * headers with the same name
74 * append - append this text onto any existing header of this same
75 * unset - remove this header
76 *
77 * Where action is unset, the third argument (value) should not be given.
78 * The header name can include the colon, or not.
79 *
80 * The Header directive can only be used where allowed by the FileInfo
81 * override.
82 *
83 * When the request is processed, the header directives are processed in
84 * this order: firstly, the main server, then the virtual server handling
85 * this request (if any), then any <Directory> sections (working downwards
86 * from the root dir), then an <Location> sections (working down from
87 * shortest URL component), the any <File> sections. This order is
88 * important if any 'set' or 'unset' actions are used. For example,
89 * the following two directives have different effect if applied in
90 * the reverse order:
91 *
92 * Header append Author "John P. Doe"
93 * Header unset Author
94 *
95 * Examples:
96 *
97 * To set the "Author" header, use
98 * Header add Author "John P. Doe"
99 *
100 * To remove a header:
101 * Header unset Author
102 *
103 */
104
105 #include "httpd.h"
106 #include "http_config.h"
107
108 typedef enum {
109 hdr_add = 'a', /* add header (could mean multiple hdrs) */
110 hdr_set = 's', /* set (replace old value) */
111 hdr_append = 'm', /* append (merge into any old value) */
112 hdr_unset = 'u' /* unset header */
113 } hdr_actions;
114
115 typedef struct {
116 hdr_actions action;
117 char *header;
118 char *value;
119 int do_err;
120 } header_entry;
121
122 /*
123 * headers_conf is our per-module configuration. This is used as both
124 * a per-dir and per-server config
125 */
126 typedef struct {
127 array_header *headers;
128 } headers_conf;
129
130 module MODULE_VAR_EXPORT headers_module;
131
create_headers_config(pool * p,server_rec * s)132 static void *create_headers_config(pool *p, server_rec *s)
133 {
134 headers_conf *a =
135 (headers_conf *) ap_pcalloc(p, sizeof(headers_conf));
136
137 a->headers = ap_make_array(p, 2, sizeof(header_entry));
138 return a;
139 }
140
create_headers_dir_config(pool * p,char * d)141 static void *create_headers_dir_config(pool *p, char *d)
142 {
143 return (headers_conf *) create_headers_config(p, NULL);
144 }
145
merge_headers_config(pool * p,void * basev,void * overridesv)146 static void *merge_headers_config(pool *p, void *basev, void *overridesv)
147 {
148 headers_conf *a =
149 (headers_conf *) ap_pcalloc(p, sizeof(headers_conf));
150 headers_conf *base = (headers_conf *) basev, *overrides = (headers_conf *) overridesv;
151
152 a->headers = ap_append_arrays(p, base->headers, overrides->headers);
153
154 return a;
155 }
156
header_cmd(cmd_parms * cmd,headers_conf * dirconf,char * action,char * hdr,char * value)157 static const char *header_cmd(cmd_parms *cmd, headers_conf * dirconf, char *action, char *hdr, char *value)
158 {
159 header_entry *new;
160 server_rec *s = cmd->server;
161 headers_conf *serverconf =
162 (headers_conf *) ap_get_module_config(s->module_config, &headers_module);
163 char *colon;
164
165 if (cmd->path) {
166 new = (header_entry *) ap_push_array(dirconf->headers);
167 }
168 else {
169 new = (header_entry *) ap_push_array(serverconf->headers);
170 }
171
172 if (cmd->info) {
173 new->do_err = 1;
174 } else {
175 new->do_err = 0;
176 }
177
178 if (!strcasecmp(action, "set"))
179 new->action = hdr_set;
180 else if (!strcasecmp(action, "add"))
181 new->action = hdr_add;
182 else if (!strcasecmp(action, "append"))
183 new->action = hdr_append;
184 else if (!strcasecmp(action, "unset"))
185 new->action = hdr_unset;
186 else
187 return "first argument must be add, set, append or unset.";
188
189 if (new->action == hdr_unset) {
190 if (value)
191 return "Header unset takes two arguments";
192 }
193 else if (!value)
194 return "Header requires three arguments";
195
196 if ((colon = strchr(hdr, ':')))
197 *colon = '\0';
198
199 new->header = hdr;
200 new->value = value;
201
202 return NULL;
203 }
204
205 static const command_rec headers_cmds[] =
206 {
207 {"Header", header_cmd, (void *)0, OR_FILEINFO, TAKE23,
208 "an action, header and value"},
209 {"ErrorHeader", header_cmd, (void *)1, OR_FILEINFO, TAKE23,
210 "an action, header and value"},
211 {NULL}
212 };
213
do_headers_fixup(request_rec * r,array_header * headers)214 static void do_headers_fixup(request_rec *r, array_header *headers)
215 {
216 int i;
217
218 for (i = 0; i < headers->nelts; ++i) {
219 header_entry *hdr = &((header_entry *) (headers->elts))[i];
220 table *tbl = (hdr->do_err ? r->err_headers_out : r->headers_out);
221 switch (hdr->action) {
222 case hdr_add:
223 ap_table_addn(tbl, hdr->header, hdr->value);
224 break;
225 case hdr_append:
226 ap_table_mergen(tbl, hdr->header, hdr->value);
227 break;
228 case hdr_set:
229 ap_table_setn(tbl, hdr->header, hdr->value);
230 break;
231 case hdr_unset:
232 ap_table_unset(tbl, hdr->header);
233 break;
234 }
235 }
236
237 }
238
fixup_headers(request_rec * r)239 static int fixup_headers(request_rec *r)
240 {
241 void *sconf = r->server->module_config;
242 headers_conf *serverconf =
243 (headers_conf *) ap_get_module_config(sconf, &headers_module);
244 void *dconf = r->per_dir_config;
245 headers_conf *dirconf =
246 (headers_conf *) ap_get_module_config(dconf, &headers_module);
247
248 do_headers_fixup(r, serverconf->headers);
249 do_headers_fixup(r, dirconf->headers);
250
251 return DECLINED;
252 }
253
254 module MODULE_VAR_EXPORT headers_module =
255 {
256 STANDARD_MODULE_STUFF,
257 NULL, /* initializer */
258 create_headers_dir_config, /* dir config creater */
259 merge_headers_config, /* dir merger --- default is to override */
260 create_headers_config, /* server config */
261 merge_headers_config, /* merge server configs */
262 headers_cmds, /* command table */
263 NULL, /* handlers */
264 NULL, /* filename translation */
265 NULL, /* check_user_id */
266 NULL, /* check auth */
267 NULL, /* check access */
268 NULL, /* type_checker */
269 fixup_headers, /* fixups */
270 NULL, /* logger */
271 NULL, /* header parser */
272 NULL, /* child_init */
273 NULL, /* child_exit */
274 NULL /* post read-request */
275 };
276
277
278