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 {