1
0
mirror of https://github.com/apache/httpd.git synced 2025-08-07 04:02:58 +03:00

Fix for multiple proxy bugs - review please:

#10722  Reverse proxying cookies
#15207  Proxy passing canonicalised URIs to backend
#16812  Case-insensitivity of proxypassreverse
#19317  Canonicalised URI causing infinite loop
#20372  AllowEncodedSlashes
May also fix 13577 (untested)

This is really two fixes: 10722 and 15207; the others are trivial consequences.
To make review easier, the simpler fix (#15207) is entirely contained in
#ifdef FIX_15207 (new code) and
#ifndef FIX_15207 (removed code)


git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@104070 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Nick Kew
2004-06-29 06:37:21 +00:00
parent 46ff3a2fdc
commit b6e89d86f7
4 changed files with 351 additions and 153 deletions

View File

@@ -1,3 +1,4 @@
#define FIX_15207
/* Copyright 1999-2004 The Apache Software Foundation /* Copyright 1999-2004 The Apache Software Foundation
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@@ -42,10 +43,22 @@
/* -------------------------------------------------------------- */ /* -------------------------------------------------------------- */
/* Translate the URL into a 'filename' */ /* Translate the URL into a 'filename' */
#ifdef FIX_15207
#define x2c(x) ((x>='0')&&(x<='9'))?(x-'0'):(((x>='a')&&(x<='f'))?(10+x-'a'):((x>='A')&&(x<='F'))?(10+x-'A'):0)
static unsigned char hex2c(const char* p) {
char c1 = p[1] ;
char c2 = p[2] ;
int i1 = x2c(c1) ;
int i2 = x2c(c2) ;
unsigned char ret = (i1<<4) | i2 ;
return ret ;
}
#endif
static int alias_match(const char *uri, const char *alias_fakename) static int alias_match(const char *uri, const char *alias_fakename)
{ {
const char *end_fakename = alias_fakename + strlen(alias_fakename); const char *end_fakename = alias_fakename + strlen(alias_fakename);
const char *aliasp = alias_fakename, *urip = uri; const char *aliasp = alias_fakename, *urip = uri;
unsigned char uric, aliasc ;
while (aliasp < end_fakename) { while (aliasp < end_fakename) {
if (*aliasp == '/') { if (*aliasp == '/') {
@@ -61,9 +74,28 @@ static int alias_match(const char *uri, const char *alias_fakename)
++urip; ++urip;
} }
else { else {
#ifndef FIX_15207
/* Other characters are compared literally */ /* Other characters are compared literally */
if (*urip++ != *aliasp++) if (*urip++ != *aliasp++)
return 0; return 0;
#else
/* Other characters are canonicalised and compared literally */
if ( *urip == '%' ) {
uric = hex2c(urip) ;
urip += 3 ;
} else {
uric = (unsigned char)*urip++ ;
}
if ( *aliasp == '%' ) {
aliasc = hex2c(aliasp) ;
aliasp += 3 ;
} else {
aliasc = (unsigned char)*aliasp++ ;
}
if ( uric != aliasc ) {
return 0;
}
#endif
} }
} }
@@ -94,9 +126,12 @@ static int alias_match(const char *uri, const char *alias_fakename)
static int proxy_detect(request_rec *r) static int proxy_detect(request_rec *r)
{ {
void *sconf = r->server->module_config; void *sconf = r->server->module_config;
proxy_server_conf *conf; proxy_server_conf *conf =
(proxy_server_conf *) ap_get_module_config(sconf, &proxy_module);
conf = (proxy_server_conf *) ap_get_module_config(sconf, &proxy_module); #ifdef FIX_15207
int i, len;
struct proxy_alias *ent = (struct proxy_alias *)conf->aliases->elts;
#endif
/* Ick... msvc (perhaps others) promotes ternary short results to int */ /* Ick... msvc (perhaps others) promotes ternary short results to int */
@@ -121,6 +156,21 @@ static int proxy_detect(request_rec *r)
r->uri = r->unparsed_uri; r->uri = r->unparsed_uri;
r->filename = apr_pstrcat(r->pool, "proxy:", r->uri, NULL); r->filename = apr_pstrcat(r->pool, "proxy:", r->uri, NULL);
r->handler = "proxy-server"; r->handler = "proxy-server";
#ifdef FIX_15207
} else {
/* test for a ProxyPass */
for (i = 0; i < conf->aliases->nelts; i++) {
len = alias_match(r->unparsed_uri, ent[i].fake);
if (len > 0) {
r->filename = apr_pstrcat(r->pool, "proxy:", ent[i].real,
r->unparsed_uri + len, NULL);
r->handler = "proxy-server";
r->proxyreq = PROXYREQ_REVERSE;
r->uri = r->unparsed_uri;
break;
}
}
#endif
} }
return DECLINED; return DECLINED;
} }
@@ -139,7 +189,7 @@ static int proxy_trans(request_rec *r)
*/ */
return OK; return OK;
} }
#ifndef FIX_15207
/* XXX: since r->uri has been manipulated already we're not really /* XXX: since r->uri has been manipulated already we're not really
* compliant with RFC1945 at this point. But this probably isn't * compliant with RFC1945 at this point. But this probably isn't
* an issue because this is a hybrid proxy/origin server. * an issue because this is a hybrid proxy/origin server.
@@ -160,6 +210,7 @@ static int proxy_trans(request_rec *r)
return OK; return OK;
} }
} }
#endif
return DECLINED; return DECLINED;
} }
@@ -221,7 +272,7 @@ static int proxy_map_location(request_rec *r)
return OK; return OK;
} }
#ifndef FIX_15207
/* -------------------------------------------------------------- */ /* -------------------------------------------------------------- */
/* Fixup the filename */ /* Fixup the filename */
@@ -236,6 +287,15 @@ static int proxy_fixup(request_rec *r)
if (!r->proxyreq || !r->filename || strncmp(r->filename, "proxy:", 6) != 0) if (!r->proxyreq || !r->filename || strncmp(r->filename, "proxy:", 6) != 0)
return DECLINED; return DECLINED;
#ifdef FIX_15207
/* We definitely shouldn't canonicalize a proxy_pass.
* But should we really canonicalize a STD_PROXY??? -- Fahree
*/
if (r->proxyreq == PROXYREQ_REVERSE) {
return OK;
}
#endif
/* XXX: Shouldn't we try this before we run the proxy_walk? */ /* XXX: Shouldn't we try this before we run the proxy_walk? */
url = &r->filename[6]; url = &r->filename[6];
@@ -250,7 +310,7 @@ static int proxy_fixup(request_rec *r)
return OK; /* otherwise; we've done the best we can */ return OK; /* otherwise; we've done the best we can */
} }
#endif
/* Send a redirection if the request contains a hostname which is not */ /* Send a redirection if the request contains a hostname which is not */
/* fully qualified, i.e. doesn't have a domain name appended. Some proxy */ /* fully qualified, i.e. doesn't have a domain name appended. Some proxy */
/* servers like Netscape's allow this and access hosts from the local */ /* servers like Netscape's allow this and access hosts from the local */
@@ -439,6 +499,10 @@ static void * create_proxy_config(apr_pool_t *p, server_rec *s)
ps->proxies = apr_array_make(p, 10, sizeof(struct proxy_remote)); ps->proxies = apr_array_make(p, 10, sizeof(struct proxy_remote));
ps->aliases = apr_array_make(p, 10, sizeof(struct proxy_alias)); ps->aliases = apr_array_make(p, 10, sizeof(struct proxy_alias));
ps->raliases = 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->noproxies = apr_array_make(p, 10, sizeof(struct noproxy_entry));
ps->dirconn = apr_array_make(p, 10, sizeof(struct dirconn_entry)); ps->dirconn = apr_array_make(p, 10, sizeof(struct dirconn_entry));
ps->allowed_connect_ports = apr_array_make(p, 10, sizeof(int)); ps->allowed_connect_ports = apr_array_make(p, 10, sizeof(int));
@@ -474,6 +538,12 @@ static void * merge_proxy_config(apr_pool_t *p, void *basev, void *overridesv)
ps->sec_proxy = apr_array_append(p, base->sec_proxy, overrides->sec_proxy); ps->sec_proxy = apr_array_append(p, base->sec_proxy, overrides->sec_proxy);
ps->aliases = apr_array_append(p, base->aliases, overrides->aliases); ps->aliases = apr_array_append(p, base->aliases, overrides->aliases);
ps->raliases = apr_array_append(p, base->raliases, overrides->raliases); 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->noproxies = apr_array_append(p, base->noproxies, overrides->noproxies);
ps->dirconn = apr_array_append(p, base->dirconn, overrides->dirconn); 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); ps->allowed_connect_ports = apr_array_append(p, base->allowed_connect_ports, overrides->allowed_connect_ports);
@@ -639,6 +709,34 @@ static const char *
return NULL; return NULL;
} }
static const char*
cookie_path(cmd_parms *cmd, void *dummy, const char *f, const char *r)
{
server_rec *s = cmd->server;
proxy_server_conf *conf;
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;
return NULL ;
}
static const char*
cookie_domain(cmd_parms *cmd, void *dummy, const char *f, const char *r)
{
server_rec *s = cmd->server;
proxy_server_conf *conf;
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;
return NULL ;
}
static const char * static const char *
set_proxy_exclude(cmd_parms *parms, void *dummy, const char *arg) set_proxy_exclude(cmd_parms *parms, void *dummy, const char *arg)
@@ -1005,6 +1103,10 @@ static const command_rec proxy_cmds[] =
"a virtual path and a URL"), "a virtual path and a URL"),
AP_INIT_TAKE12("ProxyPassReverse", add_pass_reverse, NULL, RSRC_CONF|ACCESS_CONF, AP_INIT_TAKE12("ProxyPassReverse", add_pass_reverse, NULL, RSRC_CONF|ACCESS_CONF,
"a virtual path and a URL for reverse proxy behaviour"), "a virtual path and a URL for reverse proxy behaviour"),
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") ,
AP_INIT_ITERATE("ProxyBlock", set_proxy_exclude, NULL, RSRC_CONF, AP_INIT_ITERATE("ProxyBlock", set_proxy_exclude, NULL, RSRC_CONF,
"A list of names, hosts or domains to which the proxy will not connect"), "A list of names, hosts or domains to which the proxy will not connect"),
AP_INIT_TAKE1("ProxyReceiveBufferSize", set_recv_buffer_size, NULL, RSRC_CONF, AP_INIT_TAKE1("ProxyReceiveBufferSize", set_recv_buffer_size, NULL, RSRC_CONF,
@@ -1081,8 +1183,10 @@ static void register_hooks(apr_pool_t *p)
ap_hook_translate_name(proxy_trans, NULL, NULL, APR_HOOK_FIRST); ap_hook_translate_name(proxy_trans, NULL, NULL, APR_HOOK_FIRST);
/* walk <Proxy > entries and suppress default TRACE behavior */ /* walk <Proxy > entries and suppress default TRACE behavior */
ap_hook_map_to_storage(proxy_map_location, NULL,NULL, APR_HOOK_FIRST); ap_hook_map_to_storage(proxy_map_location, NULL,NULL, APR_HOOK_FIRST);
#ifndef FIX_15207
/* fixups */ /* fixups */
ap_hook_fixups(proxy_fixup, NULL, aszSucc, APR_HOOK_FIRST); ap_hook_fixups(proxy_fixup, NULL, aszSucc, APR_HOOK_FIRST);
#endif
/* post read_request handling */ /* post read_request handling */
ap_hook_post_read_request(proxy_detect, NULL, NULL, APR_HOOK_FIRST); ap_hook_post_read_request(proxy_detect, NULL, NULL, APR_HOOK_FIRST);
/* post config handling */ /* post config handling */

View File

@@ -49,6 +49,7 @@
#include "apr_strings.h" #include "apr_strings.h"
#include "apr_uri.h" #include "apr_uri.h"
#include "apr_date.h" #include "apr_date.h"
#include "apr_strmatch.h"
#include "apr_fnmatch.h" #include "apr_fnmatch.h"
#define APR_WANT_STRFUNC #define APR_WANT_STRFUNC
#include "apr_want.h" #include "apr_want.h"
@@ -158,6 +159,14 @@ typedef struct {
bad_body bad_body
} badopt; /* how to deal with bad headers */ } badopt; /* how to deal with bad headers */
char badopt_set; char badopt_set;
/* putting 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_server_conf; } proxy_server_conf;
@@ -229,7 +238,6 @@ PROXY_DECLARE(char *)ap_proxy_canonenc(apr_pool_t *p, const char *x, int len, en
PROXY_DECLARE(char *)ap_proxy_canon_netloc(apr_pool_t *p, char **const urlp, char **userp, PROXY_DECLARE(char *)ap_proxy_canon_netloc(apr_pool_t *p, char **const urlp, char **userp,
char **passwordp, char **hostp, apr_port_t *port); char **passwordp, char **hostp, apr_port_t *port);
PROXY_DECLARE(const char *)ap_proxy_date_canon(apr_pool_t *p, const char *x); PROXY_DECLARE(const char *)ap_proxy_date_canon(apr_pool_t *p, const char *x);
PROXY_DECLARE(apr_table_t *)ap_proxy_read_headers(request_rec *r, request_rec *rp, char *buffer, int size, conn_rec *c);
PROXY_DECLARE(int) ap_proxy_liststr(const char *list, const char *val); PROXY_DECLARE(int) ap_proxy_liststr(const char *list, const char *val);
PROXY_DECLARE(char *)ap_proxy_removestr(apr_pool_t *pool, const char *list, const char *val); PROXY_DECLARE(char *)ap_proxy_removestr(apr_pool_t *pool, const char *list, const char *val);
PROXY_DECLARE(int) ap_proxy_hex2sec(const char *x); PROXY_DECLARE(int) ap_proxy_hex2sec(const char *x);

View File

@@ -122,13 +122,106 @@ static const char *ap_proxy_location_reverse_map(request_rec *r, proxy_server_co
ent = (struct proxy_alias *)conf->raliases->elts; ent = (struct proxy_alias *)conf->raliases->elts;
for (i = 0; i < conf->raliases->nelts; i++) { for (i = 0; i < conf->raliases->nelts; i++) {
l2 = strlen(ent[i].real); l2 = strlen(ent[i].real);
if (l1 >= l2 && strncmp(ent[i].real, url, l2) == 0) { if (l1 >= l2 && strncasecmp(ent[i].real, url, l2) == 0) {
u = apr_pstrcat(r->pool, ent[i].fake, &url[l2], NULL); u = apr_pstrcat(r->pool, ent[i].fake, &url[l2], NULL);
return ap_construct_url(r->pool, u, r); return ap_construct_url(r->pool, u, r);
} }
} }
return url; 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_server_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, doffs ;
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 = strchr(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 = strchr(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 && strncasecmp(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 */ /* Clear all connection-based headers from the incoming headers table */
static void ap_proxy_clear_connection(apr_pool_t *p, apr_table_t *headers) static void ap_proxy_clear_connection(apr_pool_t *p, apr_table_t *headers)
@@ -375,6 +468,7 @@ apr_status_t ap_proxy_http_create_connection(apr_pool_t *p, request_rec *r,
return OK; return OK;
} }
static static
apr_status_t ap_proxy_http_request(apr_pool_t *p, request_rec *r, apr_status_t ap_proxy_http_request(apr_pool_t *p, request_rec *r,
proxy_http_conn_t *p_conn, conn_rec *origin, proxy_http_conn_t *p_conn, conn_rec *origin,
@@ -751,6 +845,139 @@ apr_status_t ap_proxy_http_request(apr_pool_t *p, request_rec *r,
return APR_SUCCESS; return APR_SUCCESS;
} }
static void process_proxy_header(request_rec* r, proxy_server_conf* c,
const char* key, const char* value)
{
static const char* date_hdrs[]
= { "Date", "Expires", "Last-Modified", NULL } ;
static const struct {
const char* name ;
const char* (*func)(request_rec*, proxy_server_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(r->headers_out, key,
ap_proxy_date_canon(r->pool, value)) ;
return ;
}
}
for ( i = 0 ; transform_hdrs[i].name ; ++i ) {
if ( !strcasecmp(transform_hdrs[i].name, key) ) {
apr_table_add(r->headers_out, key,
(*transform_hdrs[i].func)(r, c, value)) ;
return ;
}
}
apr_table_add(r->headers_out, key, value) ;
return ;
}
static void ap_proxy_read_headers(request_rec *r, request_rec *rr, char *buffer, int size, conn_rec *c)
{
int len;
char *value, *end;
char field[MAX_STRING_LEN];
int saw_headers = 0;
void *sconf = r->server->module_config;
proxy_server_conf *psc;
psc = (proxy_server_conf *) ap_get_module_config(sconf, &proxy_module);
r->headers_out = apr_table_make(r->pool, 20);
/*
* Read header lines until we get the empty separator line, a read error,
* the connection closes (EOF), or we timeout.
*/
while ((len = ap_getline(buffer, size, rr, 1)) > 0) {
if (!(value = strchr(buffer, ':'))) { /* Find the colon separator */
/* We may encounter invalid headers, usually from buggy
* MS IIS servers, so we need to determine just how to handle
* them. We can either ignore them, assume that they mark the
* start-of-body (eg: a missing CRLF) or (the default) mark
* the headers as totally bogus and return a 500. The sole
* exception is an extra "HTTP/1.0 200, OK" line sprinkled
* in between the usual MIME headers, which is a favorite
* IIS bug.
*/
/* XXX: The mask check is buggy if we ever see an HTTP/1.10 */
if (!apr_date_checkmask(buffer, "HTTP/#.# ###*")) {
if (psc->badopt == bad_error) {
/* Nope, it wasn't even an extra HTTP header. Give up. */
return ;
}
else if (psc->badopt == bad_body) {
/* if we've already started loading headers_out, then
* return what we've accumulated so far, in the hopes
* that they are useful. Otherwise, we completely bail.
*/
/* FIXME: We've already scarfed the supposed 1st line of
* the body, so the actual content may end up being bogus
* as well. If the content is HTML, we may be lucky.
*/
if (saw_headers) {
ap_log_error(APLOG_MARK, APLOG_WARNING, 0, r->server,
"proxy: Starting body due to bogus non-header in headers "
"returned by %s (%s)", r->uri, r->method);
return ;
} else {
ap_log_error(APLOG_MARK, APLOG_WARNING, 0, r->server,
"proxy: No HTTP headers "
"returned by %s (%s)", r->uri, r->method);
return ;
}
}
}
/* this is the psc->badopt == bad_ignore case */
ap_log_error(APLOG_MARK, APLOG_WARNING, 0, r->server,
"proxy: Ignoring bogus HTTP header "
"returned by %s (%s)", r->uri, r->method);
continue;
}
*value = '\0';
++value;
/* XXX: RFC2068 defines only SP and HT as whitespace, this test is
* wrong... and so are many others probably.
*/
while (apr_isspace(*value))
++value; /* Skip to start of value */
/* should strip trailing whitespace as well */
for (end = &value[strlen(value)-1]; end > value && apr_isspace(*end); --
end)
*end = '\0';
/* make sure we add so as not to destroy duplicated headers
* Modify headers requiring canonicalisation and/or affected
* by ProxyPassReverse and family with process_proxy_header
*/
process_proxy_header(r, psc, buffer, value) ;
saw_headers = 1;
/* the header was too long; at the least we should skip extra data */
if (len >= size - 1) {
while ((len = ap_getline(field, MAX_STRING_LEN, rr, 1))
>= MAX_STRING_LEN - 1) {
/* soak up the extra data */
}
if (len == 0) /* time to exit the larger loop as well */
break;
}
}
}
static int addit_dammit(void *v, const char *key, const char *val) static int addit_dammit(void *v, const char *key, const char *val)
{ {
@@ -850,13 +1077,11 @@ apr_status_t ap_proxy_http_process_response(apr_pool_t * p, request_rec *r,
/* First, tuck away all already existing cookies */ /* First, tuck away all already existing cookies */
save_table = apr_table_make(r->pool, 2); save_table = apr_table_make(r->pool, 2);
apr_table_do(addit_dammit, save_table, r->err_headers_out,
"Set-Cookie", NULL);
apr_table_do(addit_dammit, save_table, r->headers_out, apr_table_do(addit_dammit, save_table, r->headers_out,
"Set-Cookie", NULL); "Set-Cookie", NULL);
r->headers_out = ap_proxy_read_headers(r, rp, buffer, /* shove the headers direct into r->headers_out */
sizeof(buffer), origin); ap_proxy_read_headers(r, rp, buffer, sizeof(buffer), origin);
if (r->headers_out == NULL) { if (r->headers_out == NULL) {
ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ap_log_error(APLOG_MARK, APLOG_WARNING, 0,
@@ -946,42 +1171,9 @@ apr_status_t ap_proxy_http_process_response(apr_pool_t * p, request_rec *r,
"proxy: HTTP: received interim %d response", "proxy: HTTP: received interim %d response",
r->status); r->status);
} }
/* Moved the fixups of Date headers and those affected by
/* we must accept 3 kinds of date, but generate only 1 kind of date */ * ProxyPassReverse/etc from here to ap_proxy_read_headers
{
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));
}
}
if ((r->status == 401) && (conf->error_override != 0)) { if ((r->status == 401) && (conf->error_override != 0)) {
const char *buf; const char *buf;

View File

@@ -352,112 +352,6 @@ PROXY_DECLARE(request_rec *)ap_proxy_make_fake_req(conn_rec *c, request_rec *r)
return rp; return rp;
} }
/*
* Reads headers from a buffer and returns an array of headers.
* Returns NULL on file error
* This routine tries to deal with too long lines and continuation lines.
*
* Note: Currently the headers are passed through unmerged. This has to be
* done so that headers which react badly to merging (such as Set-Cookie
* headers, which contain commas within the date field) do not get stuffed
* up.
*/
PROXY_DECLARE(apr_table_t *)ap_proxy_read_headers(request_rec *r, request_rec *rr, char *buffer, int size, conn_rec *c)
{
apr_table_t *headers_out;
int len;
char *value, *end;
char field[MAX_STRING_LEN];
int saw_headers = 0;
void *sconf = r->server->module_config;
proxy_server_conf *psc;
psc = (proxy_server_conf *) ap_get_module_config(sconf, &proxy_module);
headers_out = apr_table_make(r->pool, 20);
/*
* Read header lines until we get the empty separator line, a read error,
* the connection closes (EOF), or we timeout.
*/
while ((len = ap_getline(buffer, size, rr, 1)) > 0) {
if (!(value = strchr(buffer, ':'))) { /* Find the colon separator */
/* We may encounter invalid headers, usually from buggy
* MS IIS servers, so we need to determine just how to handle
* them. We can either ignore them, assume that they mark the
* start-of-body (eg: a missing CRLF) or (the default) mark
* the headers as totally bogus and return a 500. The sole
* exception is an extra "HTTP/1.0 200, OK" line sprinkled
* in between the usual MIME headers, which is a favorite
* IIS bug.
*/
/* XXX: The mask check is buggy if we ever see an HTTP/1.10 */
if (!apr_date_checkmask(buffer, "HTTP/#.# ###*")) {
if (psc->badopt == bad_error) {
/* Nope, it wasn't even an extra HTTP header. Give up. */
return NULL;
}
else if (psc->badopt == bad_body) {
/* if we've already started loading headers_out, then
* return what we've accumulated so far, in the hopes
* that they are useful. Otherwise, we completely bail.
*/
/* FIXME: We've already scarfed the supposed 1st line of
* the body, so the actual content may end up being bogus
* as well. If the content is HTML, we may be lucky.
*/
if (saw_headers) {
ap_log_error(APLOG_MARK, APLOG_WARNING, 0, r->server,
"proxy: Starting body due to bogus non-header in headers "
"returned by %s (%s)", r->uri, r->method);
return headers_out;
} else {
ap_log_error(APLOG_MARK, APLOG_WARNING, 0, r->server,
"proxy: No HTTP headers "
"returned by %s (%s)", r->uri, r->method);
return NULL;
}
}
}
/* this is the psc->badopt == bad_ignore case */
ap_log_error(APLOG_MARK, APLOG_WARNING, 0, r->server,
"proxy: Ignoring bogus HTTP header "
"returned by %s (%s)", r->uri, r->method);
continue;
}
*value = '\0';
++value;
/* XXX: RFC2068 defines only SP and HT as whitespace, this test is
* wrong... and so are many others probably.
*/
while (apr_isspace(*value))
++value; /* Skip to start of value */
/* should strip trailing whitespace as well */
for (end = &value[strlen(value)-1]; end > value && apr_isspace(*end); --end)
*end = '\0';
/* make sure we add so as not to destroy duplicated headers */
apr_table_add(headers_out, buffer, value);
saw_headers = 1;
/* the header was too long; at the least we should skip extra data */
if (len >= size - 1) {
while ((len = ap_getline(field, MAX_STRING_LEN, rr, 1))
>= MAX_STRING_LEN - 1) {
/* soak up the extra data */
}
if (len == 0) /* time to exit the larger loop as well */
break;
}
}
return headers_out;
}
/* /*
* list is a comma-separated list of case-insensitive tokens, with * list is a comma-separated list of case-insensitive tokens, with