This has been discussed before(*), but I never got around
to patching it in SVN.
(1) ProxyPassReverse is documented as working inside <Location>
(2) ... but ProxyPassReverse is implemented on the *server* config.
So, although it is syntactically correct within <Location> due to a
hack, it doesn't actually work there beyond the trivial case.
It loses the merge_dir_config, and instead collects all <Location>s
in a single array without any means of distinguishing them.
I attach two patches: one for trunk, the other for 2.0.
The 2.0 patch is in production at my Client, and combines a patch
I made for them in January (i.e. well-tested:-) with the
long-standing patch for Bug 10722 at issues.apache.org.
If noone objects I'll commit the Trunk patch and propose the
2.0 patch for backport.
(*) http://marc.theaimsgroup.com/?l=apache-httpd-dev&m=110726027118798&w=2
--
Nick Kew
Index: mod_proxy_http.c
===================================================================
--- mod_proxy_http.c (revision 231170)
+++ mod_proxy_http.c (working copy)
@@ -968,7 +968,7 @@
return APR_SUCCESS;
}
-static void process_proxy_header(request_rec* r, proxy_server_conf* c,
+static void process_proxy_header(request_rec* r, proxy_dir_conf* c,
const char* key, const char* value)
{
static const char* date_hdrs[]
@@ -1021,7 +1021,9 @@
int saw_headers = 0;
void *sconf = r->server->module_config;
proxy_server_conf *psc;
+ proxy_dir_conf *dconf;
+ dconf = ap_get_module_config(r->per_dir_config, &proxy_module);
psc = (proxy_server_conf *) ap_get_module_config(sconf, &proxy_module);
r->headers_out = apr_table_make(r->pool, 20);
@@ -1096,7 +1098,7 @@
* Modify headers requiring canonicalisation and/or affected
* by ProxyPassReverse and family with process_proxy_header
*/
- process_proxy_header(r, psc, buffer, value) ;
+ process_proxy_header(r, dconf, buffer, value) ;
saw_headers = 1;
/* the header was too long; at the least we should skip extra data */
Index: mod_proxy.c
===================================================================
--- mod_proxy.c (revision 231170)
+++ mod_proxy.c (working copy)
@@ -788,11 +788,6 @@
ps->sec_proxy = apr_array_make(p, 10, sizeof(ap_conf_vector_t *));
ps->proxies = apr_array_make(p, 10, sizeof(struct proxy_remote));
ps->aliases = apr_array_make(p, 10, sizeof(struct proxy_alias));
- ps->raliases = apr_array_make(p, 10, sizeof(struct proxy_alias));
- ps->cookie_paths = apr_array_make(p, 10, sizeof(struct proxy_alias));
- ps->cookie_domains = apr_array_make(p, 10, sizeof(struct proxy_alias));
- ps->cookie_path_str = apr_strmatch_precompile(p, "path=", 0);
- ps->cookie_domain_str = apr_strmatch_precompile(p, "domain=", 0);
ps->noproxies = apr_array_make(p, 10, sizeof(struct noproxy_entry));
ps->dirconn = apr_array_make(p, 10, sizeof(struct dirconn_entry));
ps->allowed_connect_ports = apr_array_make(p, 10, sizeof(int));
@@ -832,13 +827,6 @@
ps->proxies = apr_array_append(p, base->proxies, overrides->proxies);
ps->sec_proxy = apr_array_append(p, base->sec_proxy, overrides->sec_proxy);
ps->aliases = apr_array_append(p, base->aliases, overrides->aliases);
- ps->raliases = apr_array_append(p, base->raliases, overrides->raliases);
- ps->cookie_paths
- = apr_array_append(p, base->cookie_paths, overrides->cookie_paths);
- ps->cookie_domains
- = apr_array_append(p, base->cookie_domains, overrides->cookie_domains);
- ps->cookie_path_str = base->cookie_path_str;
- ps->cookie_domain_str = base->cookie_domain_str;
ps->noproxies = apr_array_append(p, base->noproxies, overrides->noproxies);
ps->dirconn = apr_array_append(p, base->dirconn, overrides->dirconn);
ps->allowed_connect_ports = apr_array_append(p,
base->allowed_connect_ports, overrides->allowed_connect_ports);
@@ -869,6 +857,13 @@
/* Filled in by proxysection, when applicable */
+ /* Put these in the dir config so they work inside <Location> */
+ new->raliases = apr_array_make(p, 10, sizeof(struct proxy_alias));
+ new->cookie_paths = apr_array_make(p, 10, sizeof(struct proxy_alias));
+ new->cookie_domains = apr_array_make(p, 10, sizeof(struct proxy_alias));
+ new->cookie_path_str = apr_strmatch_precompile(p, "path=", 0);
+ new->cookie_domain_str = apr_strmatch_precompile(p, "domain=", 0);
+
return (void *) new;
}
@@ -880,6 +875,15 @@
new->p = add->p;
new->p_is_fnmatch = add->p_is_fnmatch;
new->r = add->r;
+
+ /* Put these in the dir config so they work inside <Location> */
+ new->raliases = apr_array_append(p, base->raliases, overrides->raliases);
+ new->cookie_paths
+ = apr_array_append(p, base->cookie_paths, overrides->cookie_paths);
+ new->cookie_domains
+ = apr_array_append(p, base->cookie_domains, overrides->cookie_domains);
+ new->cookie_path_str = base->cookie_path_str;
+ new->cookie_domain_str = base->cookie_domain_str;
return new;
}
@@ -1042,14 +1046,11 @@
}
static const char *
- add_pass_reverse(cmd_parms *cmd, void *dummy, const char *f, const char *r)
+ add_pass_reverse(cmd_parms *cmd, void *dconf, const char *f, const char *r)
{
- server_rec *s = cmd->server;
- proxy_server_conf *conf;
+ proxy_dir_conf *conf = dconf;
struct proxy_alias *new;
- conf = (proxy_server_conf *)ap_get_module_config(s->module_config,
- &proxy_module);
if (r!=NULL && cmd->path == NULL ) {
new = apr_array_push(conf->raliases);
new->fake = f;
@@ -1068,14 +1069,11 @@
return NULL;
}
static const char*
- cookie_path(cmd_parms *cmd, void *dummy, const char *f, const char *r)
+ cookie_path(cmd_parms *cmd, void *dconf, const char *f, const char *r)
{
- server_rec *s = cmd->server;
- proxy_server_conf *conf;
+ proxy_dir_conf *conf = dconf;
struct proxy_alias *new;
- conf = (proxy_server_conf *)ap_get_module_config(s->module_config,
- &proxy_module);
new = apr_array_push(conf->cookie_paths);
new->fake = f;
new->real = r;
@@ -1083,14 +1081,11 @@
return NULL;
}
static const char*
- cookie_domain(cmd_parms *cmd, void *dummy, const char *f, const char *r)
+ cookie_domain(cmd_parms *cmd, void *dconf, const char *f, const char *r)
{
- server_rec *s = cmd->server;
- proxy_server_conf *conf;
+ proxy_dir_conf *conf = dconf;
struct proxy_alias *new;
- conf = (proxy_server_conf *)ap_get_module_config(s->module_config,
- &proxy_module);
new = apr_array_push(conf->cookie_domains);
new->fake = f;
new->real = r;
Index: mod_proxy.h
===================================================================
--- mod_proxy.h (revision 231170)
+++ mod_proxy.h (working copy)
@@ -125,7 +125,6 @@
apr_array_header_t *proxies;
apr_array_header_t *sec_proxy;
apr_array_header_t *aliases;
- apr_array_header_t *raliases;
apr_array_header_t *noproxies;
apr_array_header_t *dirconn;
apr_array_header_t *allowed_connect_ports;
@@ -173,10 +172,6 @@
* the strmatch_patterns are really a const just to have a
* case-independent strstr.
*/
- apr_array_header_t* cookie_paths;
- apr_array_header_t* cookie_domains;
- const apr_strmatch_pattern* cookie_path_str;
- const apr_strmatch_pattern* cookie_domain_str;
enum {
status_off,
status_on,
@@ -191,6 +186,19 @@
const char *p; /* The path */
int p_is_fnmatch; /* Is this path an fnmatch candidate? */
ap_regex_t *r; /* Is this a regex? */
+
+/* ProxyPassReverse and friends are documented as working inside
+ * <Location>. But in fact they never have done in the case of
+ * more than one <Location>, because the server_conf can't see it.
+ * We need to move them to the per-dir config.
+ * Discussed in February:
+ * http://marc.theaimsgroup.com/?l=apache-httpd-dev&m=110726027118798&w=2
+ */
+ apr_array_header_t *raliases;
+ apr_array_header_t* cookie_paths;
+ apr_array_header_t* cookie_domains;
+ const apr_strmatch_pattern* cookie_path_str;
+ const apr_strmatch_pattern* cookie_domain_str;
} proxy_dir_conf;
typedef struct {
--- dist/mod_proxy.c 2005-08-05 10:26:01.000000000 +0100
+++ patched/mod_proxy.c 2005-08-06 20:52:09.846068216 +0100
@@ -439,7 +439,6 @@
ps->sec_proxy = apr_array_make(p, 10, sizeof(ap_conf_vector_t *));
ps->proxies = apr_array_make(p, 10, sizeof(struct proxy_remote));
ps->aliases = apr_array_make(p, 10, sizeof(struct proxy_alias));
- ps->raliases = apr_array_make(p, 10, sizeof(struct proxy_alias));
ps->noproxies = apr_array_make(p, 10, sizeof(struct noproxy_entry));
ps->dirconn = apr_array_make(p, 10, sizeof(struct dirconn_entry));
ps->allowed_connect_ports = apr_array_make(p, 10, sizeof(int));
@@ -474,7 +473,6 @@
ps->proxies = apr_array_append(p, base->proxies, overrides->proxies);
ps->sec_proxy = apr_array_append(p, base->sec_proxy, overrides->sec_proxy);
ps->aliases = apr_array_append(p, base->aliases, overrides->aliases);
- ps->raliases = apr_array_append(p, base->raliases, overrides->raliases);
ps->noproxies = apr_array_append(p, base->noproxies, overrides->noproxies);
ps->dirconn = apr_array_append(p, base->dirconn, overrides->dirconn);
ps->allowed_connect_ports = apr_array_append(p,
base->allowed_connect_ports, overrides->allowed_connect_ports);
@@ -500,6 +498,11 @@
/* Filled in by proxysection, when applicable */
+ new->raliases = apr_array_make(p, 10, sizeof(struct proxy_alias));
+ new->cookie_paths = apr_array_make(p, 10, sizeof(struct proxy_alias));
+ new->cookie_domains = apr_array_make(p, 10, sizeof(struct proxy_alias));
+ new->cookie_path_str = apr_strmatch_precompile(p, "path=", 0) ;
+ new->cookie_domain_str = apr_strmatch_precompile(p, "domain=", 0) ;
return (void *) new;
}
@@ -507,10 +510,18 @@
{
proxy_dir_conf *new = (proxy_dir_conf *) apr_pcalloc(p,
sizeof(proxy_dir_conf));
proxy_dir_conf *add = (proxy_dir_conf *) addv;
+ proxy_dir_conf *base = (proxy_dir_conf *) basev;
new->p = add->p;
new->p_is_fnmatch = add->p_is_fnmatch;
new->r = add->r;
+ new->raliases = apr_array_append(p, base->raliases, add->raliases);
+ new->cookie_paths = apr_array_append(p, base->cookie_paths,
+ add->cookie_paths);
+ new->cookie_domains = apr_array_append(p, base->cookie_domains,
+ add->cookie_domains);
+ new->cookie_path_str = base->cookie_path_str;
+ new->cookie_domain_str = base->cookie_domain_str;
return new;
}
@@ -617,12 +628,9 @@
static const char *
add_pass_reverse(cmd_parms *cmd, void *dummy, const char *f, const char *r)
{
- server_rec *s = cmd->server;
- proxy_server_conf *conf;
+ proxy_dir_conf *conf = dummy;
struct proxy_alias *new;
- conf = (proxy_server_conf *)ap_get_module_config(s->module_config,
- &proxy_module);
if (r!=NULL && cmd->path == NULL ) {
new = apr_array_push(conf->raliases);
new->fake = f;
@@ -640,6 +648,29 @@
return NULL;
}
+static const char*
+ cookie_path(cmd_parms *cmd, void *dummy, const char *f, const char *r)
+{
+ proxy_dir_conf *conf = dummy;
+ struct proxy_alias *new;
+
+ new = apr_array_push(conf->cookie_paths) ;
+ new->fake = f;
+ new->real = r;
+ return NULL ;
+}
+static const char*
+ cookie_domain(cmd_parms *cmd, void *dummy, const char *f, const char *r)
+{
+ proxy_dir_conf *conf = dummy;
+ struct proxy_alias *new;
+
+ new = apr_array_push(conf->cookie_domains) ;
+ new->fake = f;
+ new->real = r;
+ return NULL ;
+}
+
static const char *
set_proxy_exclude(cmd_parms *parms, void *dummy, const char *arg)
@@ -1031,6 +1062,10 @@
"This overrides the server timeout"),
AP_INIT_TAKE1("ProxyBadHeader", set_bad_opt, NULL, RSRC_CONF,
"How to handle bad header line in response: IsError | Ignore |
StartBody"),
+ AP_INIT_TAKE2("ProxyPassReverseCookiePath", cookie_path, NULL,
+ RSRC_CONF|ACCESS_CONF, "Path rewrite rule for proxying cookies") ,
+ AP_INIT_TAKE2("ProxyPassReverseCookieDomain", cookie_domain, NULL,
+ RSRC_CONF|ACCESS_CONF, "Domain rewrite rule for proxying cookies") ,
{NULL}
};
--- dist/mod_proxy.h 2005-08-05 10:26:01.000000000 +0100
+++ patched/mod_proxy.h 2005-08-06 20:46:27.467117728 +0100
@@ -51,6 +51,7 @@
#include "apr_uri.h"
#include "apr_date.h"
#include "apr_fnmatch.h"
+#include "apr_strmatch.h"
#define APR_WANT_STRFUNC
#include "apr_want.h"
@@ -119,7 +120,6 @@
apr_array_header_t *proxies;
apr_array_header_t *sec_proxy;
apr_array_header_t *aliases;
- apr_array_header_t *raliases;
apr_array_header_t *noproxies;
apr_array_header_t *dirconn;
apr_array_header_t *allowed_connect_ports;
@@ -166,6 +166,16 @@
const char *p; /* The path */
int p_is_fnmatch; /* Is this path an fnmatch candidate? */
regex_t *r; /* Is this a regex? */
+ apr_array_header_t *raliases;
+
+/* new stuff on the end maximises binary back-compatibility.
+ the strmatch_patterns are really a const just to have a
+ case-independent strstr.
+ */
+ apr_array_header_t* cookie_paths ;
+ apr_array_header_t* cookie_domains ;
+ const apr_strmatch_pattern* cookie_path_str ;
+ const apr_strmatch_pattern* cookie_domain_str ;
} proxy_dir_conf;
typedef struct {
--- dist/proxy_http.c 2005-08-05 10:26:20.000000000 +0100
+++ patched/proxy_http.c 2005-08-06 20:56:06.363112160 +0100
@@ -19,6 +19,7 @@
#include "mod_proxy.h"
module AP_MODULE_DECLARE_DATA proxy_http_module;
+module AP_MODULE_DECLARE_DATA proxy_module;
int ap_proxy_http_canon(request_rec *r, char *url);
int ap_proxy_http_handler(request_rec *r, proxy_server_conf *conf,
@@ -110,7 +111,7 @@
return OK;
}
-static const char *ap_proxy_location_reverse_map(request_rec *r,
proxy_server_conf *conf, const char *url)
+static const char *ap_proxy_location_reverse_map(request_rec *r,
proxy_dir_conf *conf, const char *url)
{
struct proxy_alias *ent;
int i, l1, l2;
@@ -130,6 +131,98 @@
}
return url;
}
+/* cookies are a bit trickier to match: we've got two substrings to worry
+ * about, and we can't just find them with strstr 'cos of case. Regexp
+ * matching would be an easy fix, but for better consistency with all the
+ * other matches we'll refrain and use apr_strmatch to find path=/domain=
+ * and stick to plain strings for the config values.
+ */
+static const char *proxy_cookie_reverse_map(request_rec *r, proxy_dir_conf
*conf, const char *str)
+{
+ struct proxy_alias *ent;
+ size_t len = strlen(str);
+ const char* newpath = NULL ;
+ const char* newdomain = NULL ;
+ const char* pathp ;
+ const char* domainp ;
+ const char* pathe ;
+ const char* domaine ;
+ size_t l1, l2, i, poffs = 0, doffs = 0 ;
+ int ddiff = 0 ;
+ int pdiff = 0 ;
+ char* ret ;
+
+/* find the match and replacement, but save replacing until we've done
+ both path and domain so we know the new strlen
+*/
+ if (pathp = apr_strmatch(conf->cookie_path_str, str, len), pathp) {
+ pathp += 5 ;
+ poffs = pathp - str ;
+ pathe = ap_strchr((char*)pathp, ';') ;
+ l1 = pathe ? (pathe-pathp) : strlen(pathp) ;
+ pathe = pathp + l1 ;
+ ent = (struct proxy_alias *)conf->cookie_paths->elts;
+ for (i = 0; i < conf->cookie_paths->nelts; i++) {
+ l2 = strlen(ent[i].fake);
+ if (l1 >= l2 && strncmp(ent[i].fake, pathp, l2) == 0) {
+ newpath = ent[i].real ;
+ pdiff = strlen(newpath) - l1 ;
+ break ;
+ }
+ }
+ }
+ if (domainp = apr_strmatch(conf->cookie_domain_str, str, len), domainp) {
+ domainp += 7 ;
+ doffs = domainp - str ;
+ domaine = ap_strchr((char*)domainp, ';') ;
+ l1 = domaine ? (domaine-domainp) : strlen(domainp) ;
+ domaine = domainp + l1 ;
+ ent = (struct proxy_alias *)conf->cookie_domains->elts;
+ for (i = 0; i < conf->cookie_domains->nelts; i++) {
+ l2 = strlen(ent[i].fake);
+ if (l1 >= l2 && strncmp(ent[i].fake, domainp, l2) == 0) {
+ newdomain = ent[i].real ;
+ ddiff = strlen(newdomain) - l1 ;
+ break ;
+ }
+ }
+ }
+ if (newpath) {
+ ret = apr_palloc(r->pool, len+pdiff+ddiff+1) ;
+ l1 = strlen(newpath) ;
+ if ( newdomain ) {
+ l2 = strlen(newdomain) ;
+ if (doffs > poffs) {
+ memcpy(ret, str, poffs) ;
+ memcpy(ret+poffs, newpath, l1) ;
+ memcpy(ret+poffs+l1, pathe, domainp-pathe) ;
+ memcpy(ret+doffs+pdiff, newdomain, l2) ;
+ strcpy(ret+doffs+pdiff+l2, domaine) ;
+ } else {
+ memcpy(ret, str, doffs) ;
+ memcpy(ret+doffs, newdomain, l2) ;
+ memcpy(ret+doffs+l2, domaine, pathp-domaine) ;
+ memcpy(ret+poffs+ddiff, newpath, l1) ;
+ strcpy(ret+poffs+ddiff+l1, pathe) ;
+ }
+ } else {
+ memcpy(ret, str, poffs) ;
+ memcpy(ret+poffs, newpath, l1) ;
+ strcpy(ret+poffs+l1, pathe) ;
+ }
+ } else {
+ if ( newdomain ) {
+ ret = apr_palloc(r->pool, len+pdiff+ddiff+1) ;
+ l2 = strlen(newdomain) ;
+ memcpy(ret, str, doffs) ;
+ memcpy(ret+doffs, newdomain, l2) ;
+ strcpy(ret+doffs+l2, domaine) ;
+ } else {
+ ret = (char*) str ; /* no change */
+ }
+ }
+ return ret ;
+}
/* Clear all connection-based headers from the incoming headers table */
static void ap_proxy_clear_connection(apr_pool_t *p, apr_table_t *headers)
@@ -659,6 +752,44 @@
return APR_SUCCESS;
}
+typedef struct {
+ request_rec* r ;
+ proxy_dir_conf* c ;
+} hdr_rec ;
+static int process_proxy_header(void* CTX, const char* key, const char* value)
+{
+ hdr_rec* ctx = CTX ;
+ static const char* date_hdrs[]
+ = { "Date", "Expires", "Last-Modified", NULL } ;
+ static const struct {
+ const char* name ;
+ const char* (*func)(request_rec*, proxy_dir_conf*, const char*) ;
+ } transform_hdrs[] = {
+ { "Location", ap_proxy_location_reverse_map } ,
+ { "Content-Location", ap_proxy_location_reverse_map } ,
+ { "URI", ap_proxy_location_reverse_map } ,
+ { "Set-Cookie", proxy_cookie_reverse_map } ,
+ { NULL, NULL }
+ } ;
+ int i ;
+ for ( i = 0 ; date_hdrs[i] ; ++i ) {
+ if ( !strcasecmp(date_hdrs[i], key) ) {
+ apr_table_add(ctx->r->headers_out, key,
+ ap_proxy_date_canon(ctx->r->pool, value)) ;
+ return 1 ;
+ }
+ }
+ for ( i = 0 ; transform_hdrs[i].name ; ++i ) {
+ if ( !strcasecmp(transform_hdrs[i].name, key) ) {
+ apr_table_add(ctx->r->headers_out, key,
+ (*transform_hdrs[i].func)(ctx->r, ctx->c, value)) ;
+ return 2 ;
+ }
+ }
+ apr_table_add(ctx->r->headers_out, key, value) ;
+ return 3 ;
+}
+
static
apr_status_t ap_proxy_http_process_response(apr_pool_t * p, request_rec *r,
proxy_http_conn_t *p_conn,
@@ -667,17 +798,23 @@
proxy_server_conf *conf,
apr_bucket_brigade *bb,
char *server_portstr) {
+ apr_table_t* backend_headers ;
conn_rec *c = r->connection;
char buffer[HUGE_STRING_LEN];
char keepchar;
request_rec *rp;
apr_bucket *e;
int len, backasswards;
+ proxy_dir_conf *dconf = ap_get_module_config(r->per_dir_config,
+ &proxy_module) ;
int received_continue = 1; /* flag to indicate if we should
* loop over response parsing logic
* in the case that the origin told us
* to HTTP_CONTINUE
*/
+ hdr_rec hdrctx ;
+ hdrctx.r = r ;
+ hdrctx.c = dconf ;
/* Get response from the remote server, and pass it up the
* filter chain
@@ -749,9 +886,9 @@
/* N.B. for HTTP/1.0 clients, we have to fold line-wrapped
headers*/
/* Also, take care with headers with multiple occurences. */
- r->headers_out = ap_proxy_read_headers(r, rp, buffer,
- sizeof(buffer), origin);
- if (r->headers_out == NULL) {
+ backend_headers = ap_proxy_read_headers(r, rp, buffer,
+ sizeof(buffer), origin);
+ if (backend_headers == NULL) {
ap_log_error(APLOG_MARK, APLOG_WARNING, 0,
r->server, "proxy: bad HTTP/%d.%d header "
"returned by %s (%s)", major, minor, r->uri,
@@ -762,7 +899,7 @@
* are in a bad position here.. so force everything we send out
* to have nothing to do with the incoming packet
*/
- r->headers_out = apr_table_make(r->pool,1);
+ backend_headers = apr_table_make(r->pool,1);
r->status = HTTP_BAD_GATEWAY;
r->status_line = "bad gateway";
return r->status;
@@ -770,11 +907,11 @@
} else {
/* strip connection listed hop-by-hop headers from response */
const char *buf;
- p_conn->close += ap_proxy_liststr(apr_table_get(r->headers_out,
+ p_conn->close +=
ap_proxy_liststr(apr_table_get(backend_headers,
"Connection"),
"close");
- ap_proxy_clear_connection(p, r->headers_out);
- if ((buf = apr_table_get(r->headers_out, "Content-Type"))) {
+ ap_proxy_clear_connection(p, backend_headers);
+ if ((buf = apr_table_get(backend_headers, "Content-Type"))) {
ap_set_content_type(r, apr_pstrdup(p, buf));
}
ap_proxy_pre_http_request(origin,rp);
@@ -783,7 +920,7 @@
/* handle Via header in response */
if (conf->viaopt != via_off && conf->viaopt != via_block) {
/* create a "Via:" response header entry and merge it */
- apr_table_mergen(r->headers_out, "Via",
+ apr_table_mergen(backend_headers, "Via",
(conf->viaopt == via_full)
? apr_psprintf(p, "%d.%d %s%s (%s)",
HTTP_VERSION_MAJOR(r->proto_num),
@@ -819,41 +956,17 @@
"proxy: HTTP: received 100 CONTINUE");
}
- /* we must accept 3 kinds of date, but generate only 1 kind of date */
- {
- const char *buf;
- if ((buf = apr_table_get(r->headers_out, "Date")) != NULL) {
- apr_table_set(r->headers_out, "Date",
- ap_proxy_date_canon(p, buf));
- }
- if ((buf = apr_table_get(r->headers_out, "Expires")) != NULL) {
- apr_table_set(r->headers_out, "Expires",
- ap_proxy_date_canon(p, buf));
- }
- if ((buf = apr_table_get(r->headers_out, "Last-Modified")) !=
NULL) {
- apr_table_set(r->headers_out, "Last-Modified",
- ap_proxy_date_canon(p, buf));
- }
- }
-
- /* munge the Location and URI response headers according to
- * ProxyPassReverse
- */
- {
- const char *buf;
- if ((buf = apr_table_get(r->headers_out, "Location")) != NULL) {
- apr_table_set(r->headers_out, "Location",
- ap_proxy_location_reverse_map(r, conf, buf));
- }
- if ((buf = apr_table_get(r->headers_out, "Content-Location")) !=
NULL) {
- apr_table_set(r->headers_out, "Content-Location",
- ap_proxy_location_reverse_map(r, conf, buf));
- }
- if ((buf = apr_table_get(r->headers_out, "URI")) != NULL) {
- apr_table_set(r->headers_out, "URI",
- ap_proxy_location_reverse_map(r, conf, buf));
- }
+/* transcribe backend headers to headers_out, rewriting any that need it.
+ * The old method based on if ( apr_table_get(...) ) fails against
+ * duplicated headers, so we copy-and-transcribe by the entry instead.
+ */
+ if ( r->headers_out ) {
+ apr_table_clear(r->headers_out) ;
+ } else {
+ r->headers_out = apr_table_make(r->pool, 10) ;
}
+ apr_table_do(process_proxy_header, &hdrctx, backend_headers, NULL) ;
+ apr_table_clear(backend_headers) ;
if ((r->status == 401) && (conf->error_override != 0)) {
const char *buf;