Hi,

I've found out that following configuration does not work as expected:

<Proxy balancer://a>
   ...
</Proxy>
<VirtualHost *:80>
    ProxyPass / balancer://a stickysession=JSESSIONID|jsessionid
</VirtualHost>

In this case, two proxy_balancers are created. The first one in Proxy section in the main config without stickysession and the second one in the vhost section with stickysession set.

Because of merge_proxy_config behaviour, the one from the main config is always preferred and therefore you cannot set stickysession (and other options) this way.

Attached patch fixes that by changing the merge strategy for balancers array to merge options set by ProxyPass.

I think we would need the same for proxy_worker too, but before I spent afternoon working on it, I wanted to ask, do you think this is the right way how to fix this?

Regards,
Jan Kaluza
Index: modules/proxy/mod_proxy.c
===================================================================
--- modules/proxy/mod_proxy.c	(revision 1644346)
+++ modules/proxy/mod_proxy.c	(working copy)
@@ -306,6 +306,7 @@
         }
         else
             balancer->s->sticky_separator = *val;
+        balancer->s->sticky_separator_set = 1;
     }
     else if (!strcasecmp(key, "nofailover")) {
         /* If set to 'on' the session will break
@@ -318,6 +319,7 @@
             balancer->s->sticky_force = 0;
         else
             return "failover must be On|Off";
+        balancer->s->sticky_force_set = 1;
     }
     else if (!strcasecmp(key, "timeout")) {
         /* Balancer timeout in seconds.
@@ -348,6 +350,7 @@
         if (provider) {
             balancer->lbmethod = provider;
             if (PROXY_STRNCPY(balancer->s->lbpname, val) == APR_SUCCESS) {
+                balancer->lbmethod_set = 1;
                 return NULL;
             }
             else {
@@ -367,6 +370,7 @@
             balancer->s->scolonsep = 0;
         else
             return "scolonpathdelim must be On|Off";
+        balancer->s->scolonsep_set = 1;
     }
     else if (!strcasecmp(key, "failonstatus")) {
         char *val_split;
@@ -397,6 +401,7 @@
             balancer->failontimeout = 0;
         else
             return "failontimeout must be On|Off";
+        balancer->failontimeout_set = 1;
     }
     else if (!strcasecmp(key, "nonce")) {
         if (!strcasecmp(val, "None")) {
@@ -407,6 +412,7 @@
                 return "Provided nonce is too large";
             }
         }
+        balancer->s->nonce_set = 1;
     }
     else if (!strcasecmp(key, "growth")) {
         ival = atoi(val);
@@ -413,6 +419,7 @@
         if (ival < 1 || ival > 100)   /* arbitrary limit here */
             return "growth must be between 1 and 100";
         balancer->growth = ival;
+        balancer->growth_set = 1;
     }
     else if (!strcasecmp(key, "forcerecovery")) {
         if (!strcasecmp(val, "on"))
@@ -421,6 +428,7 @@
             balancer->s->forcerecovery = 0;
         else
             return "forcerecovery must be On|Off";
+        balancer->s->forcerecovery_set = 1;
     }
     else {
         return "unknown Balancer parameter";
@@ -1272,6 +1280,89 @@
     return ps;
 }
 
+static apr_array_header_t *merge_balancers(apr_pool_t *p,
+                                           apr_array_header_t *base,
+                                           apr_array_header_t *overrides)
+{
+    proxy_balancer *b1;
+    proxy_balancer *b2;
+    proxy_balancer *copy;
+    int x, y, found;
+    apr_array_header_t *merged = apr_array_make(p, base->nelts,
+                                                sizeof(proxy_balancer));
+
+    /* Check if the balancer is defined in both override and base configs:
+     * a) If it is, merge the changes which can be done by ProxyPass.
+     * b) Otherwise, copy the balancer to merged array.
+     */
+    b2 = (proxy_balancer *) overrides->elts;
+    for (x = 0; x < overrides->nelts; x++) {
+        b1 = (proxy_balancer *) base->elts;
+        for (y = 0, found = 0; y < base->nelts; y++) {
+            if (b1->hash.def == b2->hash.def && b1->hash.fnv == b2->hash.fnv) {
+                if (b2->s->sticky && *b2->s->sticky) {
+                    PROXY_STRNCPY(b1->s->sticky_path, b2->s->sticky_path);
+                    PROXY_STRNCPY(b1->s->sticky, b2->s->sticky);
+                }
+                if (b2->s->sticky_separator_set) {
+                    b1->s->sticky_separator_set = b2->s->sticky_separator_set;
+                    b1->s->sticky_separator = b2->s->sticky_separator;
+                }
+                if (b2->s->timeout) {
+                    b1->s->timeout = b2->s->timeout;
+                }
+                if (b2->s->max_attempts_set) {
+                    b1->s->max_attempts_set = b2->s->max_attempts_set;
+                    b1->s->max_attempts = b2->s->max_attempts;
+                }
+                if (b2->lbmethod_set) {
+                    b1->lbmethod_set = b2->lbmethod_set;
+                    b1->lbmethod = b2->lbmethod;
+                    PROXY_STRNCPY(b1->s->lbpname, b2->s->lbpname);
+                }
+                if (b2->growth_set) {
+                    b1->growth_set = b2->growth_set;
+                    b1->growth = b2->growth;
+                }
+                if (b2->failontimeout_set) {
+                    b1->failontimeout_set = b2->failontimeout_set;
+                    b1->failontimeout = b2->failontimeout;
+                }
+                if (b2->s->nonce_set) {
+                    b1->s->nonce_set = b2->s->nonce_set;
+                    PROXY_STRNCPY(b1->s->nonce, b2->s->nonce);
+                }
+                if (b2->s->sticky_force_set) {
+                    b1->s->sticky_force_set = b2->s->sticky_force_set;
+                    b1->s->sticky_force = b2->s->sticky_force;
+                }
+                if (b2->s->scolonsep_set) {
+                    b1->s->scolonsep_set = b2->s->scolonsep_set;
+                    b1->s->scolonsep = b2->s->scolonsep;
+                }
+                if (b2->s->forcerecovery_set) {
+                    b1->s->forcerecovery_set = b2->s->forcerecovery_set;
+                    b1->s->forcerecovery = b2->s->forcerecovery;
+                }
+                if (!apr_is_empty_array(b2->errstatuses)) {
+                    apr_array_cat(b1->errstatuses, b2->errstatuses);
+                }
+
+                *(proxy_balancer *)apr_array_push(merged) = *b1;
+                found = 1;
+                break;
+            }
+            b1++;
+        }
+        if (!found) {
+            *(proxy_balancer *)apr_array_push(merged) = *b2;
+        }
+        b2++;
+    }
+
+    return merged;
+}
+
 static void * merge_proxy_config(apr_pool_t *p, void *basev, void *overridesv)
 {
     proxy_server_conf *ps = apr_pcalloc(p, sizeof(proxy_server_conf));
@@ -1296,7 +1387,7 @@
     ps->dirconn = apr_array_append(p, base->dirconn, overrides->dirconn);
     if (ps->inherit || ps->ppinherit) {
         ps->workers = apr_array_append(p, base->workers, overrides->workers);
-        ps->balancers = apr_array_append(p, base->balancers, overrides->balancers);
+        ps->balancers = merge_balancers(p, base->balancers, overrides->balancers);
     }
     else {
         ps->workers = overrides->workers;
Index: modules/proxy/mod_proxy.h
===================================================================
--- modules/proxy/mod_proxy.h	(revision 1644346)
+++ modules/proxy/mod_proxy.h	(working copy)
@@ -443,6 +443,11 @@
     unsigned int    inactive:1;
     unsigned int    forcerecovery:1;
     char      sticky_separator;                                /* separator for sessionid/route */
+    unsigned int    forcerecovery_set:1;
+    unsigned int    scolonsep_set:1;
+    unsigned int    sticky_force_set:1; 
+    unsigned int    nonce_set:1;
+    unsigned int    sticky_separator_set:1;
 } proxy_balancer_shared;
 
 #define ALIGNED_PROXY_BALANCER_SHARED_SIZE (APR_ALIGN_DEFAULT(sizeof(proxy_balancer_shared)))
@@ -463,6 +468,9 @@
     void            *context;    /* general purpose storage */
     proxy_balancer_shared *s;    /* Shared data */
     int failontimeout;           /* Whether to mark a member in Err if IO timeout occurs */
+    unsigned int failontimeout_set:1;
+    unsigned int growth_set:1;
+    unsigned int lbmethod_set:1;
 };
 
 struct proxy_balancer_method {

Reply via email to