From 34ebfb1f08ed76326d5250629649d02a4c6aa76f Mon Sep 17 00:00:00 2001 From: Jim Jagielski Date: Tue, 17 Jul 2007 17:22:35 +0000 Subject: [PATCH] *) mod_proxy: Added ProxyPassMatch directive, which is similar to ProxyPass but takes a regex local path prefix. [Jim Jagielski] git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.2.x@556976 13f79535-47bb-0310-9956-ffa450edef68 --- CHANGES | 3 + STATUS | 8 --- docs/manual/mod/mod_proxy.xml | 32 +++++++++++ modules/proxy/mod_proxy.c | 105 ++++++++++++++++++++++++++++------ modules/proxy/mod_proxy.h | 1 + 5 files changed, 123 insertions(+), 26 deletions(-) diff --git a/CHANGES b/CHANGES index 6298dc1fb0e..86918701f94 100644 --- a/CHANGES +++ b/CHANGES @@ -21,6 +21,9 @@ Changes with Apache 2.2.5 values could previously point to cleaned up storage. PR 41551. [Davi Arnaut ] + *) mod_proxy: Added ProxyPassMatch directive, which is similar + to ProxyPass but takes a regex local path prefix. [Jim Jagielski] + *) mod_cache: Do not set Date or Expires when they are missing from the original response or are invalid. [Justin Erenkrantz] diff --git a/STATUS b/STATUS index 56cdbe212c1..63b62d01e4d 100644 --- a/STATUS +++ b/STATUS @@ -77,14 +77,6 @@ RELEASE SHOWSTOPPERS: PATCHES ACCEPTED TO BACKPORT FROM TRUNK: [ start all new proposals below, under PATCHES PROPOSED. ] - * mod_proxy: Add in ProxyPassMatch directive, that allows - ProxyPass to take a regex. - Trunk version of patch: - http://svn.apache.org/viewvc?view=rev&revision=537429 - http://svn.apache.org/viewvc?view=rev&revision=537599 - 2.2.x version of patch: - http://people.apache.org/~jim/patches/ppmatch.txt - +1: jim, jfclere, mturk PATCHES PROPOSED TO BACKPORT FROM TRUNK: diff --git a/docs/manual/mod/mod_proxy.xml b/docs/manual/mod/mod_proxy.xml index b8df3ed2ef5..cedd7694348 100644 --- a/docs/manual/mod/mod_proxy.xml +++ b/docs/manual/mod/mod_proxy.xml @@ -733,6 +733,38 @@ expressions + +ProxyPassMatch +Maps remote servers into the local server URL-space using regular expressions +ProxyPassMatch [regex] !|url [key=value + [key=value ...]] +server configvirtual host +directory + + + +

This directive is equivalent to ProxyPass, + but makes use of regular expressions, instead of simple prefix matching. The + supplied regular expression is matched against the url, and if it + matches, the server will substitute any parenthesized matches into the given + string and use it as a new url.

+ +

Suppose the local server has address http://example.com/; + then

+ + + ProxyPassMatch ^(/.*\.gif)$ http://backend.example.com$1 + + +

will cause a local request for + http://example.com/mirror/foo/bar.gif to be internally converted + into a proxy request to http://backend.example.com/foo/bar.gif.

+ +

The ! directive is useful in situations where you don't want + to reverse-proxy a subdirectory.

