Hi,

Chuck Murcko forwarded my message about a patch to add Header
set/unset/add/append and Expires/Cache-Control directives yesterday
(thanks, Chuck). I thought that I should follow up with a short
explanation of the rationale for this functionality.

But first, since this is my initial post to this list, I want to say
thank you to everyone here. Mod_proxy is such a nice thing to have as
part of Apache, and I am tremendously impressed by all the development
work going into the 2.0 rewrite (I read through the list archives,
last night.) We depend on mod_proxy as a caching front-end to our
public web servers (http://allafrica.com -- we distribute news and
information from 85 or so African publishers). We serve about 300,000
dynamically-built pages a day (50 request/second at peak times,
including image files) using just a couple of dual-processor Linux
boxen, one for mod_perl and one for mod_proxy!

As our traffic has expanded, we've tried to offload more and more of
the work onto the mod_proxy box. We needed to do two things that
mod_proxy didn't support: 1) send some "connection" information to the
mod_perl backend based on request host/uri, 2) fine-tune mod_proxy
caching, so that the "public" information about expiration times of
documents could differ from the "private" caching information that
mod_proxy uses.

1) involved adding a directive:

 ProxyRequestHeader [set|unset|add|append] Header [value] [match-pattern]

This directive allows the manipulation of a header, with an optional
pattern to match against the request uri controlling application of
the directive. A simple example of use would be:

 <VirtualHost 0.0.0.0>
 ServerName          en.allafrica.com
 ProxyRequestHeader  set  Req-Language  "en"
 </VirtualHost>

While I was in the code, I also added a symmetrical directive applying
to responses rather than requests:

 ProxyResponseHeader [set|unset|add|append] Header [value] [pattern]

This works exactly the same way. We don't use it, yet, in our
production code, but I've been playing with it as a way to quickly set
headers that give hints to some of our commercial, non-browser clients
doing feed-retrieval via HTTP (we do bulk commercial feeds for
Lexis-Nexis, Comtex, ISyndicate, etc.).

2) involved a pair of directives:

 ProxyResponseExpiresVector [seconds] [match-pattern]
 CacheFreshenDate           On|Off    [match-pattern]

We wanted to try to spread out some of the requests for pages that,
perhaps because of downstream caching, were clumping together. We also
needed to be able to cache documents inside mod_proxy, but discourage
caching downstream, for some parts of our site (because we are
contractually obligated to attempt to provide "more accurate" usage
logging). An Example of these directives in use:

 
 CacheFreshenDate            On        "^/publishers/dailynation"
 # daily-nation index page expires immediately
 ProxyResponseExpiresVector  0         "^/publishers/dailynation/$"
 # rest of daily-nation pages ttl 30 seconds
 ProxyResponseExpiresVector  30        "^/publishers/dailynation"

--

I would like to know whether this functionality would be useful to
other folks using mod_proxy, and what I can do to make it more
useful. An obvious way to increase the power of the
header-manipulation directives would be to allow some dynamic
substitutions (variables ala mod_rewrite, or something similar). Ian
has mentioned a notes-table interface, as well, which is an
interesting idea.

I've put the patches up at: 

http://allafrica.com/tools/apache/mod_proxy/

as well as appending them, here. And my "rolled-in" documentation is
here:

http://allafrica.com/tools/apache/mod_proxy/mod_proxy.html#cachefreshendate

--

Thanks,
Kwindla

diff -u apache_1.3.19/src/modules/proxy/mod_proxy.c 
apache_1.3.19-mod/src/modules/proxy/mod_proxy.c
--- apache_1.3.19/src/modules/proxy/mod_proxy.c Mon Jan 15 12:05:27 2001
+++ apache_1.3.19-mod/src/modules/proxy/mod_proxy.c     Wed May  2 15:23:04 2001
@@ -443,9 +443,15 @@
     ps->cache.cache_completion = DEFAULT_CACHE_COMPLETION;
     ps->cache.cache_completion_set = 0;
 
