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;