On 04/06/2007 01:13 PM, Georg von Zezschwitz wrote: > Jim Jagielski wrote: > >>> >>> If we state that the evaluation takes place in the occurence of >>> stickysession attributes >>> and suggest >>> >>> stickysession=Cookie:JSESSIONID stickysession=Path:;jsessionid to >>> the user >>> >>> it will perform faster in average. >>> >>> As I promised to write the patch, I would do it the way Jim suggested >>> it for backward >>> compatibility, however I would also add a table "sticky_type" >>> containing the "Cookie vs. >>> Path vs. Env"-prefix (in a parsed way) to the balancer struct. >>> >>> Is this OK for everybody? >>> >> >> Patch for trunk... > > > Hi, > > attached is the patch for trunk with documentation & Co. > > Could anybody review it & commit?
Many thanks for sending the patch and my apologies that reviewing it took that long. Please find my comments below. Regards Rüdiger Throughout the code there are a number of code style issues that should be fixed. Most of them are related to missing spaces before or after assignments or operators. I do not mention them explicitly in my review later. Please have a look at http://httpd.apache.org/dev/styleguide.html. Index: docs/manual/mod/mod_proxy.xml =================================================================== --- docs/manual/mod/mod_proxy.xml (revision 526077) +++ docs/manual/mod/mod_proxy.xml (working copy) @@ -707,9 +707,19 @@ </td></tr> <tr><td>stickysession</td> <td>-</td> - <td>Balancer sticky session name. The value is usually set to something - like <code>JSESSIONID</code> or <code>PHPSESSIONID</code>, - and it depends on the backend application server that support sessions. + <td>Balancer sticky session name. Multiple definitions are possible and + are interpreted in the sequence of their definition. The + value can be preceeded with a specification <code>Cookie</code>, + <code>Path</code> or <code>Env</code> to restrict the search. + Without this specification, the identifier is searched in the URL path + and then in the cookie. The value is usually set to something + like <code>JSESSIONID</code> or <code>PHPSESSIONID</code>, e.g. + <br/><indent> + <code>stickysession=Cookie:JSESSIONID + stickysession=Path:;jsessionid</code> + </indent> + for Java Servlets and depends on the backend application server + that support sessions. I think the examples should be split into two separate sentences: One for the simple case (no specification) for which PHPSESSIONID is a good example and one for the more complex case (two settings with different specifications) for which Java Servlets are a good example. Index: modules/proxy/mod_proxy_balancer.c =================================================================== --- modules/proxy/mod_proxy_balancer.c (revision 526077) +++ modules/proxy/mod_proxy_balancer.c (working copy) @@ -581,6 +605,30 @@ } } +static void print_balancer_sticky(request_rec *r, + apr_array_header_t *sticky) +{ + int i; + struct proxy_sticky_entry *entries; + + if (sticky==NULL) + return; + entries = (struct proxy_sticky_entry *) sticky->elts; + for (i = 0; i < sticky->nelts; i++) { + if (i>0) + ap_rputs (" ", r); + switch (entries[i].method) { + case PROXY_STICKY_COOKIE: + ap_rputs ("Cookie:", r); break; + case PROXY_STICKY_PATH: + ap_rputs ("Path:", r); break; + case PROXY_STICKY_ENV: + ap_rputs ("Env:", r); break; Style + } + ap_rputs (entries[i].name, r); + } +} + /* Manages the loadfactors and member status */ static int balancer_handler(request_rec *r) @@ -645,10 +693,30 @@ if (bsel) { const char *val; if ((val = apr_table_get(params, "ss"))) { - if (strlen(val)) - bsel->sticky = apr_pstrdup(conf->pool, val); - else - bsel->sticky = NULL; + char *tok_cntx; + bsel->sticky = apr_array_make(conf->pool, 1, + sizeof (struct proxy_sticky_entry)); + char *v = apr_strtok(apr_pstrdup(r->pool, val), "+", &tok_cntx); This is not allowed in ANSI C: Declarations of variables need to be at the beginning of a block. Better use ap_strchr here. + while (v!=NULL) { + struct proxy_sticky_entry * entry = + (struct proxy_sticky_entry *) apr_array_push(bsel->sticky); + const char *colon_pos = strchr (v, ':'); + entry->method = PROXY_STICKY_COOKIE | PROXY_STICKY_PATH; + if (colon_pos!=NULL) { + while (*++colon_pos==' ') + continue; + entry->name = apr_pstrdup(conf->pool, colon_pos); + if (!strncasecmp ("cookie:", v, 7)) + entry->method = PROXY_STICKY_COOKIE; + else if (!strncasecmp ("path:", v, 5)) + entry->method = PROXY_STICKY_PATH; + else if (!strncasecmp ("env:", v, 4)) + entry->method = PROXY_STICKY_ENV; + } else { + entry->name = apr_pstrdup(conf->pool, v); + } + v = apr_strtok(NULL, "+", &tok_cntx); + } } if ((val = apr_table_get(params, "tm"))) { int ival = atoi(val); Index: modules/proxy/mod_proxy.c =================================================================== --- modules/proxy/mod_proxy.c (revision 526077) +++ modules/proxy/mod_proxy.c (working copy) @@ -272,14 +272,36 @@ const char *key, const char *val) { - int ival; if (!strcasecmp(key, "stickysession")) { - /* Balancer sticky session name. - * Set to something like JSESSIONID or - * PHPSESSIONID, etc.., - */ - balancer->sticky = apr_pstrdup(p, val); + /* Balancer sticky session name. + * Set to something like JSESSIONID or + * PHPSESSIONID, etc.., + */ + struct proxy_sticky_entry *entry; + + if (balancer->sticky==NULL) + balancer->sticky = + apr_array_make(p, 1, sizeof (struct proxy_sticky_entry)); + entry = (struct proxy_sticky_entry *) apr_array_push(balancer->sticky); + const char *colon_pos = strchr (val, ':'); This is not allowed in ANSI C: Declarations of variables need to be at the beginning of a block. Better use ap_strchr_c here. + if (colon_pos!=NULL) { + while (*++colon_pos==' ') + continue; + entry->name = apr_pstrdup(p, colon_pos); + if (!strncasecmp ("cookie:", val, 7)) + entry->method = PROXY_STICKY_COOKIE; + else if (!strncasecmp ("path:", val, 5)) + entry->method = PROXY_STICKY_PATH; + else if (!strncasecmp ("env:", val, 4)) + entry->method = PROXY_STICKY_ENV; + else + return "stickysession must be preceeded by Cookie|Path|Env " + "followed by a colon"; + } else { + entry->method = PROXY_STICKY_COOKIE | PROXY_STICKY_PATH; + entry->name = apr_pstrdup(p, val); + } This looks very similar to the logic in mod_proxy_balancer.c. Does it make sense to duplicate the code? Shouldn't this be moved to proxy_util.c? @@ -324,7 +346,7 @@ return "unknown lbmethod"; } else { - return "unknown Balancer parameter"; + return apr_pstrcat (p, "unknown Balancer parameter ", key); The last parameter to apr_pstrcat needs to be NULL. } return NULL; } @@ -1152,7 +1173,8 @@ } else *val++ = '\0'; - apr_table_setn(params, word, val); >From my personal point of view I would prefer staying with the table and just do apr_table_addn when it comes to stickysession to have this key in the table multiple times. + * (const char**) (apr_array_push (params)) = word; + * (const char**) (apr_array_push (params)) = val; This style looks nasty and may break on some compilers. Please use a temporary variable to save the return value of apr_array_push. } }; @@ -1177,9 +1198,20 @@ if (err) return apr_pstrcat(cmd->temp_pool, "ProxyPass ", err, NULL); } - for (i = 0; i < arr->nelts; i++) { - const char *err = set_balancer_param(conf, cmd->pool, balancer, elts[i].key, - elts[i].val); + else { + if (params->nelts > 0 && + (balancer->sticky || balancer->sticky_force || + balancer->max_attempts_set || balancer->timeout)) { + ap_log_error(APLOG_MARK, APLOG_WARNING, 0, cmd->server, + "repeated parameter definition for balancer %s " + "overwrites previous definitions", + balancer->name); + balancer->sticky = NULL; Why resetting balancer->sticky here? It is not clear that the contents of balancer->sticky is changed. It makes sense to reset it if we have at least one "stickysession" parameter inside of params->elts so that we cleanly overwrite all the "stickysession" stuff then. Index: modules/proxy/mod_proxy.h =================================================================== --- modules/proxy/mod_proxy.h (revision 526077) +++ modules/proxy/mod_proxy.h (working copy) @@ -373,6 +373,15 @@ void *context; /* general purpose storage */ }; +struct proxy_sticky_entry { + const char *name; /* key to look for, e.g. JSESSIONID */ + int method; /* where to search, e.g. PROXY_STICKY_ENV */ +}; I would add a typedef for this struct like for the other structs here.