[MEDIUM] add support for URI hash depth and length limits
This patch adds two optional arguments "len" and "depth" to
"balance uri". They are used to limit the length in characters
of the analysis, as well as the number of directory components
it applies to.
diff --git a/doc/configuration.txt b/doc/configuration.txt
index 3564ad8..399bebb 100644
--- a/doc/configuration.txt
+++ b/doc/configuration.txt
@@ -745,6 +745,20 @@
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 @@
server's weight on the fly will have no effect.
<arguments> 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 <len>] [depth <depth>]
balance url_param <param> [check_post [<max_wait>]]
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 03fa518..aa27654 100644
--- a/include/proto/backend.h
+++ b/include/proto/backend.h
@@ -159,6 +159,7 @@
{
unsigned long hash = 0;
int c;
+ int slashes = 0;
if (px->lbprm.tot_weight == 0)
return NULL;
@@ -166,10 +167,19 @@
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 091be57..fe69b08 100644
--- a/include/types/proxy.h
+++ b/include/types/proxy.h
@@ -166,6 +166,8 @@
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 6497567..9ced724 100644
--- a/src/backend.c
+++ b/src/backend.c
@@ -1973,8 +1973,36 @@
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 @@
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;