Craig a écrit :
> Hi,
>
> is it possible to "balance source" based on a X-Forwarded-For header?
> That's a feature I'd very much like to use, because I'm running a squid
> cache as reverse proxy on the same machine as ha-proxy and the squid
> forwards all requests to ha-proxy, which then does the load-balancing -
> which won't work based on source, because it's always 127.0.0.1.
> I've searched the docs, but can't think about a possibility (or maybe
> I'm a bit blind...).
>
> Thanks,
> Craig
>
>   
There is a patch made by me that allow for balancing on any http header
field.
I don't now if willy has made it into the core but you can apply it and
test (patch
was  made for 1.3.15.7 but could apply to 1.3.16 too).


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 <param> [check_post [<max_wait>]]
 
+      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 <px> 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;

Reply via email to