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:
@@ -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 */
|
||||||
|
@@ -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);
|
||||||
|
@@ -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;
|
||||||
|
@@ -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
|
||||||
|
Reference in New Issue
Block a user