]> granicus.if.org Git - apache/commitdiff
mod_proxy: add ap_proxy_define_match_worker() and use it for ProxyPassMatch
authorJan Kaluža <jkaluza@apache.org>
Fri, 11 Jul 2014 10:36:15 +0000 (10:36 +0000)
committerJan Kaluža <jkaluza@apache.org>
Fri, 11 Jul 2014 10:36:15 +0000 (10:36 +0000)
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

modules/proxy/mod_proxy.c
modules/proxy/mod_proxy.h
modules/proxy/proxy_util.c

index eeff4606c126e5b8bd383875406ccb04e8a9456a..9beffacb6c150ca3b2242c358a7d03f90b637afc 100644 (file)
@@ -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/<Proxy> and "
+                               "ProxyPassMatch/<ProxyMatch> 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/<Proxy> and "
+                                   "ProxyPassMatch/<ProxyMatch> 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,
index b6aafd9246d53c82b09cee3cda5335f3c9c6316d..2f4e5ef6447ec1a640cc98b962949f13021783d6 100644 (file)
@@ -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
index 4d91a21c0e3aea9a18b82e7f5d65f379d1da69bc..d1b6352d5f0cb2302c77dae1faaa19ea4c0a6cb9 100644 (file)
@@ -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 "\<any>" => "<any>" 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
  */