diff --git a/doc/configuration.txt b/doc/configuration.txt index 3564ad8eb..399bebb6d 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -745,6 +745,20 @@ balance url_param [check_post []] that changing a server's weight on the fly will have no effect. + This algorithm support two optional parameters "len" and + "depth", both followed by a positive integer number. These + options may be helpful when it is needed to balance servers + based on the beginning of the URI only. The "len" parameter + indicates that the algorithm should only consider that many + characters at the beginning of the URI to compute the hash. + Note that having "len" set to 1 rarely makes sense since most + URIs start with a leading "/". + + The "depth" parameter indicates the maximum directory depth + to be used to compute the hash. One level is counted for each + slash in the request. If both parameters are specified, the + evaluation stops when either is reached. + url_param The URL parameter specified in argument will be looked up in the query string of each HTTP GET request. @@ -783,9 +797,10 @@ balance url_param [check_post []] server's weight on the fly will have no effect. is an optional list of arguments which may be needed by some - algorithms. Right now, only the "url_param" algorithm supports - an optional argument. + algorithms. Right now, only "url_param" and "uri" support an + optional argument. + balance uri [len ] [depth ] balance url_param [check_post []] The definition of the load balancing algorithm is mandatory for a backend diff --git a/include/proto/backend.h b/include/proto/backend.h index 03fa518ca..aa27654f3 100644 --- a/include/proto/backend.h +++ b/include/proto/backend.h @@ -159,6 +159,7 @@ static inline struct server *get_server_uh(struct proxy *px, char *uri, int uri_ { unsigned long hash = 0; int c; + int slashes = 0; if (px->lbprm.tot_weight == 0) return NULL; @@ -166,10 +167,19 @@ static inline struct server *get_server_uh(struct proxy *px, char *uri, int uri_ if (px->lbprm.map.state & PR_MAP_RECALC) recalc_server_map(px); + if (px->uri_len_limit) + uri_len = MIN(uri_len, px->uri_len_limit); + while (uri_len--) { c = *uri++; - if (c == '?') + if (c == '/') { + slashes++; + if (slashes == px->uri_dirs_depth1) /* depth+1 */ + break; + } + else if (c == '?') break; + hash = c + (hash << 6) + (hash << 16) - hash; } diff --git a/include/types/proxy.h b/include/types/proxy.h index 091be57e2..fe69b0896 100644 --- a/include/types/proxy.h +++ b/include/types/proxy.h @@ -166,6 +166,8 @@ struct proxy { char *url_param_name; /* name of the URL parameter used for hashing */ int url_param_len; /* strlen(url_param_name), computed only once */ unsigned url_param_post_limit; /* if checking POST body for URI parameter, max body to wait for */ + int uri_len_limit; /* character limit for uri balancing algorithm */ + int uri_dirs_depth1; /* directories+1 (slashes) limit for uri balancing algorithm */ char *appsession_name; /* name of the cookie to look for */ int appsession_name_len; /* strlen(appsession_name), computed only once */ int appsession_len; /* length of the appsession cookie value to be used */ diff --git a/src/backend.c b/src/backend.c index 649756787..9ced724a4 100644 --- a/src/backend.c +++ b/src/backend.c @@ -1973,8 +1973,36 @@ int backend_parse_balance(const char **args, char *err, int errlen, struct proxy curproxy->lbprm.algo |= BE_LB_ALGO_SH; } else if (!strcmp(args[0], "uri")) { + int arg = 1; + curproxy->lbprm.algo &= ~BE_LB_ALGO; curproxy->lbprm.algo |= BE_LB_ALGO_UH; + + while (*args[arg]) { + if (!strcmp(args[arg], "len")) { + if (!*args[arg+1] || (atoi(args[arg+1]) <= 0)) { + snprintf(err, errlen, "'balance uri len' expects a positive integer (got '%s').", args[arg+1]); + return -1; + } + curproxy->uri_len_limit = atoi(args[arg+1]); + arg += 2; + } + else if (!strcmp(args[arg], "depth")) { + if (!*args[arg+1] || (atoi(args[arg+1]) <= 0)) { + snprintf(err, errlen, "'balance uri depth' expects a positive integer (got '%s').", args[arg+1]); + return -1; + } + /* hint: we store the position of the ending '/' (depth+1) so + * that we avoid a comparison while computing the hash. + */ + curproxy->uri_dirs_depth1 = atoi(args[arg+1]) + 1; + arg += 2; + } + else { + snprintf(err, errlen, "'balance uri' only accepts parameters 'len' and 'depth' (got '%s').", args[arg]); + return -1; + } + } } else if (!strcmp(args[0], "url_param")) { if (!*args[1]) { @@ -1987,7 +2015,7 @@ int backend_parse_balance(const char **args, char *err, int errlen, struct proxy free(curproxy->url_param_name); curproxy->url_param_name = strdup(args[1]); curproxy->url_param_len = strlen(args[1]); - if ( *args[2] ) { + if (*args[2]) { if (strcmp(args[2], "check_post")) { snprintf(err, errlen, "'balance url_param' only accepts check_post modifier."); return -1;