Advertisement
Guest User

Untitled

a guest
Sep 15th, 2012
99
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 28.43 KB | None | 0 0
  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_log.h"
  82. #include "util_filter.h"
  83. #include "http_protocol.h"
  84.  
  85. #include "mod_ssl.h" /* for the ssl_var_lookup optional function defn */
  86.  
  87. /* format_tag_hash is initialized during pre-config */
  88. static apr_hash_t *format_tag_hash;
  89.  
  90. typedef 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_actions;
  100.  
  101. /*
  102.  * magic cmd->info values
  103.  */
  104. static char hdr_in  = '0';  /* RequestHeader */
  105. static char hdr_out = '1';  /* Header onsuccess */
  106. static char hdr_err = '2';  /* Header always */
  107.  
  108. /*
  109.  * There is an array of struct format_tag per Header/RequestHeader
  110.  * config directive
  111.  */
  112. typedef struct {
  113.     const char* (*func)(request_rec *r,char *arg);
  114.     char *arg;
  115. } format_tag;
  116.  
  117. /* 'Magic' condition_var value to run action in post_read_request */
  118. static const char* condition_early = "early";
  119. /*
  120.  * There is one "header_entry" per Header/RequestHeader config directive
  121.  */
  122. typedef struct {
  123.     hdr_actions action;
  124.     const char *header;
  125.     apr_array_header_t *ta;   /* Array of format_tag structs */
  126.     ap_regex_t *regex;
  127.     const char *condition_var;
  128.     const char *subs;
  129. } header_entry;
  130.  
  131. /* echo_do is used for Header echo to iterate through the request headers*/
  132. typedef struct {
  133.     request_rec *r;
  134.     header_entry *hdr;
  135. } echo_do;
  136.  
  137. /* edit_do is used for Header edit to iterate through the request headers */
  138. typedef struct {
  139.     apr_pool_t *p;
  140.     header_entry *hdr;
  141.     apr_table_t *t;
  142. } edit_do;
  143.  
  144. /*
  145.  * headers_conf is our per-module configuration. This is used as both
  146.  * a per-dir and per-server config
  147.  */
  148. typedef struct {
  149.     apr_array_header_t *fixup_in;
  150.     apr_array_header_t *fixup_out;
  151.     apr_array_header_t *fixup_err;
  152. } headers_conf;
  153.  
  154. module AP_MODULE_DECLARE_DATA headers_module;
  155.  
  156. /* Pointer to ssl_var_lookup, if available. */
  157. static APR_OPTIONAL_FN_TYPE(ssl_var_lookup) *header_ssl_lookup = NULL;
  158.  
  159. /*
  160.  * Tag formatting functions
  161.  */
  162. static const char *constant_item(request_rec *r, char *stuff)
  163. {
  164.     return stuff;
  165. }
  166. static const char *header_request_duration(request_rec *r, char *a)
  167. {
  168.     return apr_psprintf(r->pool, "D=%" APR_TIME_T_FMT,
  169.                         (apr_time_now() - r->request_time));
  170. }
  171. static const char *header_request_time(request_rec *r, char *a)
  172. {
  173.     return apr_psprintf(r->pool, "t=%" APR_TIME_T_FMT, r->request_time);
  174. }
  175.  
  176. /* unwrap_header returns HDR with any newlines converted into
  177.  * whitespace if necessary. */
  178. static const char *unwrap_header(apr_pool_t *p, const char *hdr)
  179. {
  180.     if (ap_strchr_c(hdr, APR_ASCII_LF) || ap_strchr_c(hdr, APR_ASCII_CR)) {
  181.         char *ptr;
  182.  
  183.         hdr = ptr = apr_pstrdup(p, hdr);
  184.  
  185.         do {
  186.             if (*ptr == APR_ASCII_LF || *ptr == APR_ASCII_CR)
  187.                 *ptr = APR_ASCII_BLANK;
  188.         } while (*ptr++);
  189.     }
  190.     return hdr;
  191. }
  192.  
  193. static const char *header_request_env_var(request_rec *r, char *a)
  194. {
  195.     const char *s = apr_table_get(r->subprocess_env,a);
  196.  
  197.     if (s)
  198.         return unwrap_header(r->pool, s);
  199.     else
  200.         return "(null)";
  201. }
  202.  
  203. static const char *header_request_ssl_var(request_rec *r, char *name)
  204. {
  205.     if (header_ssl_lookup) {
  206.         const char *val = header_ssl_lookup(r->pool, r->server,
  207.                                             r->connection, r, name);
  208.         if (val && val[0])
  209.             return unwrap_header(r->pool, val);
  210.         else
  211.             return "(null)";
  212.     }
  213.     else {
  214.         return "(null)";
  215.     }
  216. }
  217.  
  218. /*
  219.  * Config routines
  220.  */
  221.  
  222. static void *create_headers_dir_config(apr_pool_t *p, char *d)
  223. {
  224.     headers_conf *conf = apr_pcalloc(p, sizeof(*conf));
  225.  
  226.     conf->fixup_in = apr_array_make(p, 2, sizeof(header_entry));
  227.     conf->fixup_out = apr_array_make(p, 2, sizeof(header_entry));
  228.     conf->fixup_err = apr_array_make(p, 2, sizeof(header_entry));
  229.  
  230.     return conf;
  231. }
  232.  
  233. static void *merge_headers_config(apr_pool_t *p, void *basev, void *overridesv)
  234. {
  235.     headers_conf *newconf = apr_pcalloc(p, sizeof(*newconf));
  236.     headers_conf *base = basev;
  237.     headers_conf *overrides = overridesv;
  238.  
  239.     newconf->fixup_in = apr_array_append(p, base->fixup_in,
  240.                                          overrides->fixup_in);
  241.     newconf->fixup_out = apr_array_append(p, base->fixup_out,
  242.                                           overrides->fixup_out);
  243.     newconf->fixup_err = apr_array_append(p, base->fixup_err,
  244.                                           overrides->fixup_err);
  245.  
  246.     return newconf;
  247. }
  248.  
  249. static char *parse_misc_string(apr_pool_t *p, format_tag *tag, const char **sa)
  250. {
  251.     const char *s;
  252.     char *d;
  253.  
  254.     tag->func = constant_item;
  255.  
  256.     s = *sa;
  257.     while (*s && *s != '%') {
  258.         s++;
  259.     }
  260.     /*
  261.      * This might allocate a few chars extra if there's a backslash
  262.      * escape in the format string.
  263.      */
  264.     tag->arg = apr_palloc(p, s - *sa + 1);
  265.  
  266.     d = tag->arg;
  267.     s = *sa;
  268.     while (*s && *s != '%') {
  269.         if (*s != '\\') {
  270.             *d++ = *s++;
  271.         }
  272.         else {
  273.             s++;
  274.             switch (*s) {
  275.             case '\\':
  276.                 *d++ = '\\';
  277.                 s++;
  278.                 break;
  279.             case 'r':
  280.                 *d++ = '\r';
  281.                 s++;
  282.                 break;
  283.             case 'n':
  284.                 *d++ = '\n';
  285.                 s++;
  286.                 break;
  287.             case 't':
  288.                 *d++ = '\t';
  289.                 s++;
  290.                 break;
  291.             default:
  292.                 /* copy verbatim */
  293.                 *d++ = '\\';
  294.                 /*
  295.                  * Allow the loop to deal with this *s in the normal
  296.                  * fashion so that it handles end of string etc.
  297.                  * properly.
  298.                  */
  299.                 break;
  300.             }
  301.         }
  302.     }
  303.     *d = '\0';
  304.  
  305.     *sa = s;
  306.     return NULL;
  307. }
  308.  
  309. static char *parse_format_tag(apr_pool_t *p, format_tag *tag, const char **sa)
  310. {
  311.     const char *s = *sa;
  312.     const char * (*tag_handler)(request_rec *,char *);
  313.  
  314.     /* Handle string literal/conditionals */
  315.     if (*s != '%') {
  316.         return parse_misc_string(p, tag, sa);
  317.     }
  318.     s++; /* skip the % */
  319.  
  320.     /* Pass through %% or % at end of string as % */
  321.     if ((*s == '%') || (*s == '\0')) {
  322.         tag->func = constant_item;
  323.         tag->arg = "%";
  324.         if (*s)
  325.             s++;
  326.         *sa = s;
  327.         return NULL;
  328.     }
  329.  
  330.     tag->arg = '\0';
  331.     /* grab the argument if there is one */
  332.     if (*s == '{') {
  333.         ++s;
  334.         tag->arg = ap_getword(p,&s,'}');
  335.     }
  336.  
  337.     tag_handler = (const char * (*)(request_rec *,char *))apr_hash_get(format_tag_hash, s++, 1);
  338.  
  339.     if (!tag_handler) {
  340.         char dummy[2];
  341.         dummy[0] = s[-1];
  342.         dummy[1] = '\0';
  343.         return apr_pstrcat(p, "Unrecognized header format %", dummy, NULL);
  344.     }
  345.     tag->func = tag_handler;
  346.  
  347.     *sa = s;
  348.     return NULL;
  349. }
  350.  
  351. /*
  352.  * A format string consists of white space, text and optional format
  353.  * tags in any order. E.g.,
  354.  *
  355.  * Header add MyHeader "Free form text %D %t more text"
  356.  *
  357.  * Decompose the format string into its tags. Each tag (struct format_tag)
  358.  * contains a pointer to the function used to format the tag. Then save each
  359.  * tag in the tag array anchored in the header_entry.
  360.  */
  361. static char *parse_format_string(apr_pool_t *p, header_entry *hdr, const char *s)
  362. {
  363.     char *res;
  364.  
  365.     /* No string to parse with unset and echo commands */
  366.     if (hdr->action == hdr_unset ||
  367.         hdr->action == hdr_edit ||
  368.         hdr->action == hdr_edit_r ||
  369.         hdr->action == hdr_echo) {
  370.         return NULL;
  371.     }
  372.  
  373.     hdr->ta = apr_array_make(p, 10, sizeof(format_tag));
  374.  
  375.     while (*s) {
  376.         if ((res = parse_format_tag(p, (format_tag *) apr_array_push(hdr->ta), &s))) {
  377.             return res;
  378.         }
  379.     }
  380.     return NULL;
  381. }
  382.  
  383. /* handle RequestHeader and Header directive */
  384. static APR_INLINE const char *header_inout_cmd(cmd_parms *cmd,
  385.                                                void *indirconf,
  386.                                                const char *action,
  387.                                                const char *hdr,
  388.                                                const char *value,
  389.                                                const char *subs,
  390.                                                const char *envclause)
  391. {
  392.     headers_conf *dirconf = indirconf;
  393.     const char *condition_var = NULL;
  394.     const char *colon;
  395.     header_entry *new;
  396.  
  397.     apr_array_header_t *fixup = (cmd->info == &hdr_in)
  398.         ? dirconf->fixup_in   : (cmd->info == &hdr_err)
  399.         ? dirconf->fixup_err
  400.         : dirconf->fixup_out;
  401.  
  402.     new = (header_entry *) apr_array_push(fixup);
  403.  
  404.     if (!strcasecmp(action, "set"))
  405.         new->action = hdr_set;
  406.     else if (!strcasecmp(action, "add"))
  407.         new->action = hdr_add;
  408.     else if (!strcasecmp(action, "append"))
  409.         new->action = hdr_append;
  410.     else if (!strcasecmp(action, "merge"))
  411.         new->action = hdr_merge;
  412.     else if (!strcasecmp(action, "unset"))
  413.         new->action = hdr_unset;
  414.     else if (!strcasecmp(action, "echo"))
  415.         new->action = hdr_echo;
  416.     else if (!strcasecmp(action, "edit"))
  417.         new->action = hdr_edit;
  418.     else if (!strcasecmp(action, "edit*"))
  419.         new->action = hdr_edit_r;
  420.     else
  421.         return "first argument must be 'add', 'set', 'append', 'merge', "
  422.                "'unset', 'echo', 'edit', or 'edit*'.";
  423.  
  424.     if (new->action == hdr_edit || new->action == hdr_edit_r) {
  425.         if (subs == NULL) {
  426.             return "Header edit requires a match and a substitution";
  427.         }
  428.         new->regex = ap_pregcomp(cmd->pool, value, AP_REG_EXTENDED);
  429.         if (new->regex == NULL) {
  430.             return "Header edit regex could not be compiled";
  431.         }
  432.         new->subs = subs;
  433.     }
  434.     else {
  435.         /* there's no subs, so envclause is really that argument */
  436.         if (envclause != NULL) {
  437.             return "Too many arguments to directive";
  438.         }
  439.         envclause = subs;
  440.     }
  441.     if (new->action == hdr_unset) {
  442.         if (value) {
  443.             if (envclause) {
  444.                 return "header unset takes two arguments";
  445.             }
  446.             envclause = value;
  447.             value = NULL;
  448.         }
  449.     }
  450.     else if (new->action == hdr_echo) {
  451.         ap_regex_t *regex;
  452.  
  453.         if (value) {
  454.             if (envclause) {
  455.                 return "Header echo takes two arguments";
  456.             }
  457.             envclause = value;
  458.             value = NULL;
  459.         }
  460.         if (cmd->info != &hdr_out && cmd->info != &hdr_err)
  461.             return "Header echo only valid on Header "
  462.                    "directives";
  463.         else {
  464.             regex = ap_pregcomp(cmd->pool, hdr, AP_REG_EXTENDED | AP_REG_NOSUB);
  465.             if (regex == NULL) {
  466.                 return "Header echo regex could not be compiled";
  467.             }
  468.         }
  469.         new->regex = regex;
  470.     }
  471.     else if (!value)
  472.         return "Header requires three arguments";
  473.  
  474.     /* Handle the envclause on Header */
  475.     if (envclause != NULL) {
  476.         if (strcasecmp(envclause, "early") == 0) {
  477.             condition_var = condition_early;
  478.         }
  479.         else {
  480.             if (strncasecmp(envclause, "env=", 4) != 0) {
  481.                 return "error: envclause should be in the form env=envar";
  482.             }
  483.             if ((envclause[4] == '\0')
  484.                 || ((envclause[4] == '!') && (envclause[5] == '\0'))) {
  485.                 return "error: missing environment variable name. "
  486.                     "envclause should be in the form env=envar ";
  487.             }
  488.             condition_var = envclause + 4;
  489.         }
  490.     }
  491.  
  492.     if ((colon = ap_strchr_c(hdr, ':'))) {
  493.         hdr = apr_pstrmemdup(cmd->pool, hdr, colon-hdr);
  494.     }
  495.  
  496.     new->header = hdr;
  497.     new->condition_var = condition_var;
  498.  
  499.     return parse_format_string(cmd->pool, new, value);
  500. }
  501.  
  502. /* Handle all (xxx)Header directives */
  503. static const char *header_cmd(cmd_parms *cmd, void *indirconf,
  504.                               const char *args)
  505. {
  506.     const char *action;
  507.     const char *hdr;
  508.     const char *val;
  509.     const char *envclause;
  510.     const char *subs;
  511.  
  512.     action = ap_getword_conf(cmd->pool, &args);
  513.     if (cmd->info == &hdr_out) {
  514.         if (!strcasecmp(action, "always")) {
  515.             cmd->info = &hdr_err;
  516.             action = ap_getword_conf(cmd->pool, &args);
  517.         }
  518.         else if (!strcasecmp(action, "onsuccess")) {
  519.             action = ap_getword_conf(cmd->pool, &args);
  520.         }
  521.     }
  522.     hdr = ap_getword_conf(cmd->pool, &args);
  523.     val = *args ? ap_getword_conf(cmd->pool, &args) : NULL;
  524.     subs = *args ? ap_getword_conf(cmd->pool, &args) : NULL;
  525.     envclause = *args ? ap_getword_conf(cmd->pool, &args) : NULL;
  526.  
  527.     if (*args) {
  528.         return apr_pstrcat(cmd->pool, cmd->cmd->name,
  529.                            " has too many arguments", NULL);
  530.     }
  531.  
  532.     return header_inout_cmd(cmd, indirconf, action, hdr, val, subs, envclause);
  533. }
  534.  
  535. /*
  536.  * Process the tags in the format string. Tags may be format specifiers
  537.  * (%D, %t, etc.), whitespace or text strings. For each tag, run the handler
  538.  * (formatter) specific to the tag. Handlers return text strings.
  539.  * Concatenate the return from each handler into one string that is
  540.  * returned from this call.
  541.  */
  542. static char* process_tags(header_entry *hdr, request_rec *r)
  543. {
  544.     int i;
  545.     const char *s;
  546.     char *str = NULL;
  547.  
  548.     format_tag *tag = (format_tag*) hdr->ta->elts;
  549.  
  550.     for (i = 0; i < hdr->ta->nelts; i++) {
  551.         s = tag[i].func(r, tag[i].arg);
  552.         if (str == NULL)
  553.             str = apr_pstrdup(r->pool, s);
  554.         else
  555.             str = apr_pstrcat(r->pool, str, s, NULL);
  556.     }
  557.     return str ? str : "";
  558. }
  559. static const char *process_regexp(header_entry *hdr, const char *value,
  560.                                   apr_pool_t *pool)
  561. {
  562.     unsigned int nmatch = 10;
  563.     ap_regmatch_t pmatch[10];
  564.     const char *subs;
  565.     const char *remainder;
  566.     char *ret;
  567.     int diffsz;
  568.     if (ap_regexec(hdr->regex, value, nmatch, pmatch, 0)) {
  569.         /* no match, nothing to do */
  570.         return value;
  571.     }
  572.     subs = ap_pregsub(pool, hdr->subs, value, nmatch, pmatch);
  573.     diffsz = strlen(subs) - (pmatch[0].rm_eo - pmatch[0].rm_so);
  574.     if (hdr->action == hdr_edit) {
  575.         remainder = value + pmatch[0].rm_eo;
  576.     }
  577.     else { /* recurse to edit multiple matches if applicable */
  578.         remainder = process_regexp(hdr, value + pmatch[0].rm_eo, pool);
  579.         diffsz += strlen(remainder) - strlen(value + pmatch[0].rm_eo);
  580.     }
  581.     ret = apr_palloc(pool, strlen(value) + 1 + diffsz);
  582.     memcpy(ret, value, pmatch[0].rm_so);
  583.     strcpy(ret + pmatch[0].rm_so, subs);
  584.     strcat(ret, remainder);
  585.     return ret;
  586. }
  587.  
  588. static int echo_header(echo_do *v, const char *key, const char *val)
  589. {
  590.     /* If the input header (key) matches the regex, echo it intact to
  591.      * r->headers_out.
  592.      */
  593.     if (!ap_regexec(v->hdr->regex, key, 0, NULL, 0)) {
  594.         apr_table_add(v->r->headers_out, key, val);
  595.     }
  596.  
  597.     return 1;
  598. }
  599.  
  600. static int edit_header(void *v, const char *key, const char *val)
  601. {
  602.     edit_do *ed = (edit_do *)v;
  603.  
  604.     apr_table_addn(ed->t, key, process_regexp(ed->hdr, val, ed->p));
  605.     return 1;
  606. }
  607.  
  608. static int add_them_all(void *v, const char *key, const char *val)
  609. {
  610.     apr_table_t *headers = (apr_table_t *)v;
  611.  
  612.     apr_table_addn(headers, key, val);
  613.     return 1;
  614. }
  615.  
  616. static void do_headers_fixup(request_rec *r, apr_table_t *headers,
  617.                              apr_array_header_t *fixup, int early)
  618. {
  619.     echo_do v;
  620.     int i;
  621.     const char *val;
  622.  
  623.     for (i = 0; i < fixup->nelts; ++i) {
  624.         header_entry *hdr = &((header_entry *) (fixup->elts))[i];
  625.         const char *envar = hdr->condition_var;
  626.  
  627.         /* ignore early headers in late calls */
  628.         if (!early && (envar == condition_early)) {
  629.             continue;
  630.         }
  631.         /* ignore late headers in early calls */
  632.         else if (early && (envar != condition_early)) {
  633.             continue;
  634.         }
  635.         /* Have any conditional envar-controlled Header processing to do? */
  636.         else if (envar && !early) {
  637.             if (*envar != '!') {
  638.                 if (apr_table_get(r->subprocess_env, envar) == NULL)
  639.                     continue;
  640.             }
  641.             else {
  642.                 if (apr_table_get(r->subprocess_env, &envar[1]) != NULL)
  643.                     continue;
  644.             }
  645.         }
  646.  
  647.         switch (hdr->action) {
  648.         case hdr_add:
  649.             apr_table_addn(headers, hdr->header, process_tags(hdr, r));
  650.             break;
  651.         case hdr_append:
  652.             apr_table_mergen(headers, hdr->header, process_tags(hdr, r));
  653.             break;
  654.         case hdr_merge:
  655.             val = apr_table_get(headers, hdr->header);
  656.             if (val == NULL) {
  657.                 apr_table_addn(headers, hdr->header, process_tags(hdr, r));
  658.             } else {
  659.                 char *new_val = process_tags(hdr, r);
  660.                 apr_size_t new_val_len = strlen(new_val);
  661.                 int tok_found = 0;
  662.  
  663.                 /* modified version of logic in ap_get_token() */
  664.                 while (*val) {
  665.                     const char *tok_start;
  666.  
  667.                     while (*val && apr_isspace(*val))
  668.                         ++val;
  669.  
  670.                     tok_start = val;
  671.  
  672.                     while (*val && *val != ',') {
  673.                         if (*val++ == '"')
  674.                             while (*val)
  675.                                 if (*val++ == '"')
  676.                                     break;
  677.                     }
  678.  
  679.                     if (new_val_len == (apr_size_t)(val - tok_start)
  680.                         && !strncmp(tok_start, new_val, new_val_len)) {
  681.                         tok_found = 1;
  682.                         break;
  683.                     }
  684.  
  685.                     if (*val)
  686.                         ++val;
  687.                 }
  688.  
  689.                 if (!tok_found) {
  690.                     apr_table_mergen(headers, hdr->header, new_val);
  691.                 }
  692.             }
  693.             break;
  694.         case hdr_set:
  695.             if (!strcasecmp(hdr->header, "Content-Type")) {
  696.                  ap_set_content_type(r, process_tags(hdr, r));
  697.             }
  698.             apr_table_setn(headers, hdr->header, process_tags(hdr, r));
  699.             break;
  700.         case hdr_unset:
  701.             apr_table_unset(headers, hdr->header);
  702.             break;
  703.         case hdr_echo:
  704.             v.r = r;
  705.             v.hdr = hdr;
  706.             apr_table_do((int (*) (void *, const char *, const char *))
  707.                          echo_header, (void *) &v, r->headers_in, NULL);
  708.             break;
  709.         case hdr_edit:
  710.         case hdr_edit_r:
  711.             if (apr_table_get(headers, hdr->header)) {
  712.                 edit_do ed;
  713.  
  714.                 ed.p = r->pool;
  715.                 ed.hdr = hdr;
  716.                 ed.t = apr_table_make(r->pool, 5);
  717.                 apr_table_do(edit_header, (void *) &ed, headers, hdr->header,
  718.                              NULL);
  719.                 apr_table_unset(headers, hdr->header);
  720.                 apr_table_do(add_them_all, (void *) headers, ed.t, NULL);
  721.             }
  722.             break;
  723.         }
  724.     }
  725. }
  726.  
  727. static void ap_headers_insert_output_filter(request_rec *r)
  728. {
  729.     headers_conf *dirconf = ap_get_module_config(r->per_dir_config,
  730.                                                  &headers_module);
  731.  
  732.     if (dirconf->fixup_out->nelts || dirconf->fixup_err->nelts) {
  733.         ap_add_output_filter("FIXUP_HEADERS_OUT", NULL, r, r->connection);
  734.     }
  735. }
  736.  
  737. /*
  738.  * Make sure our error-path filter is in place.
  739.  */
  740. static void ap_headers_insert_error_filter(request_rec *r)
  741. {
  742.     headers_conf *dirconf = ap_get_module_config(r->per_dir_config,
  743.                                                  &headers_module);
  744.  
  745.     if (dirconf->fixup_err->nelts) {
  746.         ap_add_output_filter("FIXUP_HEADERS_ERR", NULL, r, r->connection);
  747.     }
  748. }
  749.  
  750. static apr_status_t ap_headers_output_filter(ap_filter_t *f,
  751.                                              apr_bucket_brigade *in)
  752. {
  753.     headers_conf *dirconf = ap_get_module_config(f->r->per_dir_config,
  754.                                                  &headers_module);
  755.  
  756.     ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, f->r->server,
  757.                  "headers: ap_headers_output_filter()");
  758.  
  759.     /* do the fixup */
  760.     do_headers_fixup(f->r, f->r->err_headers_out, dirconf->fixup_err, 0);
  761.     do_headers_fixup(f->r, f->r->headers_out, dirconf->fixup_out, 0);
  762.  
  763.     /* remove ourselves from the filter chain */
  764.     ap_remove_output_filter(f);
  765.  
  766.     /* send the data up the stack */
  767.     return ap_pass_brigade(f->next,in);
  768. }
  769.  
  770. /*
  771.  * Make sure we propagate any "Header always" settings on the error
  772.  * path through http_protocol.c.
  773.  */
  774. static apr_status_t ap_headers_error_filter(ap_filter_t *f,
  775.                                             apr_bucket_brigade *in)
  776. {
  777.     headers_conf *dirconf;
  778.  
  779.     dirconf = ap_get_module_config(f->r->per_dir_config,
  780.                                     &headers_module);
  781.     ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, f->r->server,
  782.                  "headers: ap_headers_error_filter()");
  783.  
  784.     /*
  785.      * Add any header fields defined by "Header always" to r->err_headers_out.
  786.      * Server-wide first, then per-directory to allow overriding.
  787.      */
  788.     do_headers_fixup(f->r, f->r->err_headers_out, dirconf->fixup_err, 0);
  789.  
  790.     /*
  791.      * We've done our bit; remove ourself from the filter chain so there's
  792.      * no possibility we'll be called again.
  793.      */
  794.     ap_remove_output_filter(f);
  795.  
  796.     /*
  797.      * Pass the buck.  (euro?)
  798.      */
  799.     return ap_pass_brigade(f->next, in);
  800. }
  801.  
  802. static apr_status_t ap_headers_fixup(request_rec *r)
  803. {
  804.     headers_conf *dirconf = ap_get_module_config(r->per_dir_config,
  805.                                                  &headers_module);
  806.  
  807.     /* do the fixup */
  808.     if (dirconf->fixup_in->nelts) {
  809.         do_headers_fixup(r, r->headers_in, dirconf->fixup_in, 0);
  810.     }
  811.  
  812.     return DECLINED;
  813. }
  814. static apr_status_t ap_headers_early(request_rec *r)
  815. {
  816.     headers_conf *dirconf = ap_get_module_config(r->per_dir_config,
  817.                                                  &headers_module);
  818.  
  819.     /* do the fixup */
  820.     if (dirconf->fixup_in->nelts) {
  821.         do_headers_fixup(r, r->headers_in, dirconf->fixup_in, 1);
  822.     }
  823.     if (dirconf->fixup_err->nelts) {
  824.         do_headers_fixup(r, r->err_headers_out, dirconf->fixup_err, 1);
  825.     }
  826.     if (dirconf->fixup_out->nelts) {
  827.         do_headers_fixup(r, r->headers_out, dirconf->fixup_out, 1);
  828.     }
  829.  
  830.     return DECLINED;
  831. }
  832.  
  833. static const command_rec headers_cmds[] =
  834. {
  835.     AP_INIT_RAW_ARGS("Header", header_cmd, &hdr_out, OR_FILEINFO,
  836.                      "an optional condition, an action, header and value "
  837.                      "followed by optional env clause"),
  838.     AP_INIT_RAW_ARGS("RequestHeader", header_cmd, &hdr_in, OR_FILEINFO,
  839.                      "an action, header and value followed by optional env "
  840.                      "clause"),
  841.     {NULL}
  842. };
  843.  
  844. static void register_format_tag_handler(const char *tag,
  845.                                         const void *tag_handler)
  846. {
  847.     apr_hash_set(format_tag_hash, tag, 1, tag_handler);
  848. }
  849.  
  850. static int header_pre_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp)
  851. {
  852.     format_tag_hash = apr_hash_make(p);
  853.     register_format_tag_handler("D", (const void *)header_request_duration);
  854.     register_format_tag_handler("t", (const void *)header_request_time);
  855.     register_format_tag_handler("e", (const void *)header_request_env_var);
  856.     register_format_tag_handler("s", (const void *)header_request_ssl_var);
  857.  
  858.     return OK;
  859. }
  860.  
  861. static int header_post_config(apr_pool_t *pconf, apr_pool_t *plog,
  862.                               apr_pool_t *ptemp, server_rec *s)
  863. {
  864.     header_ssl_lookup = APR_RETRIEVE_OPTIONAL_FN(ssl_var_lookup);
  865.     return OK;
  866. }
  867.  
  868. static void register_hooks(apr_pool_t *p)
  869. {
  870.     ap_register_output_filter("FIXUP_HEADERS_OUT", ap_headers_output_filter,
  871.                               NULL, AP_FTYPE_CONTENT_SET);
  872.     ap_register_output_filter("FIXUP_HEADERS_ERR", ap_headers_error_filter,
  873.                               NULL, AP_FTYPE_CONTENT_SET);
  874.     ap_hook_pre_config(header_pre_config,NULL,NULL,APR_HOOK_MIDDLE);
  875.     ap_hook_post_config(header_post_config,NULL,NULL,APR_HOOK_MIDDLE);
  876.     ap_hook_insert_filter(ap_headers_insert_output_filter, NULL, NULL, APR_HOOK_LAST);
  877.     ap_hook_insert_error_filter(ap_headers_insert_error_filter,
  878.                                 NULL, NULL, APR_HOOK_LAST);
  879.     ap_hook_fixups(ap_headers_fixup, NULL, NULL, APR_HOOK_LAST);
  880.     ap_hook_post_read_request(ap_headers_early, NULL, NULL, APR_HOOK_FIRST);
  881. }
  882.  
  883. module AP_MODULE_DECLARE_DATA headers_module =
  884. {
  885.     STANDARD20_MODULE_STUFF,
  886.     create_headers_dir_config,  /* dir config creater */
  887.     merge_headers_config,       /* dir merger --- default is to override */
  888.     NULL,                       /* server config */
  889.     NULL,                       /* merge server configs */
  890.     headers_cmds,               /* command apr_table_t */
  891.     register_hooks              /* register hooks */
  892. };
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement