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

mod_proxy: Optimise ProxyPass within a Location so that it is stored

per-directory, and chosen during the location walk. Make ProxyPass
work correctly from within a LocationMatch.


git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1026184 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Graham Leggett
2010-10-22 00:13:45 +00:00
parent 8de5190445
commit 13fec746f9
4 changed files with 165 additions and 88 deletions

View File

@@ -559,21 +559,104 @@ static apr_array_header_t *proxy_vars(request_rec *r,
}
return ret;
}
static int proxy_trans(request_rec *r)
static int proxy_trans_match(request_rec *r, struct proxy_alias *ent,
proxy_dir_conf *dconf)
{
void *sconf = r->server->module_config;
proxy_server_conf *conf =
(proxy_server_conf *) ap_get_module_config(sconf, &proxy_module);
int i, len;
struct proxy_alias *ent = (struct proxy_alias *) conf->aliases->elts;
proxy_dir_conf *dconf = ap_get_module_config(r->per_dir_config,
&proxy_module);
int len;
const char *fake;
const char *real;
ap_regmatch_t regm[AP_MAX_REG_MATCH];
ap_regmatch_t reg1[AP_MAX_REG_MATCH];
char *found = NULL;
int mismatch = 0;
unsigned int nocanon = ent->flags & PROXYPASS_NOCANON;
const char *use_uri = nocanon ? r->unparsed_uri : r->uri;
if ((dconf->interpolate_env == 1) && (ent->flags & PROXYPASS_INTERPOLATE)) {
fake = proxy_interpolate(r, ent->fake);
real = proxy_interpolate(r, ent->real);
}
else {
fake = ent->fake;
real = ent->real;
}
if (ent->regex) {
if (!ap_regexec(ent->regex, r->uri, AP_MAX_REG_MATCH, regm, 0)) {
if ((real[0] == '!') && (real[1] == '\0')) {
return DECLINED;
}
/* test that we haven't reduced the URI */
if (nocanon && ap_regexec(ent->regex, r->unparsed_uri,
AP_MAX_REG_MATCH, reg1, 0)) {
mismatch = 1;
use_uri = r->uri;
}
found = ap_pregsub(r->pool, real, use_uri, AP_MAX_REG_MATCH,
(use_uri == r->uri) ? regm : reg1);
/* Note: The strcmp() below catches cases where there
* was no regex substitution. This is so cases like:
*
* ProxyPassMatch \.gif balancer://foo
*
* will work "as expected". The upshot is that the 2
* directives below act the exact same way (ie: $1 is implied):
*
* ProxyPassMatch ^(/.*\.gif)$ balancer://foo
* ProxyPassMatch ^(/.*\.gif)$ balancer://foo$1
*
* which may be confusing.
*/
if (found && strcmp(found, real)) {
found = apr_pstrcat(r->pool, "proxy:", found, NULL);
}
else {
found = apr_pstrcat(r->pool, "proxy:", real, use_uri, NULL);
}
}
}
else {
len = alias_match(r->uri, fake);
if (len != 0) {
if ((real[0] == '!') && (real[1] == '\0')) {
return DECLINED;
}
if (nocanon && len != alias_match(r->unparsed_uri, ent->fake)) {
mismatch = 1;
use_uri = r->uri;
}
found = apr_pstrcat(r->pool, "proxy:", real, use_uri + len, NULL);
}
}
if (mismatch) {
/* We made a reducing transformation, so we can't safely use
* unparsed_uri. Safe fallback is to ignore nocanon.
*/
ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,
"Unescaped URL path matched ProxyPass; ignoring unsafe nocanon");
}
if (found) {
r->filename = found;
r->handler = "proxy-server";
r->proxyreq = PROXYREQ_REVERSE;
if (nocanon && !mismatch) {
/* mod_proxy_http needs to be told. Different module. */
apr_table_setn(r->notes, "proxy-nocanon", "1");
}
return OK;
}
return DONE;
}
static int proxy_trans(request_rec *r)
{
int i;
struct proxy_alias *ent;
proxy_dir_conf *dconf;
proxy_server_conf *conf;
if (r->proxyreq) {
/* someone has already set up the proxy, it was possibly ourselves
@@ -587,86 +670,27 @@ static int proxy_trans(request_rec *r)
* an issue because this is a hybrid proxy/origin server.
*/
for (i = 0; i < conf->aliases->nelts; i++) {
unsigned int nocanon = ent[i].flags & PROXYPASS_NOCANON;
const char *use_uri = nocanon ? r->unparsed_uri : r->uri;
if ((dconf->interpolate_env == 1)
&& (ent[i].flags & PROXYPASS_INTERPOLATE)) {
fake = proxy_interpolate(r, ent[i].fake);
real = proxy_interpolate(r, ent[i].real);
}
else {
fake = ent[i].fake;
real = ent[i].real;
}
if (ent[i].regex) {
if (!ap_regexec(ent[i].regex, r->uri, AP_MAX_REG_MATCH, regm, 0)) {
if ((real[0] == '!') && (real[1] == '\0')) {
return DECLINED;
}
/* test that we haven't reduced the URI */
if (nocanon && ap_regexec(ent[i].regex, r->unparsed_uri,
AP_MAX_REG_MATCH, reg1, 0)) {
mismatch = 1;
use_uri = r->uri;
}
found = ap_pregsub(r->pool, real, use_uri, AP_MAX_REG_MATCH,
(use_uri == r->uri) ? regm : reg1);
/* Note: The strcmp() below catches cases where there
* was no regex substitution. This is so cases like:
*
* ProxyPassMatch \.gif balancer://foo
*
* will work "as expected". The upshot is that the 2
* directives below act the exact same way (ie: $1 is implied):
*
* ProxyPassMatch ^(/.*\.gif)$ balancer://foo
* ProxyPassMatch ^(/.*\.gif)$ balancer://foo$1
*
* which may be confusing.
*/
if (found && strcmp(found, real)) {
found = apr_pstrcat(r->pool, "proxy:", found, NULL);
}
else {
found = apr_pstrcat(r->pool, "proxy:", real,
use_uri, NULL);
}
}
}
else {
len = alias_match(r->uri, fake);
dconf = ap_get_module_config(r->per_dir_config, &proxy_module);
if (len != 0) {
if ((real[0] == '!') && (real[1] == '\0')) {
return DECLINED;
}
if (nocanon
&& len != alias_match(r->unparsed_uri, ent[i].fake)) {
mismatch = 1;
use_uri = r->uri;
}
found = apr_pstrcat(r->pool, "proxy:", real,
use_uri + len, NULL);
}
}
if (mismatch) {
/* We made a reducing transformation, so we can't safely use
* unparsed_uri. Safe fallback is to ignore nocanon.
*/
ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,
"Unescaped URL path matched ProxyPass; ignoring unsafe nocanon");
/* short way - this location is reverse proxied? */
if (dconf->alias) {
int rv = proxy_trans_match(r, dconf->alias, dconf);
if (DONE != rv) {
return rv;
}
}
if (found) {
r->filename = found;
r->handler = "proxy-server";
r->proxyreq = PROXYREQ_REVERSE;
if (nocanon && !mismatch) {
/* mod_proxy_http needs to be told. Different module. */
apr_table_setn(r->notes, "proxy-nocanon", "1");
conf
= (proxy_server_conf *) ap_get_module_config(r->server->module_config, &proxy_module);
/* long way - walk the list of aliases, find a match */
if (conf->aliases->nelts) {
ent = (struct proxy_alias *) conf->aliases->elts;
for (i = 0; i < conf->aliases->nelts; i++) {
int rv = proxy_trans_match(r, &ent[i], dconf);
if (DONE != rv) {
return rv;
}
return OK;
}
}
return DECLINED;
@@ -1216,6 +1240,8 @@ static void *merge_proxy_dir_config(apr_pool_t *p, void *basev, void *addv)
new->error_override = (add->error_override_set == 0) ? base->error_override
: add->error_override;
new->error_override_set = add->error_override_set || base->error_override_set;
new->alias = (add->alias_set == 0) ? base->alias : add->alias;
new->alias_set = add->alias_set || base->alias_set;
return new;
}
@@ -1297,6 +1323,7 @@ static const char *
static const char *
add_pass(cmd_parms *cmd, void *dummy, const char *arg, int is_regex)
{
proxy_dir_conf *dconf = (proxy_dir_conf *)dummy;
server_rec *s = cmd->server;
proxy_server_conf *conf =
(proxy_server_conf *) ap_get_module_config(s->module_config, &proxy_module);
@@ -1356,10 +1383,27 @@ static const char *
}
};
if (r == NULL)
if (r == NULL) {
return "ProxyPass|ProxyPassMatch needs a path when not defined in a location";
}
/* if per directory, save away the single alias */
if (cmd->path) {
if (dconf->alias_set) {
return "ProxyPass may be defined just once within a specific location block";
}
dconf->alias = apr_pcalloc(cmd->pool, sizeof(struct proxy_alias));
dconf->alias_set = 1;
new = dconf->alias;
if (apr_fnmatch_test(f)) {
use_regex = 1;
}
}
/* if per server, add to the alias array */
else {
new = apr_array_push(conf->aliases);
}
new = apr_array_push(conf->aliases);
new->fake = apr_pstrdup(cmd->pool, f);
new->real = apr_pstrdup(cmd->pool, r);
new->flags = flags;