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