+    ps->freshen_date = ap_make_array(p, 10, sizeof(hdr_actions_entry));
+    ps->resp_exp_vector = ap_make_array(p, 10, sizeof(resp_exp_vector_entry));
+    ps->req_headers = ap_make_array(p, 10, sizeof(hdr_actions_entry));
+    ps->resp_headers = ap_make_array(p, 10, sizeof(hdr_actions_entry));
+
     return ps;
 }
 
+
 static void *
      merge_proxy_config(pool *p, void *basev,
                         void *overridesv)
@@ -477,6 +483,18 @@
     ps->cache.dirlevels = (overrides->cache.dirlevels_set == 0) ? 
base->cache.dirlevels : overrides->cache.dirlevels;
     ps->cache.dirlength = (overrides->cache.dirlength_set == 0) ? 
base->cache.dirlength : overrides->cache.dirlength;
     ps->cache.cache_completion = (overrides->cache.cache_completion_set == 0) 
? base->cache.cache_completion : overrides->cache.cache_completion;
+    /* put freshen_date and resp_exp_vector from the overriding config
+       in front of the base config arrays, the semantics being that
+       virtual server configs should be checked first */
+    ps->freshen_date = 
ap_append_arrays(p,overrides->freshen_date,base->freshen_date);
+    ps->resp_exp_vector = 
ap_append_arrays(p,overrides->resp_exp_vector,base->resp_exp_vector);
+    /* add req_ and resp_headers from the overriding config after
+       those from the base config arrays, the semantics being that the
+       directives are applied in declaration order, with those
+       specific to a virtual server coming after and therefore
+       overriding those from the root config */
+    ps->req_headers = 
ap_append_arrays(p,base->req_headers,overrides->req_headers);
+    ps->resp_headers = 
ap_append_arrays(p,base->resp_headers,overrides->resp_headers);
 
     return ps;
 }
@@ -883,6 +901,120 @@
     return NULL;    
 }
 
