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