You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@httpd.apache.org by Bill Stoddard <bi...@wstoddard.com> on 2001/05/21 20:00:24 UTC

[PATCH] mod_headers

Here is something I've been playing with this AM.  The idea is to handle
config directives that look like this..

Header add MyHeader  "It took %D microseconds to server this request"

Picked up a lot of code from mod_log_config.  This code only handles the %D
option and string literals but it should be easy to add additional %
options. Need to enable conditional processing as well.

Bill

Index: mod_headers.c
===================================================================
RCS file: /home/cvs/httpd-2.0/modules/metadata/mod_headers.c,v
retrieving revision 1.24
diff -u -r1.24 mod_headers.c
--- mod_headers.c 2001/05/20 09:31:04 1.24
+++ mod_headers.c 2001/05/21 17:44:05
@@ -106,9 +106,10 @@
  */

 #include "apr.h"
+#include "apr_lib.h"
 #include "apr_strings.h"
 #include "apr_buckets.h"
-
+#include "apr_hash.h"
 #define APR_WANT_STRFUNC
 #include "apr_want.h"

@@ -118,6 +119,8 @@
 #include "http_log.h"
 #include "util_filter.h"

+static apr_hash_t *header_hash;
+
 typedef enum {
     hdr_add = 'a',              /* add header (could mean multiple hdrs) */
     hdr_set = 's',              /* set (replace old value) */
@@ -131,9 +134,23 @@
 } hdr_inout;

 typedef struct {
+    char* (*func)();
+} header_handler;
+/*
+ * There is an array of "header_item" per Header/RequestHeader config
directive
+ */
+typedef struct {
+    char* (*func)();
+    char *arg;
+} header_item;
+
+/*
+ * There is one "header_entry" per Header/RequestHeader config directive
+ */
+typedef struct {
     hdr_actions action;
     char *header;
-    const char *value;
+    apr_array_header_t *hia;   /* array of header_items */
 } header_entry;

 /*
@@ -147,6 +164,19 @@

 module AP_MODULE_DECLARE_DATA headers_module;

+/*
+ * Formatting functions
+ */
+static const char *constant_item(request_rec *r, char *stuff)
+{
+    return stuff;
+}
+static const char *header_request_duration(request_rec *r, char *a)
+{
+    return apr_psprintf(r->pool, "%qd", (apr_time_now() -
r->request_time));
+}
+
+
 static void *create_headers_config(apr_pool_t *p, server_rec *s)
 {
     headers_conf *conf = apr_pcalloc(p, sizeof(*conf));
@@ -174,7 +204,163 @@
     return newconf;
 }

+static char *parse_misc_string(apr_pool_t *p, header_item *hi, const char
**sa)
+{
+    const char *s;
+    char *d;
+
+    hi->func = constant_item;
+//    it->conditions = NULL;
+
+    s = *sa;
+    while (*s && *s != '%') {
+ s++;
+    }
+    /*
+     * This might allocate a few chars extra if there's a backslash
+     * escape in the format string.
+     */
+    hi->arg = apr_palloc(p, s - *sa + 1);
+
+    d = hi->arg;
+    s = *sa;
+    while (*s && *s != '%') {
+ if (*s != '\\') {
+     *d++ = *s++;
+ }
+ else {
+     s++;
+     switch (*s) {
+     case '\\':
+  *d++ = '\\';
+  s++;
+  break;
+     case 'r':
+  *d++ = '\r';
+  s++;
+  break;
+     case 'n':
+  *d++ = '\n';
+  s++;
+  break;
+     case 't':
+  *d++ = '\t';
+  s++;
+  break;
+     default:
+  /* copy verbatim */
+  *d++ = '\\';
+  /*
+   * Allow the loop to deal with this *s in the normal
+   * fashion so that it handles end of string etc.
+   * properly.
+   */
+  break;
+     }
+ }
+    }
+    *d = '\0';
+
+    *sa = s;
+    return NULL;
+}
+
+static char *parse_header_item(apr_pool_t *p, header_item *hi, const char
**sa)
+{ 
+    const char *s = *sa;
+    header_handler *handler;
+
+    /* Handle string literal/conditionals */
+    if (*s != '%') {
+        return parse_misc_string(p, hi, sa);
+    }
+
+    s++; /* skip the % */
+
+    while (*s) {
+        int i;
+        switch (*s) {
+        case '!':
+            ++s;
+//            it->condition_sense = !it->condition_sense;
+            break;
+
+        case '<':
+            ++s;
+//            it->want_orig = 1;
+            break;
+
+        case '>':
+            ++s;
+//            it->want_orig = 0;
+            break;
 
+        case ',':
+            ++s;
+            bre
ak;
+
+        case '{':
+            ++s;
+            hi->arg = ap_getword(p, &s, '}');
+            break;
+
+        case '0':
+        case '1':
+        case '2':
+        case '3':
+        case '4':
+        case '5':
+        case '6':
+        case '7':
+        case '8':
+        case '9':
+            i = *s - '0';
+            while (apr_isdigit(*++s)) {
+                i = i * 10 + (*s) - '0';
+            }
+//            if (!it->conditions) {
+//                it->conditions = apr_array_make(p, 4, sizeof(int));
+//            }
+//            *(int *) apr_array_push(it->conditions) = i;
+            break;
+
+        default:
+            handler = (header_handler *)apr_hash_get(header_hash, s++, 1);
+            if (!handler) {
+                char dummy[2];
+
+                dummy[0] = s[-1];
+                dummy[1] = '\0';
+                return apr_pstrcat(p, "Unrecognized Header or RequestHeader
directive %",
+                                   dummy, NULL);
+            }
+            hi->func = handler->func;
+//            if (it->want_orig == -1) {
+//                it->want_orig = handler->want_orig_default;
+//            }
+            *sa = s;
+            hi->arg = '\0';
+            return NULL;
+        }
+    }
+}
+/*
+ * Build the array of header_items to hang off the header_entry
+ */
+static char *parse_header_string(apr_pool_t *p, header_entry *hdr, const
char *s)
+{
+    char *res;
+    hdr->hia = apr_array_make(p, 30, sizeof(header_item));
+
+    while (*s) {
+        if ((res = parse_header_item(p, (header_item *)
apr_array_push(hdr->hia), &s))) {
+            return res;
+        }
+    }
+
+    return NULL;
+}
+
 /* handle RequestHeader and Header directive */
 static const char *header_inout_cmd(hdr_inout inout, cmd_parms *cmd, void
*indirconf,
                               const char *action, const char *inhdr,
@@ -217,9 +403,11 @@
         *colon = '\0';

     new->header = hdr;
-    new->value = value;

-    return NULL;
+    /* Parse header string value
+     * Should init a function pointer
+     */
+    return parse_header_string(cmd->pool, new, value);
 }

 /* handle Header directive */