+static const char* 
+    set_freshen_date(cmd_parms *parms, void *mconfig, char *one, char *two) 
+{
+    proxy_server_conf *psf =
+      ap_get_module_config(parms->server->module_config, &proxy_module);
+    hdr_actions_entry *f = 
+      (hdr_actions_entry *)ap_push_array(psf->freshen_date);
+    /* set action */
+    if (strcasecmp(one, "Off") == 0)
+      f->action = hdr_off;
+    else if (strcasecmp(one, "On") == 0)
+      f->action = hdr_on;
+    else 
+      return "CacheFreshenDate must be either On or Off";
+    /* set pattern (null is okay, will be dealt with at match time) */
+    if (two) {
+      f->pattern = ap_pregcomp(parms->pool,two,REG_EXTENDED|REG_NOSUB);
+      if (f->pattern == NULL)
+        return ap_psprintf
+          (parms->pool,"Regular expression could not be compiled: %s", two);
+    } else {
+      f->pattern = NULL;
+    }
+    return NULL;
+}
+
+static const char* 
+    set_resp_exp_vector(cmd_parms *parms, void *mconfig, char *one, char *two) 
+{
+    proxy_server_conf *psf =
+      ap_get_module_config(parms->server->module_config, &proxy_module);
+    resp_exp_vector_entry *rev = 
+      (resp_exp_vector_entry *)ap_push_array(psf->resp_exp_vector);
+    int i = atoi(one);
+    /* set seconds number */
+    if (i < -1)
+      return "ProxyResponseExpiresVector must be a number of seconds (0 for 
\"immediately), or -1 to explicitly disable\"";
+    rev->vector = i;
+    /* set pattern (again, null is okay) */
+    if (two) {
+      rev->pattern = ap_pregcomp(parms->pool,two,REG_EXTENDED|REG_NOSUB);
+      if (rev->pattern == NULL)
+        return ap_psprintf
+          (parms->pool,"Regular expression could not be compiled: %s", two);
+    } else {
+      rev->pattern = NULL;
+    }
+    return NULL;
+}
+
+static const char*
+    set_header_directive(cmd_parms *parms, void *mconfig, const char *args)
+{
+  char *one = ap_getword_conf(parms->pool,&args); 
+  char *two = ap_getword_conf(parms->pool,&args); 
+  char *three = ap_getword_conf(parms->pool,&args); 
+  char *four = ap_getword_conf(parms->pool,&args); 
+  proxy_server_conf *psf =
+    ap_get_module_config(parms->server->module_config, &proxy_module);
+  hdr_actions_entry *h;
+  /* push onto the correct array */
+  if (strcmp("ProxyRequestHeader",(char*)parms->info) == 0)
+    h = (hdr_actions_entry *)ap_push_array(psf->req_headers);
+  else
+    h = (hdr_actions_entry *)ap_push_array(psf->resp_headers);
+  /* set action */
+  if (strcasecmp(one,"set") == 0)
+    h->action = hdr_set;
+  else if (strcasecmp(one,"unset") == 0)
+    h->action = hdr_unset;
+  else if (strcasecmp(one,"add") == 0)
+    h->action = hdr_add;
+  else if (strcasecmp(one,"append") == 0)
+    h->action = hdr_append;
+  else 
+    return ap_psprintf
+      (parms->pool, "Argument to %s must be one of set | unset | add | append",
+       (char*)parms->info);
+  /* set which header */
+  h->header = ap_pstrdup(parms->pool,two);
+  /* unset only takes 2/3 arguments -- so set its pattern and return */
+  if (h->action == hdr_unset) {
+    if (strcmp(three,"")!=0) {
+        h->pattern = ap_pregcomp(parms->pool,three,REG_EXTENDED|REG_NOSUB);
+        if (h->pattern == NULL)
+          return ap_psprintf
+            (parms->pool,"Regular expression could not be compiled: %s", 
three);
+    } else {
+      h->pattern = NULL;
+    }
+    if (!strcmp(four,"")==0)
+      return ap_psprintf
+        (parms->pool,"%s 'unset' only takes two or three arguments", 
+         (char*)parms->info);
+    return NULL;
+  }
+  /* set value string */
+  if (strcmp(three,"")==0)
+    return ap_psprintf
+      (parms->pool,"%s requires at least three arguments", (char*)parms->info);
+  h->value = ap_pstrdup(parms->pool,three);
+  /* set pattern */
+  if (strcmp(four,"")!=0) {
+    h->pattern = ap_pregcomp(parms->pool,four,REG_EXTENDED|REG_NOSUB);
+    if (h->pattern == NULL)
+      return ap_psprintf
+        (parms->pool,"Regular expression could not be compiled: %s", four);
+  } else {
+    h->pattern = NULL;
+  }
+
+  return NULL;
+}
+
 static const handler_rec proxy_handlers[] =
 {
     {"proxy-server", proxy_handler},
@@ -931,6 +1063,16 @@
      "Force a http cache completion after this percentage is loaded"},
     {"ProxyVia", set_via_opt, NULL, RSRC_CONF, TAKE1,
      "Configure Via: proxy header header to one of: on | off | block | full"},
+    {"CacheFreshenDate", set_freshen_date, NULL, RSRC_CONF, TAKE12,
+     "Whether to update the Date header when returning cached proxy 
responses"},
+    {"ProxyResponseExpiresVector", set_resp_exp_vector, NULL, RSRC_CONF, 
TAKE12,
+     "A constant to add to current time for expires headers on proxy 
response"},
+    {"ProxyRequestHeader", set_header_directive, (void*)"ProxyRequestHeader", 
+     RSRC_CONF,RAW_ARGS, 
+     "A directive for headers to be sent with proxy requests"},
+    {"ProxyResponseHeader", set_header_directive, 
(void*)"ProxyResponseHeader", 
+     RSRC_CONF,RAW_ARGS, 
+     "A directive for headers that are returned with responses"},
     {NULL}
 };
 
diff -u apache_1.3.19/src/modules/proxy/mod_proxy.h 
apache_1.3.19-mod/src/modules/proxy/mod_proxy.h
--- apache_1.3.19/src/modules/proxy/mod_proxy.h Mon Jan 15 12:05:28 2001
+++ apache_1.3.19-mod/src/modules/proxy/mod_proxy.h     Tue May  1 19:27:49 2001
@@ -120,6 +120,7 @@
     enc_path, enc_search, enc_user, enc_fpath, enc_parm
 };
 
