diff -ru haproxy-1.3.15.7/doc/configuration.txt haproxy-1.3.15.7-cur/doc/configuration.txt --- haproxy-1.3.15.7/doc/configuration.txt 2008-12-04 11:29:13.000000000 +0100 +++ haproxy-1.3.15.7-cur/doc/configuration.txt 2009-02-24 16:17:19.000000000 +0100 @@ -788,6 +788,19 @@ balance url_param [check_post []] + header The Http Header specified in argument will be looked up in + each HTTP request. + + With the "Host" header name, an optionnal use_domain_only + parameter is available, for reducing the hash algorithm to + the main domain part, eg for "haproxy.1wt.eu", only "1wt" + will be taken into consideration. + + Example : + balance header User-Agent + balance header Host + balance header Host use_domain_only + The definition of the load balancing algorithm is mandatory for a backend and limited to one per backend. @@ -795,6 +808,7 @@ balance roundrobin balance url_param userid balance url_param session_id check_post 64 + balance header Host Note: the following caveats and limitations on using the "check_post" extension with "url_param" must be considered : Seulement dans haproxy-1.3.15.7-cur/doc: configuration.txt~ diff -ru haproxy-1.3.15.7/include/types/backend.h haproxy-1.3.15.7-cur/include/types/backend.h --- haproxy-1.3.15.7/include/types/backend.h 2008-12-04 11:29:13.000000000 +0100 +++ haproxy-1.3.15.7-cur/include/types/backend.h 2009-02-24 16:04:16.000000000 +0100 @@ -43,6 +43,7 @@ #define BE_LB_ALGO_UH (BE_LB_PROP_L7 | 0x03) /* balance on URI hash */ #define BE_LB_ALGO_PH (BE_LB_PROP_L7 | 0x04) /* balance on URL parameter hash */ #define BE_LB_ALGO_LC (BE_LB_PROP_DYN | 0x05) /* fast weighted round-robin mode (dynamic) */ +#define BE_LB_ALGO_HH (BE_LB_PROP_L7 | 0x06) /* balance on Http Header value */ /* various constants */ diff -ru haproxy-1.3.15.7/include/types/proxy.h haproxy-1.3.15.7-cur/include/types/proxy.h --- haproxy-1.3.15.7/include/types/proxy.h 2008-12-04 11:29:13.000000000 +0100 +++ haproxy-1.3.15.7-cur/include/types/proxy.h 2009-02-24 16:04:16.000000000 +0100 @@ -166,6 +166,9 @@ 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 */ + char *header_name; /* name of the header parameter used for hashing */ + int header_len; /* strlen(header_name), computed only once */ + int header_match_domain; /* toggle use of special match function */ 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 -ru haproxy-1.3.15.7/src/backend.c haproxy-1.3.15.7-cur/src/backend.c --- haproxy-1.3.15.7/src/backend.c 2008-12-04 11:29:13.000000000 +0100 +++ haproxy-1.3.15.7-cur/src/backend.c 2009-02-24 16:04:16.000000000 +0100 @@ -1281,6 +1281,85 @@ return NULL; } +/* + * This function tries to find a running server for the proxy following + * the Header parameter hash method. It looks for a specific parameter in the + * URL and hashes it to compute the server ID. This is useful to optimize + * performance by avoiding bounces between servers in contexts where sessions + * are shared but cookies are not usable. If the parameter is not found, NULL + * is returned. If any server is found, it will be returned. If no valid server + * is found, NULL is returned. + */ +struct server *get_server_hh(struct session *s) +{ + unsigned long hash = 0; + struct http_txn *txn = &s->txn; + struct http_msg *msg = &txn->req; + struct proxy *px = s->be; + unsigned int plen = px->header_len; + unsigned long len; + struct hdr_ctx ctx; + const char *p; + + /* tot_weight appears to mean srv_count */ + if (px->lbprm.tot_weight == 0) + return NULL; + + if (px->lbprm.map.state & PR_MAP_RECALC) + recalc_server_map(px); + + ctx.idx = 0; + + /* if the message is chunked, we skip the chunk size, but use the value as len */ + http_find_header2(px->header_name, plen, msg->sol, &txn->hdr_idx, &ctx); + if ( ctx.idx ) { + /* Found a the header_name in the headers + we will compute the hash based on this value ctx.val */ + len = ctx.vlen; + p = (char *)ctx.line + ctx.val; + fprintf (stderr, "Found value for %s: '%.*s', length %i\n", + px->header_name, + (int)len, p, (int)len + ); + + fprintf (stderr, "Hashing on: "); + if (!px->header_match_domain) { + while (len) { + fprintf (stderr, "%c",*p); + hash = *p + (hash << 6) + (hash << 16) - hash; + len--; + p++; + } + } else { + p += len - 1; + int dohash = 0; + /* special computation, use only main domain name, not tld/host + going back from the end of string, start hashing at first + dot stop at next. + This is only compatible with 'Host' header, need a special + option to activate this + */ + while (len) { + if (*p == '.') { + if (!dohash) {dohash = 1;} + else { break; } + } else { + if (dohash) { + fprintf (stderr, "%c",*p); + hash = *p + (hash << 6) + (hash << 16) - hash; + } + } + len--; + p--; + } + } + + fprintf (stderr, "\n"); + return px->lbprm.map.srv[hash % px->lbprm.tot_weight]; + } + return NULL; +} + /* * This function applies the load-balancing algorithm to the session, as @@ -1400,6 +1479,19 @@ } } break; + case BE_LB_ALGO_HH: + /* Header Parameter hashing */ + s->srv = get_server_hh(s); + + if (!s->srv) { + /* parameter not found, fall back to round robin on the map */ + s->srv = get_server_rr_with_conns(s->be, s->prev_srv); + if (!s->srv) { + err = SRV_STATUS_FULL; + goto out; + } + } + break; default: /* unknown balancing algorithm */ err = SRV_STATUS_INTERNAL; @@ -2077,8 +2169,31 @@ curproxy->url_param_post_limit = 3; /* minimum example: S=3 or \r\nS=6& */ } } + else if (!strcmp(args[0], "header")) { + if (!*args[1]) { + snprintf(err, errlen, "'balance header' requires an http header field name."); + return -1; + } + curproxy->lbprm.algo &= ~BE_LB_ALGO; + curproxy->lbprm.algo |= BE_LB_ALGO_HH; + if (curproxy->header_name) + free(curproxy->header_name); + curproxy->header_name = strdup(args[1]); + curproxy->header_len = strlen(args[1]); + curproxy->header_match_domain = 0; + + if ( *args[2] ) { + if (strcmp(args[2], "use_domain_only") || + strcmp(args[1], "Host")) { + snprintf(err, errlen, "'balance header Host' only accepts use_domain_only modifier."); + return -1; + } + curproxy->header_match_domain = 1; + } + + } else { - snprintf(err, errlen, "'balance' only supports 'roundrobin', 'leastconn', 'source', 'uri' and 'url_param' options."); + snprintf(err, errlen, "'balance' only supports 'roundrobin', 'leastconn', 'source', 'uri', 'url_param' and 'header' options."); return -1; } return 0;