@@ -238,9 +426,28 @@
     return header_inout_cmd(hdr_in, cmd, indirconf, action, inhdr, value);
 }

+/*
+ * Run the header formatters and return the response as a
+ * concatenated string
+ */
+static char* process_items(header_entry *hdr, request_rec *r)
+{
+    int i;
+    char *s;
+    char *str = NULL;
+
+    header_item *hi = (header_item*) hdr->hia->elts;

-static void do_headers_fixup(apr_table_t *headers,
-                             apr_array_header_t *fixup)
+    for (i = 0; i < hdr->hia->nelts; i++) {
+        s = hi[i].func(r, hi[i].arg);
+        if (str == NULL)
+            str = s;
+        else
+            str = apr_pstrcat(r->pool, str, s, NULL);
+    }
+    return str;
+}
+static void do_headers_fixup(apr_table_t *headers, apr_array_header_t
*fixup, request_rec *r)
 {
     int i;

@@ -248,13 +455,13 @@
         header_entry *hdr = &((header_entry *) (fixup->elts))[i];
         switch (hdr->action) {
         case hdr_add:
-            apr_table_addn(headers, hdr->header, hdr->value);
+            apr_table_addn(headers, hdr->header, process_items(hdr, r));
             break;
         case hdr_append:
-            apr_table_mergen(headers, hdr->header, hdr->value);
+            apr_table_mergen(headers, hdr->header, process_items(hdr, r));
             break;
         case hdr_set:
-            apr_table_setn(headers, hdr->header, hdr->value);
+            apr_table_setn(headers, hdr->header, process_items(hdr, r));
             break;
         case hdr_unset:
             apr_table_unset(headers, hdr->header);
@@ -287,8 +494,8 @@
    "headers: ap_headers_output_filter()");

     /* do the fixup */
-    do_headers_fixup(f->r->headers_out, serverconf->fixup_out);
-    do_headers_fixup(f->r->headers_out, dirconf->fixup_out);
+    do_headers_fixup(f->r->headers_out, serverconf->fixup_out, f->r);
+    do_headers_fixup(f->r->headers_out, dirconf->fixup_out, f->r);

     /* remove ourselves from the filter chain */
     ap_remove_output_filter(f);
@@ -306,8 +513,8 @@

     /* do the fixup */
     if (serverconf->fixup_in->nelts || dirconf->fixup_in->nelts) {
-        do_headers_fixup(r->headers_in, serverconf->fixup_in);
-        do_headers_fixup(r->headers_in, dirconf->fixup_in);
+        do_headers_fixup(r->headers_in, serverconf->fixup_in, r);
+        do_headers_fixup(r->headers_in, dirconf->fixup_in, r);
     }

     return DECLINED;
@@ -321,9 +528,52 @@
                    "an action, header and value"),
     {NULL}
 };
+static void register_header_handler(apr_pool_t *p, char *tag, void
*handler, int def)
+{
+    header_handler *h = apr_palloc(p, sizeof(*h));
+    h->func = handler;
+
+    apr_hash_set(header_hash, tag, 1, (const void *)h);
+}
+static void header_pre_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t
*ptemp)
+{
+    header_hash = apr_hash_make(p);
+    register_header_handler(p, "D", (void*) header_request_duration, 0);
+
+}

 static void register_hooks(apr_pool_t *p)
 {
+    ap_hook_pre_config(header_pre_config,NULL,NULL,APR_HOOK_MIDDLE);
     ap_hook_insert_filter(ap_headers_insert_output_filter, NULL, NULL,
APR_HOOK_LAST);
     ap_hook_fixups(ap_headers_fixup, NULL, NULL, APR_HOOK_LAST);
     ap_register_output_filter("FIXUP_HEADERS_OUT",
ap_headers_output_filter, AP_FTYPE_CONTENT);