+
 #define HDR_APP (0)            /* append header, for proxy_add_header() */
 #define HDR_REP (1)            /* replace header, for proxy_add_header() */
 
@@ -177,6 +178,25 @@
     struct in_addr addr;
 };
 
+
+/* for configurable headers */
+typedef enum { 
+  hdr_on, hdr_off, hdr_set, hdr_unset, hdr_add, hdr_append 
+} hdr_actions;
+
+typedef struct {
+  hdr_actions action;
+  char       *header;
+  char       *value;
+  regex_t    *pattern;
+} hdr_actions_entry;
+
+typedef struct {
+  int         vector;
+  regex_t    *pattern;
+} resp_exp_vector_entry;
+
+  
 #define DEFAULT_CACHE_SPACE 5
 #define DEFAULT_CACHE_MAXEXPIRE SEC_ONE_DAY
 #define DEFAULT_CACHE_EXPIRE    SEC_ONE_HR
@@ -226,6 +246,10 @@
     char viaopt_set;
     size_t recv_buffer_size;
     char recv_buffer_size_set;
+    array_header *freshen_date;
+    array_header *resp_exp_vector;
+    array_header *req_headers;
+    array_header *resp_headers;
 } proxy_server_conf;
 
 struct hdr_entry {
@@ -307,6 +331,10 @@
 table *ap_proxy_read_headers(request_rec *r, char *buffer, int size, BUFF *f);
 long int ap_proxy_send_fb(BUFF *f, request_rec *r, cache_req *c);
 void ap_proxy_send_headers(request_rec *r, const char *respline, table *hdrs);
+void ap_proxy_freshen_date(request_rec *r, proxy_server_conf *psf, table* t);
+void ap_proxy_vectored_exp(request_rec *r, proxy_server_conf *psf, table* t);
+void ap_proxy_header_fixup(request_rec *r, proxy_server_conf *psf, table* t,
+                           array_header *directives);
 int ap_proxy_liststr(const char *list, const char *val);
 void ap_proxy_hash(const char *it, char *val, int ndepth, int nlength);
 int ap_proxy_hex2sec(const char *x);
diff -u apache_1.3.19/src/modules/proxy/proxy_http.c 
apache_1.3.19-mod/src/modules/proxy/proxy_http.c
--- apache_1.3.19/src/modules/proxy/proxy_http.c        Fri Feb  9 07:40:27 2001
+++ apache_1.3.19-mod/src/modules/proxy/proxy_http.c    Wed May  2 11:56:14 2001
@@ -315,6 +315,9 @@
     else
        ap_bvputs(f, "Host: ", desthost, CRLF, NULL);
 
+    /* run fixup for the request header directives */
+    ap_proxy_header_fixup(r,conf,r->headers_in,conf->req_headers);
+
     if (conf->viaopt == via_block) {
        /* Block all outgoing Via: headers */
        ap_table_unset(r->headers_in, "Via");
@@ -502,6 +505,19 @@
            c = ap_proxy_cache_error(c);
     }
 
+
+
+/* Set extra response headers. We can set whatever we want here
+   (including Expires and family) because ap_proxy_cache_update has
+   alread set the hex header line for the cache file. But the rest of
+   the cache file, including the HTTP headers, will include whatever
+   we put here. This is good, in general, but it does mean we have to
+   adjust any running-vector Expires headers in the
+   ap_proxy_send_headers, so even cached files get nice clean headers
+   with times set correctly in the future.*/
+    ap_proxy_vectored_exp(r,conf,resp_hdrs);
+    ap_proxy_header_fixup(r,conf,resp_hdrs,conf->resp_headers);
+
 /* send headers */
     tdo.req = r;
     tdo.cache = c;
@@ -552,3 +568,9 @@
     ap_proxy_garbage_coll(r);
     return OK;
 }
