Apache HTTPD
mod_headers.c
Go to the documentation of this file.
1/* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17/*
18 * mod_headers.c: Add/append/remove HTTP response headers
19 * Written by Paul Sutton, [email protected], 1 Oct 1996
20 *
21 * The Header directive can be used to add/replace/remove HTTP headers
22 * within the response message. The RequestHeader directive can be used
23 * to add/replace/remove HTTP headers before a request message is processed.
24 * Valid in both per-server and per-dir configurations.
25 *
26 * Syntax is:
27 *
28 * Header action header value
29 * RequestHeader action header value
30 *
31 * Where action is one of:
32 * set - set this header, replacing any old value
33 * add - add this header, possible resulting in two or more
34 * headers with the same name
35 * append - append this text onto any existing header of this same
36 * merge - merge this text onto any existing header of this same,
37 * avoiding duplicate values
38 * unset - remove this header
39 * edit - transform the header value according to a regexp
40 *
41 * Where action is unset, the third argument (value) should not be given.
42 * The header name can include the colon, or not.
43 *
44 * The Header and RequestHeader directives can only be used where allowed
45 * by the FileInfo override.
46 *
47 * When the request is processed, the header directives are processed in
48 * this order: firstly, the main server, then the virtual server handling
49 * this request (if any), then any <Directory> sections (working downwards
50 * from the root dir), then an <Location> sections (working down from
51 * shortest URL component), the any <File> sections. This order is
52 * important if any 'set' or 'unset' actions are used. For example,
53 * the following two directives have different effect if applied in
54 * the reverse order:
55 *
56 * Header append Author "John P. Doe"
57 * Header unset Author
58 *
59 * Examples:
60 *
61 * To set the "Author" header, use
62 * Header add Author "John P. Doe"
63 *
64 * To remove a header:
65 * Header unset Author
66 *
67 */
68
69#include "apr.h"
70#include "apr_lib.h"
71#include "apr_strings.h"
72#include "apr_buckets.h"
73
74#include "apr_hash.h"
75#define APR_WANT_STRFUNC
76#include "apr_want.h"
77
78#include "httpd.h"
79#include "http_config.h"
80#include "http_request.h"
81#include "http_ssl.h"
82#include "http_log.h"
83#include "util_filter.h"
84#include "http_protocol.h"
85#include "ap_expr.h"
86
87/* format_tag_hash is initialized during pre-config */
89
90typedef enum {
91 hdr_add = 'a', /* add header (could mean multiple hdrs) */
92 hdr_set = 's', /* set (replace old value) */
93 hdr_append = 'm', /* append (merge into any old value) */
94 hdr_merge = 'g', /* merge (merge, but avoid duplicates) */
95 hdr_unset = 'u', /* unset header */
96 hdr_echo = 'e', /* echo headers from request to response */
97 hdr_edit = 'r', /* change value by regexp, match once */
98 hdr_edit_r = 'R', /* change value by regexp, everymatch */
99 hdr_setifempty = 'i', /* set value if header not already present*/
100 hdr_note = 'n' /* set value of header in a note */
102
103/*
104 * magic cmd->info values
105 */
106static char hdr_in = '0'; /* RequestHeader */
107static char hdr_out_onsuccess = '1'; /* Header onsuccess */
108static char hdr_out_always = '2'; /* Header always */
109
110/* Callback function type. */
111typedef const char *format_tag_fn(request_rec *r, char *a);
112
113/*
114 * There is an array of struct format_tag per Header/RequestHeader
115 * config directive
116 */
117typedef struct {
119 char *arg;
120} format_tag;
121
122/* 'Magic' condition_var value to run action in post_read_request */
123static const char* condition_early = "early";
124/*
125 * There is one "header_entry" per Header/RequestHeader config directive
126 */
127typedef struct {
129 const char *header;
130 apr_array_header_t *ta; /* Array of format_tag structs */
132 const char *condition_var;
133 const char *subs;
137
138/* echo_do is used for Header echo to iterate through the request headers*/
139typedef struct {
142} echo_do;
143
144/* edit_do is used for Header edit to iterate through the request headers */
150
151/*
152 * headers_conf is our per-module configuration. This is used as both
153 * a per-dir and per-server config
154 */
160
161module AP_MODULE_DECLARE_DATA headers_module;
162
163/*
164 * Tag formatting functions
165 */
166static const char *constant_item(request_rec *r, char *stuff)
167{
168 return stuff;
169}
170static const char *header_request_duration(request_rec *r, char *a)
171{
172 return apr_psprintf(r->pool, "D=%" APR_TIME_T_FMT,
174}
175static const char *header_request_time(request_rec *r, char *a)
176{
178}
179
180/* unwrap_header returns HDR with any newlines converted into
181 * whitespace if necessary. */
182static const char *unwrap_header(apr_pool_t *p, const char *hdr)
183{
185 char *ptr;
186
187 hdr = ptr = apr_pstrdup(p, hdr);
188
189 do {
190 if (*ptr == APR_ASCII_LF || *ptr == APR_ASCII_CR)
191 *ptr = APR_ASCII_BLANK;
192 } while (*ptr++);
193 }
194 return hdr;
195}
196
197static const char *header_request_env_var(request_rec *r, char *a)
198{
199 const char *s = apr_table_get(r->subprocess_env,a);
200
201 if (s)
202 return unwrap_header(r->pool, s);
203 else
204 return "(null)";
205}
206
207static const char *header_request_ssl_var(request_rec *r, char *name)
208{
209 const char *val = ap_ssl_var_lookup(r->pool, r->server,
210 r->connection, r, name);
211 if (val && val[0])
212 return unwrap_header(r->pool, val);
213 else
214 return "(null)";
215}
216
217static const char *header_request_loadavg(request_rec *r, char *a)
218{
221 return apr_psprintf(r->pool, "l=%.2f/%.2f/%.2f", t.loadavg,
222 t.loadavg5, t.loadavg15);
223}
224
225static const char *header_request_idle(request_rec *r, char *a)
226{
228 ap_get_sload(&t);
229 return apr_psprintf(r->pool, "i=%d", t.idle);
230}
231
232static const char *header_request_busy(request_rec *r, char *a)
233{
235 ap_get_sload(&t);
236 return apr_psprintf(r->pool, "b=%d", t.busy);
237}
238
239/*
240 * Config routines
241 */
242
244{
245 headers_conf *conf = apr_pcalloc(p, sizeof(*conf));
246
247 conf->fixup_in = apr_array_make(p, 2, sizeof(header_entry));
248 conf->fixup_out = apr_array_make(p, 2, sizeof(header_entry));
249 conf->fixup_err = apr_array_make(p, 2, sizeof(header_entry));
250
251 return conf;
252}
253
255{
259
260 newconf->fixup_in = apr_array_append(p, base->fixup_in,
261 overrides->fixup_in);
262 newconf->fixup_out = apr_array_append(p, base->fixup_out,
263 overrides->fixup_out);
264 newconf->fixup_err = apr_array_append(p, base->fixup_err,
265 overrides->fixup_err);
266
267 return newconf;
268}
269
270static char *parse_misc_string(apr_pool_t *p, format_tag *tag, const char **sa)
271{
272 const char *s;
273 char *d;
274
275 tag->func = constant_item;
276
277 s = *sa;
278 while (*s && *s != '%') {
279 s++;
280 }
281 /*
282 * This might allocate a few chars extra if there's a backslash
283 * escape in the format string.
284 */
285 tag->arg = apr_palloc(p, s - *sa + 1);
286
287 d = tag->arg;
288 s = *sa;
289 while (*s && *s != '%') {
290 if (*s != '\\') {
291 *d++ = *s++;
292 }
293 else {
294 s++;
295 switch (*s) {
296 case '\\':
297 *d++ = '\\';
298 s++;
299 break;
300 case 'r':
301 *d++ = '\r';
302 s++;
303 break;
304 case 'n':
305 *d++ = '\n';
306 s++;
307 break;
308 case 't':
309 *d++ = '\t';
310 s++;
311 break;
312 default:
313 /* copy verbatim */
314 *d++ = '\\';
315 /*
316 * Allow the loop to deal with this *s in the normal
317 * fashion so that it handles end of string etc.
318 * properly.
319 */
320 break;
321 }
322 }
323 }
324 *d = '\0';
325
326 *sa = s;
327 return NULL;
328}
329
330static char *parse_format_tag(apr_pool_t *p, format_tag *tag, const char **sa)
331{
332 const char *s = *sa;
333 const char * (*tag_handler)(request_rec *,char *);
334
335 /* Handle string literal/conditionals */
336 if (*s != '%') {
337 return parse_misc_string(p, tag, sa);
338 }
339 s++; /* skip the % */
340
341 /* Pass through %% or % at end of string as % */
342 if ((*s == '%') || (*s == '\0')) {
343 tag->func = constant_item;
344 tag->arg = "%";
345 if (*s)
346 s++;
347 *sa = s;
348 return NULL;
349 }
350
351 tag->arg = "\0";
352 /* grab the argument if there is one */
353 if (*s == '{') {
354 ++s;
355 tag->arg = ap_getword(p,&s,'}');
356 }
357
358 tag_handler = (const char * (*)(request_rec *,char *))apr_hash_get(format_tag_hash, s++, 1);
359
360 if (!tag_handler) {
361 char dummy[2];
362 dummy[0] = s[-1];
363 dummy[1] = '\0';
364 return apr_pstrcat(p, "Unrecognized header format %", dummy, NULL);
365 }
366 tag->func = tag_handler;
367
368 *sa = s;
369 return NULL;
370}
371
372/*
373 * A format string consists of white space, text and optional format
374 * tags in any order. E.g.,
375 *
376 * Header add MyHeader "Free form text %D %t more text"
377 *
378 * Decompose the format string into its tags. Each tag (struct format_tag)
379 * contains a pointer to the function used to format the tag. Then save each
380 * tag in the tag array anchored in the header_entry.
381 */
382static char *parse_format_string(cmd_parms *cmd, header_entry *hdr, const char *s)
383{
384 apr_pool_t *p = cmd->pool;
385 char *res;
386
387 /* No string to parse with unset and echo commands */
388 if (hdr->action == hdr_unset || hdr->action == hdr_echo) {
389 return NULL;
390 }
391 /* Tags are in the replacement value for edit */
392 else if (hdr->action == hdr_edit || hdr->action == hdr_edit_r ) {
393 s = hdr->subs;
394 }
395
396 if (!strncmp(s, "expr=", 5)) {
397 const char *err;
398 hdr->expr_out = ap_expr_parse_cmd(cmd, s+5,
400 &err, NULL);
401 if (err) {
402 return apr_pstrcat(cmd->pool,
403 "Can't parse value expression : ", err, NULL);
404 }
405 return NULL;
406 }
407
408 hdr->ta = apr_array_make(p, 10, sizeof(format_tag));
409
410 while (*s) {
411 if ((res = parse_format_tag(p, (format_tag *) apr_array_push(hdr->ta), &s))) {
412 return res;
413 }
414 }
415 return NULL;
416}
417
418/* handle RequestHeader and Header directive */
420 void *indirconf,
421 const char *action,
422 const char *hdr,
423 const char *value,
424 const char *subs,
425 const char *envclause)
426{
428 const char *condition_var = NULL;
429 const char *colon;
430 header_entry *new;
431 ap_expr_info_t *expr = NULL;
432
433 apr_array_header_t *fixup = (cmd->info == &hdr_in)
434 ? dirconf->fixup_in : (cmd->info == &hdr_out_always)
435 ? dirconf->fixup_err
436 : dirconf->fixup_out;
437
439
440 if (!strcasecmp(action, "set"))
441 new->action = hdr_set;
442 else if (!strcasecmp(action, "setifempty"))
443 new->action = hdr_setifempty;
444 else if (!strcasecmp(action, "add"))
445 new->action = hdr_add;
446 else if (!strcasecmp(action, "append"))
447 new->action = hdr_append;
448 else if (!strcasecmp(action, "merge"))
449 new->action = hdr_merge;
450 else if (!strcasecmp(action, "unset"))
451 new->action = hdr_unset;
452 else if (!strcasecmp(action, "echo"))
453 new->action = hdr_echo;
454 else if (!strcasecmp(action, "edit"))
455 new->action = hdr_edit;
456 else if (!strcasecmp(action, "edit*"))
457 new->action = hdr_edit_r;
458 else if (!strcasecmp(action, "note"))
459 new->action = hdr_note;
460 else
461 return "first argument must be 'add', 'set', 'setifempty', 'append', 'merge', "
462 "'unset', 'echo', 'note', 'edit', or 'edit*'.";
463
464 if (new->action == hdr_edit || new->action == hdr_edit_r) {
465 if (subs == NULL) {
466 return "Header edit requires a match and a substitution";
467 }
468 new->regex = ap_pregcomp(cmd->pool, value, AP_REG_EXTENDED);
469 if (new->regex == NULL) {
470 return "Header edit regex could not be compiled";
471 }
472 new->subs = subs;
473 }
474 else {
475 /* there's no subs, so envclause is really that argument */
476 if (envclause != NULL) {
477 return "Too many arguments to directive";
478 }
479 envclause = subs;
480 }
481 if (new->action == hdr_unset) {
482 if (value) {
483 if (envclause) {
484 return "header unset takes two arguments";
485 }
487 value = NULL;
488 }
489 }
490 else if (new->action == hdr_echo) {
492
493 if (value) {
494 if (envclause) {
495 return "Header echo takes two arguments";
496 }
498 value = NULL;
499 }
500 if (cmd->info != &hdr_out_onsuccess && cmd->info != &hdr_out_always)
501 return "Header echo only valid on Header "
502 "directives";
503 else {
505 if (regex == NULL) {
506 return "Header echo regex could not be compiled";
507 }
508 }
509 new->regex = regex;
510 }
511 else if (!value)
512 return "Header requires three arguments";
513
514 /* Handle the envclause on Header */
515 if (envclause != NULL) {
516 if (strcasecmp(envclause, "early") == 0) {
517 condition_var = condition_early;
518 }
519 else if (strncasecmp(envclause, "env=", 4) == 0) {
520 if ((envclause[4] == '\0')
521 || ((envclause[4] == '!') && (envclause[5] == '\0'))) {
522 return "error: missing environment variable name. "
523 "envclause should be in the form env=envar ";
524 }
525 condition_var = envclause + 4;
526 }
527 else if (strncasecmp(envclause, "expr=", 5) == 0) {
528 const char *err = NULL;
529 expr = ap_expr_parse_cmd(cmd, envclause + 5, 0, &err, NULL);
530 if (err) {
531 return apr_pstrcat(cmd->pool,
532 "Can't parse envclause/expression: ", err,
533 NULL);
534 }
535 }
536 else {
537 return apr_pstrcat(cmd->pool, "Unknown parameter: ", envclause,
538 NULL);
539 }
540 }
541
542 if ((colon = ap_strchr_c(hdr, ':'))) {
543 hdr = apr_pstrmemdup(cmd->pool, hdr, colon-hdr);
544 }
545
546 new->header = hdr;
547 new->condition_var = condition_var;
548 new->expr = expr;
549
550 return parse_format_string(cmd, new, value);
551}
552
553/* Handle all (xxx)Header directives */
554static const char *header_cmd(cmd_parms *cmd, void *indirconf,
555 const char *args)
556{
557 const char *action;
558 const char *hdr;
559 const char *val;
560 const char *envclause;
561 const char *subs;
562
563 action = ap_getword_conf(cmd->temp_pool, &args);
564 if (cmd->info == &hdr_out_onsuccess) {
565 if (!strcasecmp(action, "always")) {
566 cmd->info = &hdr_out_always;
567 action = ap_getword_conf(cmd->temp_pool, &args);
568 }
569 else if (!strcasecmp(action, "onsuccess")) {
570 action = ap_getword_conf(cmd->temp_pool, &args);
571 }
572 }
573 hdr = ap_getword_conf(cmd->pool, &args);
574 val = *args ? ap_getword_conf(cmd->pool, &args) : NULL;
575 subs = *args ? ap_getword_conf(cmd->pool, &args) : NULL;
576 envclause = *args ? ap_getword_conf(cmd->pool, &args) : NULL;
577
578 if (*args) {
579 return apr_pstrcat(cmd->pool, cmd->cmd->name,
580 " has too many arguments", NULL);
581 }
582
583 return header_inout_cmd(cmd, indirconf, action, hdr, val, subs, envclause);
584}
585
586/*
587 * Process the tags in the format string. Tags may be format specifiers
588 * (%D, %t, etc.), whitespace or text strings. For each tag, run the handler
589 * (formatter) specific to the tag. Handlers return text strings.
590 * Concatenate the return from each handler into one string that is
591 * returned from this call.
592 * If the original value was prefixed with "expr=", processing is
593 * handled instead by ap_expr.
594 */
596{
597 int i;
598 const char *s;
599 char *str = NULL;
601
602 if (hdr->expr_out) {
603 const char *err;
604 const char *val;
605 val = ap_expr_str_exec(r, hdr->expr_out, &err);
606 if (err) {
608 "Can't evaluate value expression: %s", err);
609 return "";
610 }
611 return apr_pstrdup(r->pool, val);
612 }
613
614 tag = (format_tag*) hdr->ta->elts;
615
616 for (i = 0; i < hdr->ta->nelts; i++) {
617 s = tag[i].func(r, tag[i].arg);
618 if (str == NULL)
619 str = apr_pstrdup(r->pool, s);
620 else
621 str = apr_pstrcat(r->pool, str, s, NULL);
622 }
623 return str ? str : "";
624}
625static const char *process_regexp(header_entry *hdr, const char *value,
626 request_rec *r)
627{
629 const char *subs;
630 const char *remainder;
631 char *ret;
632 int diffsz;
633 if (ap_regexec(hdr->regex, value, AP_MAX_REG_MATCH, pmatch, 0)) {
634 /* no match, nothing to do */
635 return value;
636 }
637 /* Process tags in the input string rather than the resulting
638 * substitution to avoid surprises
639 */
641 if (subs == NULL)
642 return NULL;
643 diffsz = strlen(subs) - (pmatch[0].rm_eo - pmatch[0].rm_so);
644 if (hdr->action == hdr_edit) {
646 }
647 else { /* recurse to edit multiple matches if applicable */
648 remainder = process_regexp(hdr, value + pmatch[0].rm_eo, r);
649 if (remainder == NULL)
650 return NULL;
651 diffsz += strlen(remainder) - strlen(value + pmatch[0].rm_eo);
652 }
653 ret = apr_palloc(r->pool, strlen(value) + 1 + diffsz);
654 memcpy(ret, value, pmatch[0].rm_so);
655 strcpy(ret + pmatch[0].rm_so, subs);
657 return ret;
658}
659
660static int echo_header(void *v, const char *key, const char *val)
661{
662 echo_do *ed = (echo_do *)v;
663
664 /* If the input header (key) matches the regex, echo it intact to
665 * r->headers_out.
666 */
667 if (!ap_regexec(ed->hdr->regex, key, 0, NULL, 0)) {
668 apr_table_add(ed->r->headers_out, key, val);
669 }
670
671 return 1;
672}
673
674static int edit_header(void *v, const char *key, const char *val)
675{
676 edit_do *ed = (edit_do *)v;
677 const char *repl = process_regexp(ed->hdr, val, ed->r);
678 if (repl == NULL)
679 return 0;
680
682 return 1;
683}
684
685static int add_them_all(void *v, const char *key, const char *val)
686{
687 apr_table_t *headers = (apr_table_t *)v;
688
689 apr_table_addn(headers, key, val);
690 return 1;
691}
692
695{
696 echo_do v;
697 int i;
698 const char *val;
699
700 for (i = 0; i < fixup->nelts; ++i) {
701 header_entry *hdr = &((header_entry *) (fixup->elts))[i];
702 const char *envar = hdr->condition_var;
703
704 /* ignore early headers in late calls */
705 if (!early && (envar == condition_early)) {
706 continue;
707 }
708 /* ignore late headers in early calls */
709 else if (early && (envar != condition_early)) {
710 continue;
711 }
712 /* Do we have an expression to evaluate? */
713 else if (hdr->expr != NULL) {
714 const char *err = NULL;
715 int eval = ap_expr_exec(r, hdr->expr, &err);
716 if (err) {
718 "Failed to evaluate expression (%s) - ignoring",
719 err);
720 }
721 else if (!eval) {
722 continue;
723 }
724 }
725 /* Have any conditional envar-controlled Header processing to do? */
726 else if (envar && !early) {
727 if (*envar != '!') {
729 continue;
730 }
731 else {
733 continue;
734 }
735 }
736
737 switch (hdr->action) {
738 case hdr_add:
739 apr_table_addn(headers, hdr->header, process_tags(hdr, r));
740 break;
741 case hdr_append:
742 apr_table_mergen(headers, hdr->header, process_tags(hdr, r));
743 break;
744 case hdr_merge:
745 val = apr_table_get(headers, hdr->header);
746 if (val == NULL) {
747 apr_table_addn(headers, hdr->header, process_tags(hdr, r));
748 } else {
749 char *new_val = process_tags(hdr, r);
751 int tok_found = 0;
752
753 /* modified version of logic in ap_get_token() */
754 while (*val) {
755 const char *tok_start;
756
757 while (apr_isspace(*val))
758 ++val;
759
760 tok_start = val;
761
762 while (*val && *val != ',') {
763 if (*val++ == '"')
764 while (*val)
765 if (*val++ == '"')
766 break;
767 }
768
771 tok_found = 1;
772 break;
773 }
774
775 if (*val)
776 ++val;
777 }
778
779 if (!tok_found) {
780 apr_table_mergen(headers, hdr->header, new_val);
781 }
782 }
783 break;
784 case hdr_set:
785 if (!ap_cstr_casecmp(hdr->header, "Content-Type")) {
787 }
788 apr_table_setn(headers, hdr->header, process_tags(hdr, r));
789 break;
790 case hdr_setifempty:
791 if (NULL == apr_table_get(headers, hdr->header)) {
792 if (!ap_cstr_casecmp(hdr->header, "Content-Type")) {
794 }
795 apr_table_setn(headers, hdr->header, process_tags(hdr, r));
796 }
797 break;
798 case hdr_unset:
799 apr_table_unset(headers, hdr->header);
800 break;
801 case hdr_echo:
802 v.r = r;
803 v.hdr = hdr;
805 break;
806 case hdr_edit:
807 case hdr_edit_r:
808 if (!ap_cstr_casecmp(hdr->header, "Content-Type") && r->content_type) {
809 const char *repl = process_regexp(hdr, r->content_type, r);
810 if (repl == NULL)
811 return 0;
813 }
814 if (apr_table_get(headers, hdr->header)) {
815 edit_do ed;
816
817 ed.r = r;
818 ed.hdr = hdr;
819 ed.t = apr_table_make(r->pool, 5);
820 if (!apr_table_do(edit_header, (void *) &ed, headers,
821 hdr->header, NULL))
822 return 0;
823 apr_table_unset(headers, hdr->header);
824 apr_table_do(add_them_all, (void *) headers, ed.t, NULL);
825 }
826 break;
827 case hdr_note:
828 apr_table_setn(r->notes, process_tags(hdr, r), apr_table_get(headers, hdr->header));
829 break;
830
831 }
832 }
833 return 1;
834}
835
837{
839 &headers_module);
840
841 if (dirconf->fixup_out->nelts || dirconf->fixup_err->nelts) {
842 ap_add_output_filter("FIXUP_HEADERS_OUT", NULL, r, r->connection);
843 }
844}
845
846/*
847 * Make sure our error-path filter is in place.
848 */
850{
852 &headers_module);
853
854 if (dirconf->fixup_err->nelts) {
855 ap_add_output_filter("FIXUP_HEADERS_ERR", NULL, r, r->connection);
856 }
857}
858
861{
862 headers_conf *dirconf = ap_get_module_config(f->r->per_dir_config,
863 &headers_module);
864
865 ap_log_error(APLOG_MARK, APLOG_TRACE2, 0, f->r->server, APLOGNO(01502)
866 "headers: ap_headers_output_filter()");
867
868 /* do the fixup */
869 do_headers_fixup(f->r, f->r->err_headers_out, dirconf->fixup_err, 0);
870 do_headers_fixup(f->r, f->r->headers_out, dirconf->fixup_out, 0);
871
872 /* remove ourselves from the filter chain */
874
875 /* send the data up the stack */
876 return ap_pass_brigade(f->next,in);
877}
878
879/*
880 * Make sure we propagate any "Header always" settings on the error
881 * path through http_protocol.c.
882 */
885{
887
888 dirconf = ap_get_module_config(f->r->per_dir_config,
889 &headers_module);
890 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, f->r->server, APLOGNO(01503)
891 "headers: ap_headers_error_filter()");
892
893 /*
894 * Add any header fields defined by "Header always" to r->err_headers_out.
895 * Server-wide first, then per-directory to allow overriding.
896 */
897 do_headers_fixup(f->r, f->r->err_headers_out, dirconf->fixup_err, 0);
898
899 /*
900 * We've done our bit; remove ourself from the filter chain so there's
901 * no possibility we'll be called again.
902 */
904
905 /*
906 * Pass the buck. (euro?)
907 */
908 return ap_pass_brigade(f->next, in);
909}
910
912{
914 &headers_module);
915
916 /* do the fixup */
917 if (dirconf->fixup_in->nelts) {
918 do_headers_fixup(r, r->headers_in, dirconf->fixup_in, 0);
919 }
920
921 return DECLINED;
922}
924{
926 &headers_module);
927
928 /* do the fixup */
929 if (dirconf->fixup_in->nelts) {
930 if (!do_headers_fixup(r, r->headers_in, dirconf->fixup_in, 1))
931 goto err;
932 }
933 if (dirconf->fixup_err->nelts) {
934 if (!do_headers_fixup(r, r->err_headers_out, dirconf->fixup_err, 1))
935 goto err;
936 }
937 if (dirconf->fixup_out->nelts) {
938 if (!do_headers_fixup(r, r->headers_out, dirconf->fixup_out, 1))
939 goto err;
940 }
941
942 return DECLINED;
943err:
945 "Regular expression replacement failed (replacement too long?)");
947}
948
949static const command_rec headers_cmds[] =
950{
952 "an optional condition, an action, header and value "
953 "followed by optional env clause"),
954 AP_INIT_RAW_ARGS("RequestHeader", header_cmd, &hdr_in, OR_FILEINFO,
955 "an action, header and value followed by optional env "
956 "clause"),
957 {NULL}
958};
959
965
979
981 apr_pool_t *ptemp, server_rec *s)
982{
983 return OK;
984}
985
1000
1002{
1004 create_headers_dir_config, /* dir config creater */
1005 merge_headers_config, /* dir merger --- default is to override */
1006 NULL, /* server config */
1007 NULL, /* merge server configs */
1008 headers_cmds, /* command apr_table_t */
1009 register_hooks /* register hooks */
1010};
Expression parser.
const char apr_size_t ap_regmatch_t * pmatch
Definition ap_regex.h:172
#define AP_REG_NOSUB
Definition ap_regex.h:79
#define AP_REG_EXTENDED
Definition ap_regex.h:78
APR-UTIL Buckets/Bucket Brigades.
APR Hash Tables.
APR general purpose library routines.
apr_size_t const unsigned char unsigned int unsigned int d
Definition apr_siphash.h:72
APR Strings library.
apr_array_append(apr_pool_t *p, const apr_array_header_t *first, const apr_array_header_t *second)
Definition apr_tables.c:213
APR Standard Headers Support.
static apr_pool_t * pconf
Definition event.c:441
#define ap_get_module_config(v, m)
void ap_hook_post_config(ap_HOOK_post_config_t *pf, const char *const *aszPre, const char *const *aszSucc, int nOrder)
Definition config.c:105
#define AP_DECLARE_MODULE(foo)
ap_conf_vector_t * base
#define AP_INIT_RAW_ARGS(directive, func, mconfig, where, help)
void ap_hook_pre_config(ap_HOOK_pre_config_t *pf, const char *const *aszPre, const char *const *aszSucc, int nOrder)
Definition config.c:91
request_rec * r
#define AP_MAX_REG_MATCH
Definition httpd.h:309
#define DECLINED
Definition httpd.h:457
#define OK
Definition httpd.h:456
apr_status_t ap_pass_brigade(ap_filter_t *filter, apr_bucket_brigade *bucket)
ap_filter_rec_t * ap_register_output_filter(const char *name, ap_out_filter_func filter_func, ap_init_filter_func filter_init, ap_filter_type ftype)
ap_filter_t * ap_add_output_filter(const char *name, void *ctx, request_rec *r, conn_rec *c)
void ap_remove_output_filter(ap_filter_t *f)
@ AP_FTYPE_CONTENT_SET
#define APLOGNO(n)
Definition http_log.h:117
#define ap_log_rerror
Definition http_log.h:454
#define APLOG_ERR
Definition http_log.h:67
#define ap_log_error
Definition http_log.h:370
#define APLOG_MARK
Definition http_log.h:283
#define APLOG_CRIT
Definition http_log.h:66
#define APLOG_TRACE2
Definition http_log.h:73
#define APLOG_DEBUG
Definition http_log.h:71
void ap_hook_insert_error_filter(ap_HOOK_insert_error_filter_t *pf, const char *const *aszPre, const char *const *aszSucc, int nOrder)
void ap_set_content_type_ex(request_rec *r, const char *ct, int trusted)
void ap_hook_post_read_request(ap_HOOK_post_read_request_t *pf, const char *const *aszPre, const char *const *aszSucc, int nOrder)
Definition protocol.c:2585
const char * ap_ssl_var_lookup(apr_pool_t *p, server_rec *s, conn_rec *c, request_rec *r, const char *name)
Definition ssl.c:186
void ap_hook_fixups(ap_HOOK_fixups_t *pf, const char *const *aszPre, const char *const *aszSucc, int nOrder)
Definition request.c:87
void ap_hook_insert_filter(ap_HOOK_insert_filter_t *pf, const char *const *aszPre, const char *const *aszSucc, int nOrder)
Definition request.c:96
void * dummy
Definition http_vhost.h:62
void const char * arg
Definition http_vhost.h:63
apr_file_t * f
apr_bucket apr_bucket_brigade * a
apr_pool_t apr_dbd_t apr_dbd_results_t ** res
Definition apr_dbd.h:287
const void apr_size_t int colon
Definition apr_escape.h:355
#define APR_HOOK_FIRST
Definition apr_hooks.h:301
#define APR_HOOK_LAST
Definition apr_hooks.h:305
#define APR_HOOK_MIDDLE
Definition apr_hooks.h:303
apr_text_header * hdr
Definition apr_xml.h:77
#define AP_EXPR_FLAG_STRING_RESULT
Definition ap_expr.h:68
#define ap_expr_parse_cmd(cmd, expr, flags, err, lookup_fn)
Definition ap_expr.h:340
int ap_expr_exec(request_rec *r, const ap_expr_info_t *expr, const char **err)
const char * ap_expr_str_exec(request_rec *r, const ap_expr_info_t *expr, const char **err)
#define OR_FILEINFO
#define HTTP_INTERNAL_SERVER_ERROR
Definition httpd.h:535
#define STANDARD20_MODULE_STUFF
int ap_cstr_casecmp(const char *s1, const char *s2)
Definition util.c:3542
void ap_get_loadavg(ap_loadavg_t *ld)
Definition util.c:3360
char * ap_getword(apr_pool_t *p, const char **line, char stop)
Definition util.c:723
#define ap_strchr_c(s, c)
Definition httpd.h:2353
char * ap_pregsub(apr_pool_t *p, const char *input, const char *source, apr_size_t nmatch, ap_regmatch_t pmatch[])
Definition util.c:457
ap_regex_t * ap_pregcomp(apr_pool_t *p, const char *pattern, int cflags)
Definition util.c:262
void ap_get_sload(ap_sload_t *ld)
Definition util.c:3305
char * ap_getword_conf(apr_pool_t *p, const char **line)
Definition util.c:833
apr_size_t size
apr_uint32_t val
Definition apr_atomic.h:66
#define apr_isspace(c)
Definition apr_lib.h:225
const char * value
Definition apr_env.h:51
int apr_status_t
Definition apr_errno.h:44
const char * key
int strcasecmp(const char *a, const char *b)
#define APR_ASCII_BLANK
Definition apr_general.h:59
int strncasecmp(const char *a, const char *b, size_t n)
#define APR_ASCII_CR
Definition apr_general.h:61
#define APR_ASCII_LF
Definition apr_general.h:63
apr_sockaddr_t * sa
apr_interval_time_t t
#define apr_pcalloc(p, size)
Definition apr_pools.h:465
const char * s
Definition apr_strings.h:95
apr_int32_t apr_int32_t apr_int32_t err
apr_int32_t in
apr_cmdtype_e cmd
const char const char *const * args
#define APR_TIME_T_FMT
Definition apr_time.h:52
Apache Configuration.
Apache Logging library.
HTTP protocol handling.
Apache Request library.
SSL protocol handling.
HTTP Daemon routines.
apr_pool_t * p
Definition md_event.c:32
md_subscription * subs
Definition md_event.c:33
static const command_rec headers_cmds[]
static const char * header_cmd(cmd_parms *cmd, void *indirconf, const char *args)
static char hdr_in
const char * format_tag_fn(request_rec *r, char *a)
static void ap_headers_insert_output_filter(request_rec *r)
static int echo_header(void *v, const char *key, const char *val)
static char hdr_out_onsuccess
static apr_status_t ap_headers_error_filter(ap_filter_t *f, apr_bucket_brigade *in)
static char hdr_out_always
static char * process_tags(header_entry *hdr, request_rec *r)
static const char * header_request_ssl_var(request_rec *r, char *name)
static const char * header_request_idle(request_rec *r, char *a)
static const char * unwrap_header(apr_pool_t *p, const char *hdr)
hdr_actions
Definition mod_headers.c:90
@ hdr_add
Definition mod_headers.c:91
@ hdr_merge
Definition mod_headers.c:94
@ hdr_note
@ hdr_edit_r
Definition mod_headers.c:98
@ hdr_set
Definition mod_headers.c:92
@ hdr_setifempty
Definition mod_headers.c:99
@ hdr_edit
Definition mod_headers.c:97
@ hdr_unset
Definition mod_headers.c:95
@ hdr_append
Definition mod_headers.c:93
@ hdr_echo
Definition mod_headers.c:96
static int do_headers_fixup(request_rec *r, apr_table_t *headers, apr_array_header_t *fixup, int early)
static apr_status_t ap_headers_output_filter(ap_filter_t *f, apr_bucket_brigade *in)
static int add_them_all(void *v, const char *key, const char *val)
static void ap_headers_insert_error_filter(request_rec *r)
static void register_format_tag_handler(const char *tag, format_tag_fn *tag_handler)
static const char * constant_item(request_rec *r, char *stuff)
static int header_post_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s)
static APR_INLINE const char * header_inout_cmd(cmd_parms *cmd, void *indirconf, const char *action, const char *hdr, const char *value, const char *subs, const char *envclause)
static const char * header_request_env_var(request_rec *r, char *a)
static int edit_header(void *v, const char *key, const char *val)
static void register_hooks(apr_pool_t *p)
static apr_hash_t * format_tag_hash
Definition mod_headers.c:88
static const char * process_regexp(header_entry *hdr, const char *value, request_rec *r)
static const char * header_request_busy(request_rec *r, char *a)
static const char * header_request_duration(request_rec *r, char *a)
static const char * header_request_loadavg(request_rec *r, char *a)
static apr_status_t ap_headers_early(request_rec *r)
static char * parse_format_string(cmd_parms *cmd, header_entry *hdr, const char *s)
static char * parse_misc_string(apr_pool_t *p, format_tag *tag, const char **sa)
static int header_pre_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp)
static apr_status_t ap_headers_fixup(request_rec *r)
static void * create_headers_dir_config(apr_pool_t *p, char *d)
static char * parse_format_tag(apr_pool_t *p, format_tag *tag, const char **sa)
static const char * header_request_time(request_rec *r, char *a)
static void * merge_headers_config(apr_pool_t *p, void *basev, void *overridesv)
static const char * condition_early
return NULL
Definition mod_so.c:359
int i
Definition mod_so.c:347
char * name
The representation of a filter chain.
A structure to hold various server loadavg.
Definition httpd.h:1427
A structure to hold server load params.
Definition httpd.h:1411
header_entry * hdr
request_rec * r
request_rec * r
header_entry * hdr
apr_table_t * t
format_tag_fn * func
hdr_actions action
const char * header
ap_expr_info_t * expr
ap_regex_t * regex
ap_expr_info_t * expr_out
const char * condition_var
const char * subs
apr_array_header_t * ta
apr_array_header_t * fixup_in
apr_array_header_t * fixup_out
apr_array_header_t * fixup_err
A structure that represents the current request.
Definition httpd.h:845
const char * content_type
Definition httpd.h:992
apr_table_t * notes
Definition httpd.h:985
apr_pool_t * pool
Definition httpd.h:847
apr_time_t request_time
Definition httpd.h:886
conn_rec * connection
Definition httpd.h:849
apr_table_t * err_headers_out
Definition httpd.h:981
apr_table_t * headers_in
Definition httpd.h:976
apr_table_t * subprocess_env
Definition httpd.h:983
server_rec * server
Definition httpd.h:851
struct ap_conf_vector_t * per_dir_config
Definition httpd.h:1047
apr_table_t * headers_out
Definition httpd.h:978
A structure to store information for each virtual server.
Definition httpd.h:1322
#define str
#define regex
Apache filter library.