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);