+
+
+
+
+
+
diff -u apache_1.3.19/src/modules/proxy/proxy_util.c 
apache_1.3.19-mod/src/modules/proxy/proxy_util.c
--- apache_1.3.19/src/modules/proxy/proxy_util.c        Wed Feb  7 08:09:59 2001
+++ apache_1.3.19-mod/src/modules/proxy/proxy_util.c    Wed May  2 15:36:56 2001
@@ -633,8 +633,15 @@
 {
     int i;
     BUFF *fp = r->connection->client;
-    table_entry *elts = (table_entry *) ap_table_elts(t)->elts;
+    table_entry *elts;
 
+    proxy_server_conf *psf = (proxy_server_conf *)
+  ap_get_module_config(r->server->module_config,&proxy_module);
+   
+    ap_proxy_freshen_date(r,psf,t);
+    ap_proxy_vectored_exp(r,psf,t);
+
+    elts = (table_entry *) ap_table_elts(t)->elts;
     ap_bvputs(fp, respline, CRLF, NULL);
 
     for (i = 0; i < ap_table_elts(t)->nelts; ++i) {
@@ -647,6 +654,77 @@
     ap_bputs(CRLF, fp);
 }
 
+void ap_proxy_freshen_date(request_rec *r, proxy_server_conf *psf, table* t)
+{
+  int i;
+  hdr_actions_entry *list = (hdr_actions_entry*)psf->freshen_date->elts;
+  for(i=0; i < psf->freshen_date->nelts; i++) {
+    if(((list+i)->pattern == NULL) || 
+       (regexec((list+i)->pattern,r->uri,0,NULL,0) != REG_NOMATCH)) {
+      if ((list+i)->action == hdr_on) {
+        ap_table_set(t, "Date", 
+                     ap_ht_time(r->pool, time(NULL), "%a %d %b %Y %T %Z", 1));
+      }
+      return;
+    }
+  }
+}
+
+/* see whether there are ProxyVectoredExpire directives to apply to
+   this request. (Don't do anything unless there is already an Expires
+   header here.) */
+void ap_proxy_vectored_exp(request_rec *r, proxy_server_conf *psf, table* t)
+{
+  int i;
+  resp_exp_vector_entry *list;
+  /* don't do anything to a doc that doesn't *already* have an Expires */
+  if (! ap_table_get(t,"Expires")) return;
+  /* okay, loop through directives */
+  list = (resp_exp_vector_entry*)psf->resp_exp_vector->elts;
+  for(i=0; i < psf->resp_exp_vector->nelts; i++) {
+    if(((list+i)->pattern == NULL) ||
+       (regexec((list+i)->pattern,r->uri,0,NULL,0) != REG_NOMATCH)) {
+      if ((list+i)->vector == -1) {
+      } else if ((list+i)->vector == 0) {
+        ap_table_setn(t, "Expires", "0");
+        ap_table_setn(t, "Cache-Control", "max-age=0");
+      } else {
+        ap_table_set(t, "Expires", 
+                     ap_ht_time(r->pool, time(NULL)+(list+i)->vector, 
+                                "%a %d %b %Y %T %Z", 1));
+        ap_table_set(t, "Cache-Control", 
+                     ap_psprintf(r->pool,"max-age=%d",(list+i)->vector)); 
+      }
+      return;
+    }
+  }
+}
+
+void ap_proxy_header_fixup(request_rec *r, proxy_server_conf *psf,
+                           table *t, array_header *directives)
+{
+  int i;
+  hdr_actions_entry *list = (hdr_actions_entry *)directives->elts;
+  for (i=0; i < directives->nelts; i++) {
+    if(((list+i)->pattern == NULL) ||
+       (regexec((list+i)->pattern,r->uri,0,NULL,0) != REG_NOMATCH)) {
+      switch ((list+i)->action) {
+      case hdr_set:
+        ap_table_setn(t,(list+i)->header,(list+i)->value);
+        break;
+      case hdr_unset:
+        ap_table_unset(t,(list+i)->header);
+        break;
+      case hdr_add:
+        ap_table_addn(t,(list+i)->header,(list+i)->value);
+        break;
+      case hdr_append:
+        ap_table_mergen(t,(list+i)->header,(list+i)->value);
+        break;
+      }
+    }
+  }
+}
 
 /*
  * list is a comma-separated list of case-insensitive tokens, with
--- apache_1.3.19/htdocs/manual/mod/mod_proxy.html      Mon Feb 26 12:18:51 2001
+++ apache_1.3.19-mod/htdocs/manual/mod/mod_proxy.html  Wed May  2 15:39:24 2001
@@ -82,6 +82,11 @@
 <LI><A HREF="#cachedirlength">CacheDirLength</A>
 <LI><A HREF="#cacheforcecompletion">CacheForceCompletion</A>
 <LI><A HREF="#nocache">NoCache</A>
+<LI><A HREF="#cachefreshendate">CacheFreshenDate</A>
+<LI><A HREF="#proxyresponseexpiresvector">ProxyResponseExpiresVector</A>
+<LI><A HREF="#proxyrequestheader">ProxyRequestHeader</A>
+<LI><A HREF="#proxyresponseheader">ProxyResponseHeader</A>
+
 </UL>
 
 <H2><A NAME="configs">Common configuration topics</A></H2>
@@ -1179,6 +1184,285 @@
 
 <HR>
 
+
+
+
+
+
+
+
+
+
+<H2><A NAME="cachefreshendate">CacheFreshenDate</A> directive</H2>
+<A
+ HREF="directive-dict.html#Syntax"
+ REL="Help"
+><STRONG>Syntax:</STRONG></A> CacheFreshenDate
+                              <EM>On|Off [match-pattern]</EM><BR>
+<A
+ HREF="directive-dict.html#Default"
+ REL="Help"
+><STRONG>Default:</STRONG></A> <EM>Off</EM><BR>
+<A
+ HREF="directive-dict.html#Context"
+ REL="Help"
+><STRONG>Context:</STRONG></A> server config, virtual host<BR>
+<A
+ HREF="directive-dict.html#Override"
+ REL="Help"
+><STRONG>Override:</STRONG></A> <EM>Not applicable</EM><BR>
+<A
+ HREF="directive-dict.html#Status"
+ REL="Help"
+><STRONG>Status:</STRONG></A> Experimental<BR>
+<A
+ HREF="directive-dict.html#Module"
+ REL="Help"
+><STRONG>Module:</STRONG></A> mod_proxy<BR>
+<A
+ HREF="directive-dict.html#Compatibility"
+ REL="Help"
+><STRONG>Compatibility:</STRONG></A> Patch, available from 
http://allafrica.com/tools/apache/mod_proxy/<P>
+
+<P>The CacheFreshenDate directive indicates that mod_proxy should
+update the <STRONG>Date:</STRONG> header on documents that are
+returned from the cache. CacheFreshenDate takes two arguments, an
+<EM>On</EM>/<EM>Off</EM> flag and an optional
+<EM>match-pattern</EM>. If the match-pattern is present, the directive
+only takes effect if the request uri matches the pattern.</P>
+
+<P>CacheFreshenDate directives can appear in server and virtual server
+configuration sections. For each request, the directives are processed
+in declaration order (with virtual server directives processed before
+base configuration directives). When a match, or a directive with no
+pattern, is found, processing stops.</P>
+
+<PRE>
+  CacheFreshenDate  On  "^/stories"
+  CacheFreshenDate  Off 
+</PRE>
+
+<HR>
+
+
+
+
+
+
+<H2><A NAME="proxyresponseexpiresvector">ProxyResponseExpiresVector</A> 
directive</H2>
+<A
+ HREF="directive-dict.html#Syntax"
+ REL="Help"
+><STRONG>Syntax:</STRONG></A> ProxyResponseExpiresVector
+                              <EM>seconds [match-pattern]</EM><BR>
+<A
+ HREF="directive-dict.html#Default"
+ REL="Help"
+><STRONG>Default:</STRONG></A> <EM>Off</EM><BR>
+<A
+ HREF="directive-dict.html#Context"
+ REL="Help"
+><STRONG>Context:</STRONG></A> server config, virtual host<BR>
+<A
+ HREF="directive-dict.html#Override"
+ REL="Help"
+><STRONG>Override:</STRONG></A> <EM>Not applicable</EM><BR>
+<A
+ HREF="directive-dict.html#Status"
+ REL="Help"
+><STRONG>Status:</STRONG></A> Experimental<BR>
+<A
+ HREF="directive-dict.html#Module"
+ REL="Help"
+><STRONG>Module:</STRONG></A> mod_proxy<BR>
+<A
+ HREF="directive-dict.html#Compatibility"
+ REL="Help"
+><STRONG>Compatibility:</STRONG></A> Patch, available from 
http://allafrica.com/tools/apache/mod_proxy/<P>
+
+<P> The ProxyResponseExpiresVector directive decouples the caching
+headers of proxy responses from the caching headers received by
+upstream servers. The directive indicates that mod_proxy should alter
+the <STRONG>Expires:</STRONG> and <STRONG>Cache-Control:
+max-age=</STRONG> headers on documents that it
+returns. ProxyResponseExpiresVector takes two arguments, the number of
+<EM>seconds</EM> in the future that expiry should be set to, and an
+optional <EM>match-pattern</EM>. If the match-pattern is present, the
+directive only takes effect if the request uri matches the
+pattern.</P>
+
+<P> ProxyResponseExpiresVector directives can appear in server and
+virtual server configuration sections. For each request, the
+directives are processed in declaration order (with virtual server
+directives processed before base configuration directives). When a
+match, or a directive with no pattern, is found, processing stops.</P>
+
+<P> The expiration times indicated do not effect mod_proxy's internal
+caching -- mod_proxy bases its own behavior on the headers received
+from upstream servers. Downstream clients can therefore be given
+longer or shorter expiration indicators than mod_proxy itself
+uses. Additionally, only documents that already have an
+<STRONG>Expires</STRONG> header are modified, so that non-cacheable
+documents are not effected.</P>
+
+<P> The <EM>seconds</EM> argument should be set to <STRONG>0</STRONG> to
+indicate immediate expiration, or <STRONG>-1</STRONG> to explicitly
+disable the header manipulation.</P>
+
+<PRE>
+  # don't change expiry for images
+  ProxyResponseExpiresVector  -1  "^/img"
+  # long expiration for archive
+  ProxyResponseExpiresVector  86400 "^/archive"
+  # 10-minute default expiration
+  ProxyResponseExpiresVector  600
+</PRE>
+
+<P> Note that <A HREF="#cachefreshendate">CacheFreshenDate</A> is
+useful in conjunction with ProxyResponseExpiresVector</P>
+
+<HR>
+
+
+
+
+
+
+
+<H2><A NAME="proxyrequestheader">ProxyRequestHeader</A> directive</H2>
+<A
+ HREF="directive-dict.html#Syntax"
+ REL="Help"
+><STRONG>Syntax:</STRONG></A> ProxyRequestHeader
+                              <EM>set | unset | add | append
+                                  header
+                                  [string]
+                                  [match-pattern]</EM><BR>
+<A
+ HREF="directive-dict.html#Default"
+ REL="Help"
+><STRONG>Default:</STRONG></A> <EM>Off</EM><BR>
+<A
+ HREF="directive-dict.html#Context"
+ REL="Help"
+><STRONG>Context:</STRONG></A> server config, virtual host<BR>
+<A
+ HREF="directive-dict.html#Override"
+ REL="Help"
+><STRONG>Override:</STRONG></A> <EM>Not applicable</EM><BR>
+<A
+ HREF="directive-dict.html#Status"
+ REL="Help"
+><STRONG>Status:</STRONG></A> Experimental<BR>
+<A
+ HREF="directive-dict.html#Module"
+ REL="Help"
+><STRONG>Module:</STRONG></A> mod_proxy<BR>
+<A
+ HREF="directive-dict.html#Compatibility"
+ REL="Help"
+><STRONG>Compatibility:</STRONG></A> Patch, available from 
http://allafrica.com/tools/apache/mod_proxy/<P>
+
+<P> The ProxyRequestHeader sets headers on upstream requests. The
+first argument, one of <EM>set | unset | add | append</EM>, indicates
+the action to be taken for the second argument, the
+<EM>header</EM>. (The trailing colon should <STRONG>not</STRONG> be
+included in the header argument.) The third argument is the
+<EM>string</EM> that should be used for a set, add or append action
+(for an unset, the string argument should be ommitted.)</P> The
+optional fourth argument, <EM>match-pattern</EM>, controls the
+application of the directive. If a match-pattern is present, the
+request uri must match the pattern for the directive to be
+applied.</P>
+
+<P> ProxyRequestHeader directives can appear in server and virtual
+server configuration sections. For each request, the directives are
+processed in declaration order -- base server directives processed
+first. For each match found, the specified action is taken.</P>
+
+<PRE>
+  ProxyRequestHeader      set      Language         "unknown"
+  ProxyRequestHeader      append   Passed-Through   this.host
+  &lt;VirtualHost english.stuff.org&gt;
+    ProxyRequestHeader    set      Language         "en"
+    ProxyRequestHeader    set      Root-Request     "yes"    "^/$"
+  &lt;VirtualHost english.stuff.org&gt;
+</PRE>
+
+<HR>
+
+
+
+
+
+
+<H2><A NAME="proxyresponseheader">ProxyResponseHeader</A> directive</H2>
+<A
+ HREF="directive-dict.html#Syntax"
+ REL="Help"
+><STRONG>Syntax:</STRONG></A> ProxyResponseHeader
+                              <EM>set | unset | add | append
+                                  header
+                                  [string]
+                                  [match-pattern]</EM><BR>
+<A
+ HREF="directive-dict.html#Default"
+ REL="Help"
+><STRONG>Default:</STRONG></A> <EM>Off</EM><BR>
+<A
+ HREF="directive-dict.html#Context"
+ REL="Help"
+><STRONG>Context:</STRONG></A> server config, virtual host<BR>
+<A
+ HREF="directive-dict.html#Override"
+ REL="Help"
+><STRONG>Override:</STRONG></A> <EM>Not applicable</EM><BR>
+<A
+ HREF="directive-dict.html#Status"
+ REL="Help"
+><STRONG>Status:</STRONG></A> Experimental<BR>
+<A
+ HREF="directive-dict.html#Module"
+ REL="Help"
+><STRONG>Module:</STRONG></A> mod_proxy<BR>
+<A
+ HREF="directive-dict.html#Compatibility"
+ REL="Help"
+><STRONG>Compatibility:</STRONG></A> Patch, available from 
http://allafrica.com/tools/apache/mod_proxy/<P>
+
+<P> The ProxyResponseHeader directive sets headers on proxy
+responses. The first argument, one of <EM>set | unset | add |
+append</EM>, indicates the action to be taken for the second argument,
+the <EM>header</EM>. (The trailing colon should <STRONG>not</STRONG>
+be included in the header argument.) The third argument is the
+<EM>string</EM> that should be used for a set, add or append action
+(for an unset, the string argument should be ommitted.)</P> The
+optional fourth argument, <EM>match-pattern</EM>, controls the
+application of the directive. If a match-pattern is present, the
+request uri must match the pattern for the directive to be
+applied.</P>
+
+<P> ProxyResponseHeader directives can appear in server and virtual
+server configuration sections. For each request, the directives are
+processed in declaration order -- base server directives processed
+first. For each match found, the specified action is taken.</P>
+
+<PRE>
+  ProxyResponseHeader      set    X-Desert    "pie"      "^/deserts/pie"
+  ProxyResponseHeader      set    X-Desert    "jello"    "^/deserts/jello"
+  ProxyResponseHeader      set    X-Desert    "jello"    "^/deserts/gelatin"
+  ProxyResponseHeader      set    X-Desert    "unknown"
+</PRE>
+
+<HR>
+
+
+
+
+
+
+
+
 <H3 ALIGN="CENTER">
  Apache HTTP Server Version 1.3
 </H3>
@@ -1188,4 +1472,5 @@
 
 </BODY>
 </HTML>
+
 

Reply via email to