+
+
+ ProxyPassReverse Adjusts the URL in HTTP response headers sent from a reverse diff --git a/modules/proxy/mod_proxy.c b/modules/proxy/mod_proxy.c index 93524a0827c..63a4c98eeb0 100644 --- a/modules/proxy/mod_proxy.c +++ b/modules/proxy/mod_proxy.c @@ -432,6 +432,8 @@ static int proxy_trans(request_rec *r) (proxy_server_conf *) ap_get_module_config(sconf, &proxy_module); int i, len; struct proxy_alias *ent = (struct proxy_alias *) conf->aliases->elts; + ap_regmatch_t regm[AP_MAX_REG_MATCH]; + char *found = NULL; if (r->proxyreq) { /* someone has already set up the proxy, it was possibly ourselves @@ -446,19 +448,53 @@ static int proxy_trans(request_rec *r) */ for (i = 0; i < conf->aliases->nelts; i++) { - len = alias_match(r->uri, ent[i].fake); + if (ent[i].regex) { + if (!ap_regexec(ent[i].regex, r->uri, AP_MAX_REG_MATCH, regm, 0)) { + if ((ent[i].real[0] == '!') && (ent[i].real[1] == '\0')) { + return DECLINED; + } + found = ap_pregsub(r->pool, ent[i].real, r->uri, AP_MAX_REG_MATCH, + regm); + /* 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, ent[i].real)) { + found = apr_pstrcat(r->pool, "proxy:", found, NULL); + } + else { + found = apr_pstrcat(r->pool, "proxy:", ent[i].real, r->uri, + NULL); + } + } + } + else { + len = alias_match(r->uri, ent[i].fake); - if (len > 0) { - if ((ent[i].real[0] == '!') && (ent[i].real[1] == 0)) { - return DECLINED; - } + if (len > 0) { + if ((ent[i].real[0] == '!') && (ent[i].real[1] == '\0')) { + return DECLINED; + } - r->filename = apr_pstrcat(r->pool, "proxy:", ent[i].real, - r->uri + len, NULL); - r->handler = "proxy-server"; - r->proxyreq = PROXYREQ_REVERSE; - return OK; - } + found = apr_pstrcat(r->pool, "proxy:", ent[i].real, + r->uri + len, NULL); + } + } + if (found) { + r->filename = found; + r->handler = "proxy-server"; + r->proxyreq = PROXYREQ_REVERSE; + return OK; + } } return DECLINED; } @@ -1031,7 +1067,7 @@ static const char * } static const char * - add_pass(cmd_parms *cmd, void *dummy, const char *arg) + add_pass(cmd_parms *cmd, void *dummy, const char *arg, int is_regex) { server_rec *s = cmd->server; proxy_server_conf *conf = @@ -1044,11 +1080,20 @@ static const char * const apr_array_header_t *arr; const apr_table_entry_t *elts; int i; + int use_regex = is_regex; while (*arg) { word = ap_getword_conf(cmd->pool, &arg); - if (!f) + if (!f) { + if (!strcmp(word, "~")) { + if (is_regex) { + return "ProxyPassMatch invalid syntax ('~' usage)."; + } + use_regex = 1; + continue; + } f = word; + } else if (!r) r = word; else { @@ -1056,16 +1101,16 @@ static const char * if (!val) { if (cmd->path) { if (*r == '/') { - return "ProxyPass can not have a path when defined in " + return "ProxyPass|ProxyPassMatch can not have a path when defined in " "a location."; } else { - return "Invalid ProxyPass parameter. Parameter must " + return "Invalid ProxyPass|ProxyPassMatch parameter. Parameter must " "be in the form 'key=value'."; } } else { - return "Invalid ProxyPass parameter. Parameter must be " + return "Invalid ProxyPass|ProxyPassMatch parameter. Parameter must be " "in the form 'key=value'."; } } @@ -1076,11 +1121,20 @@ static const char * }; if (r == NULL) - return "ProxyPass needs a path when not defined in a location"; + return "ProxyPass|ProxyPassMatch needs a path when not defined in a location"; new = apr_array_push(conf->aliases); new->fake = apr_pstrdup(cmd->pool, f); new->real = apr_pstrdup(cmd->pool, r); + if (use_regex) { + new->regex = ap_pregcomp(cmd->pool, f, AP_REG_EXTENDED); + if (new->regex == NULL) + return "Regular expression could not be compiled."; + } + else { + new->regex = NULL; + } + if (r[0] == '!' && r[1] == '\0') return NULL; @@ -1122,6 +1176,19 @@ static const char * return NULL; } +static const char * + add_pass_noregex(cmd_parms *cmd, void *dummy, const char *arg) +{ + return add_pass(cmd, dummy, arg, 0); +} + +static const char * + add_pass_regex(cmd_parms *cmd, void *dummy, const char *arg) +{ + return add_pass(cmd, dummy, arg, 1); +} + + static const char * add_pass_reverse(cmd_parms *cmd, void *dconf, const char *f, const char *r) { @@ -1700,7 +1767,9 @@ static const command_rec proxy_cmds[] = "a scheme, partial URL or '*' and a proxy server"), AP_INIT_TAKE2("ProxyRemoteMatch", add_proxy_regex, NULL, RSRC_CONF, "a regex pattern and a proxy server"), - AP_INIT_RAW_ARGS("ProxyPass", add_pass, NULL, RSRC_CONF|ACCESS_CONF, + AP_INIT_RAW_ARGS("ProxyPass", add_pass_noregex, NULL, RSRC_CONF|ACCESS_CONF, + "a virtual path and a URL"), + AP_INIT_RAW_ARGS("ProxyPassMatch", add_pass_regex, NULL, RSRC_CONF|ACCESS_CONF, "a virtual path and a URL"), AP_INIT_TAKE12("ProxyPassReverse", add_pass_reverse, NULL, RSRC_CONF|ACCESS_CONF, "a virtual path and a URL for reverse proxy behaviour"), diff --git a/modules/proxy/mod_proxy.h b/modules/proxy/mod_proxy.h index 12659e7defe..e7879525611 100644 --- a/modules/proxy/mod_proxy.h +++ b/modules/proxy/mod_proxy.h @@ -109,6 +109,7 @@ struct proxy_remote { struct proxy_alias { const char *real; const char *fake; + ap_regex_t *regex; }; struct dirconn_entry { -- 2.47.3