Index: docs/manual/mod/mod_proxy.xml =================================================================== --- docs/manual/mod/mod_proxy.xml (revision 541773) +++ docs/manual/mod/mod_proxy.xml (working copy) @@ -720,6 +720,38 @@ +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 proxied server Index: CHANGES =================================================================== --- CHANGES (revision 541773) +++ CHANGES (working copy) @@ -1,6 +1,9 @@ -*- coding: utf-8 -*- Changes with Apache 2.2.5 + *) mod_proxy: Added ProxyPassMatch directive, which is similar + to ProxyPass but takes a regex local path prefix. [Jim Jagielski] + *) mod_cache: Let Cache-Control max-age set the expiration of the cached representation if Expires is not set. [Justin Erenkrantz] Index: modules/proxy/mod_proxy.c =================================================================== --- modules/proxy/mod_proxy.c (revision 541773) +++ modules/proxy/mod_proxy.c (working copy) @@ -432,6 +432,8 @@ (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 @@ */ 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 * - 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 @@ 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 @@ 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 @@ }; 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; @@ -1123,6 +1177,19 @@ } 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) { proxy_dir_conf *conf = dconf; @@ -1700,8 +1767,10 @@ "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"), AP_INIT_TAKE2("ProxyPassReverseCookiePath", cookie_path, NULL, Index: modules/proxy/mod_proxy.h =================================================================== --- modules/proxy/mod_proxy.h (revision 541773) +++ modules/proxy/mod_proxy.h (working copy) @@ -109,6 +109,7 @@ struct proxy_alias { const char *real; const char *fake; + ap_regex_t *regex; }; struct dirconn_entry {