From: Jan Kaluža Date: Fri, 11 Jul 2014 10:36:15 +0000 (+0000) Subject: mod_proxy: add ap_proxy_define_match_worker() and use it for ProxyPassMatch X-Git-Tag: 2.5.0-alpha~3987 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=c0a52f109dcb9b93cd8aca9bfedb06720fa3a253;p=apache mod_proxy: add ap_proxy_define_match_worker() and use it for ProxyPassMatch and ProxyMatch section to distinguish between normal workers and workers with regex substitutions in the name. Implement handling of such workers in ap_proxy_get_worker(). PR 43513 git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1609680 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/modules/proxy/mod_proxy.c b/modules/proxy/mod_proxy.c index eeff4606c1..9beffacb6c 100644 --- a/modules/proxy/mod_proxy.c +++ b/modules/proxy/mod_proxy.c @@ -1647,15 +1647,30 @@ static const char * new->balancer = balancer; } else { - proxy_worker *worker = ap_proxy_get_worker(cmd->temp_pool, NULL, conf, de_socketfy(cmd->pool, r)); + proxy_worker *worker = ap_proxy_get_worker(cmd->temp_pool, NULL, conf, new->real); int reuse = 0; if (!worker) { - const char *err = ap_proxy_define_worker(cmd->pool, &worker, NULL, conf, r, 0); + const char *err; + if (use_regex) { + err = ap_proxy_define_match_worker(cmd->pool, &worker, NULL, + conf, r, 0); + } + else { + err = ap_proxy_define_worker(cmd->pool, &worker, NULL, + conf, r, 0); + } if (err) return apr_pstrcat(cmd->temp_pool, "ProxyPass ", err, NULL); PROXY_COPY_CONF_PARAMS(worker, conf); - } else { + } + else if ((use_regex != 0) ^ (worker->s->is_name_matchable)) { + return apr_pstrcat(cmd->temp_pool, "ProxyPass/ and " + "ProxyPassMatch/ can't be used " + "altogether with the same worker name ", + "(", worker->s->name, ")", NULL); + } + else { reuse = 1; ap_log_error(APLOG_MARK, APLOG_INFO, 0, cmd->server, APLOGNO(01145) "Sharing worker '%s' instead of creating new worker '%s'", @@ -2270,6 +2285,7 @@ static const char *proxysection(cmd_parms *cmd, void *mconfig, const char *arg) char *word, *val; proxy_balancer *balancer = NULL; proxy_worker *worker = NULL; + int use_regex = 0; const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE); proxy_server_conf *sconf = @@ -2308,6 +2324,7 @@ static const char *proxysection(cmd_parms *cmd, void *mconfig, const char *arg) if (!r) { return "Regex could not be compiled"; } + use_regex = 1; } /* initialize our config and fetch it */ @@ -2354,12 +2371,24 @@ static const char *proxysection(cmd_parms *cmd, void *mconfig, const char *arg) worker = ap_proxy_get_worker(cmd->temp_pool, NULL, sconf, de_socketfy(cmd->temp_pool, (char*)conf->p)); if (!worker) { - err = ap_proxy_define_worker(cmd->pool, &worker, NULL, - sconf, conf->p, 0); + if (use_regex) { + err = ap_proxy_define_match_worker(cmd->pool, &worker, NULL, + sconf, conf->p, 0); + } + else { + err = ap_proxy_define_worker(cmd->pool, &worker, NULL, + sconf, conf->p, 0); + } if (err) return apr_pstrcat(cmd->temp_pool, thiscmd->name, " ", err, NULL); } + else if ((use_regex != 0) ^ (worker->s->is_name_matchable)) { + return apr_pstrcat(cmd->temp_pool, "ProxyPass/ and " + "ProxyPassMatch/ can't be used " + "altogether with the same worker name ", + "(", worker->s->name, ")", NULL); + } } if (worker == NULL && balancer == NULL) { return apr_pstrcat(cmd->pool, thiscmd->name, diff --git a/modules/proxy/mod_proxy.h b/modules/proxy/mod_proxy.h index b6aafd9246..2f4e5ef644 100644 --- a/modules/proxy/mod_proxy.h +++ b/modules/proxy/mod_proxy.h @@ -398,6 +398,7 @@ typedef struct { unsigned int keepalive_set:1; unsigned int disablereuse_set:1; unsigned int was_malloced:1; + unsigned int is_name_matchable:1; } proxy_worker_shared; #define ALIGNED_PROXY_WORKER_SHARED_SIZE (APR_ALIGN_DEFAULT(sizeof(proxy_worker_shared))) @@ -644,6 +645,24 @@ PROXY_DECLARE(char *) ap_proxy_define_worker(apr_pool_t *p, const char *url, int do_malloc); +/** + * Define and Allocate space for the ap_strcmp_match()able worker to proxy + * configuration. + * @param p memory pool to allocate worker from + * @param worker the new worker + * @param balancer the balancer that the worker belongs to + * @param conf current proxy server configuration + * @param url url containing worker name (produces match pattern) + * @param do_malloc true if shared struct should be malloced + * @return error message or NULL if successful (*worker is new worker) + */ +PROXY_DECLARE(char *) ap_proxy_define_match_worker(apr_pool_t *p, + proxy_worker **worker, + proxy_balancer *balancer, + proxy_server_conf *conf, + const char *url, + int do_malloc); + /** * Share a defined proxy worker via shm * @param worker worker to be shared diff --git a/modules/proxy/proxy_util.c b/modules/proxy/proxy_util.c index 4d91a21c0e..d1b6352d5f 100644 --- a/modules/proxy/proxy_util.c +++ b/modules/proxy/proxy_util.c @@ -1509,6 +1509,44 @@ PROXY_DECLARE(char *) ap_proxy_worker_name(apr_pool_t *p, return apr_pstrcat(p, "unix:", worker->s->uds_path, "|", worker->s->name, NULL); } +/* + * Taken from ap_strcmp_match() : + * Match = 0, NoMatch = 1, Abort = -1, Inval = -2 + * Based loosely on sections of wildmat.c by Rich Salz + * Hmmm... shouldn't this really go component by component? + * + * Adds handling of the "\" => "" unescaping. + */ +static int ap_proxy_strcmp_ematch(const char *str, const char *expected) +{ + apr_size_t x, y; + + for (x = 0, y = 0; expected[y]; ++y, ++x) { + if ((!str[x]) && (expected[y] != '$' || !apr_isdigit(expected[y + 1]))) + return -1; + if (expected[y] == '$' && apr_isdigit(expected[y + 1])) { + while (expected[y] == '$' && apr_isdigit(expected[y + 1])) + y += 2; + if (!expected[y]) + return 0; + while (str[x]) { + int ret; + if ((ret = ap_proxy_strcmp_ematch(&str[x++], &expected[y])) != 1) + return ret; + } + return -1; + } + else if (expected[y] == '\\') { + /* NUL is an invalid char! */ + if (!expected[++y]) + return -2; + } + if (str[x] != expected[y]) + return 1; + } + return (str[x] != '\0'); +} + PROXY_DECLARE(proxy_worker *) ap_proxy_get_worker(apr_pool_t *p, proxy_balancer *balancer, proxy_server_conf *conf, @@ -1569,11 +1607,15 @@ PROXY_DECLARE(proxy_worker *) ap_proxy_get_worker(apr_pool_t *p, if ( ((worker_name_length = strlen(worker->s->name)) <= url_length) && (worker_name_length >= min_match) && (worker_name_length > max_match) - && (strncmp(url_copy, worker->s->name, worker_name_length) == 0) ) { + && (worker->s->is_name_matchable + || strncmp(url_copy, worker->s->name, + worker_name_length) == 0) + && (!worker->s->is_name_matchable + || ap_proxy_strcmp_ematch(url_copy, + worker->s->name) == 0) ) { max_worker = worker; max_match = worker_name_length; } - } } else { worker = (proxy_worker *)conf->workers->elts; @@ -1581,7 +1623,12 @@ PROXY_DECLARE(proxy_worker *) ap_proxy_get_worker(apr_pool_t *p, if ( ((worker_name_length = strlen(worker->s->name)) <= url_length) && (worker_name_length >= min_match) && (worker_name_length > max_match) - && (strncmp(url_copy, worker->s->name, worker_name_length) == 0) ) { + && (worker->s->is_name_matchable + || strncmp(url_copy, worker->s->name, + worker_name_length) == 0) + && (!worker->s->is_name_matchable + || ap_proxy_strcmp_ematch(url_copy, + worker->s->name) == 0) ) { max_worker = worker; max_match = worker_name_length; } @@ -1703,6 +1750,7 @@ PROXY_DECLARE(char *) ap_proxy_define_worker(apr_pool_t *p, wshared->hash.def = ap_proxy_hashfunc(wshared->name, PROXY_HASHFUNC_DEFAULT); wshared->hash.fnv = ap_proxy_hashfunc(wshared->name, PROXY_HASHFUNC_FNV); wshared->was_malloced = (do_malloc != 0); + wshared->is_name_matchable = 0; if (sockpath) { if (PROXY_STRNCPY(wshared->uds_path, sockpath) != APR_SUCCESS) { return apr_psprintf(p, "worker uds path (%s) too long", sockpath); @@ -1722,6 +1770,24 @@ PROXY_DECLARE(char *) ap_proxy_define_worker(apr_pool_t *p, return NULL; } +PROXY_DECLARE(char *) ap_proxy_define_match_worker(apr_pool_t *p, + proxy_worker **worker, + proxy_balancer *balancer, + proxy_server_conf *conf, + const char *url, + int do_malloc) +{ + char *err; + + err = ap_proxy_define_worker(p, worker, balancer, conf, url, do_malloc); + if (err) { + return err; + } + + (*worker)->s->is_name_matchable = 1; + return NULL; +} + /* * Create an already defined worker and free up memory */