Hello,

  I apologize for my persistence and realize that everyone if busy with getting
1.5 out of the door. I have no expectations on that front for the patch included
here. However any feedback is welcome. I went thru some of the submitted
patches and saw one by Simon Horman to use an external process after I
made this change and will revisit that again.

  I re-did my implementation, and this time I am submitting it as a patch for
consideration. I am posting the commit message that explains the change.

=================================================================
 We add new directives to the http-check keyword

The server option is used to specify an external
health checking server to use for health checks.

Example:
    http-check server <ipv4|ipv6>

The info option is used to specify a http
header to communicate information about the server
being checked to the external health checking server

Example:
    http-check info [header <http-header>]

The default value of the header is 'X-Check-Info'

This option is independent of the server directive. When
used includes a http header in the health check request
of the form

<http-header>: <value>

Finally, we add to the server directive a 'info'
option. This value assigned to this option is passed
to the external health checking server.

Example:
    server id <addr> [info <value>]

Putting it all togeather

backend bck1
    mode http

    # the host header works but wasn't the intent
    option      httpchk   GET /health HTTP/1.1\r\nHost:\ www.hst1.com

    # specify a server to use for the check
    http-check  server chksrv1.dc.hst1.com

    # request for info about the server using the default host header
    # the following 2 lines are equivalent
    # http-check info
    http-check  info X-Check-Info

    # pass in the info using the default
    # the following 2 lines are equivalent
    # server a1 a1.dc.hst1.com:80 weight 20 maxconn 5 check inter 2s
    server a1 a1.dc.hst1.com:80 weight 20 maxconn 5 check inter 2s info a1

    # this is probably a better alternative
    server a1 a1.dc.hst1.com:80 weight 20 maxconn 5 check inter 2s
info a1.dc.hst1.com
=================================================================

This implementation can also be used for http health checks when
running in tcp mode
providing a potential alternative to implementing health checks for
tcp mode deployments
not directly available in haproxy, also allowing for more advanced
health check beyond
a hello message.

Following is a config that I used to test this

global
        maxconn     10

defaults
        mode        tcp
        clitimeout  30m
        srvtimeout  30m
        contimeout  4s

backend myblog
        option      httpchk   GET /_health.php HTTP/1.1
        http-check  server bhaskar-dev:80
        http-check  info
        server b1 blackmagic.tumblr.com:80 weight 20 maxconn 5 check
inter 2s info blackmagic.tumblr.com

frontend myblogfrontend
      bind *:9080

      default_backend myblog


Thanks
Bhaskar

On Thu, Feb 6, 2014 at 2:45 PM, Bhaskar Maddala <madda...@gmail.com> wrote:
> Hello,
>
>    Since I did not get any responses on this, I decided to try
> motivating a reponse
> by attempting an implementation. I am attaching a patch that does
> this. Admittedly
> this patch is an iteration and I am not submitting it for anything
> more than receiving
> feedback, on the requirement, alternative ideas and the implementation.
>
> Following is an explanation
>
> I added an option httpchksrv which takes an ipv4/6 address (external
> health checker)
>  and an option http header. The http header is used to communicate to the 
> health
> check server the backend server to check.
>
>         option      httpchk   GET /_health.php HTTP/1.1
>         option      httpchksrv    <ipv4|ipv6> [header
> <http-header-name=X-Check-For>]
>
> Next, I added a "header-value" specification to the server definition
>
>          server a1 magic.tumblr.com:80 weight 20 maxconn 5 check inter
> 2s header-value magic.tumblr.com
>
> the header-value is used for the http-header-name specified in httpchksrv
>
> Here is an example of the health check request
>
> GET /_health.php HTTP/1.1
> X-Check-For: magic.tumblr.com
>
> The default value of header-value is the server id, in this case 'a1'
>
> The following is a little abstract and describes how health checks can be 
> cached
> using this change, please bear with my attempts to describe it, these may be
> in-adequate. Please take this for what it is, broad strokes of an
> idea. I am not in any way advocating for this deployment.
>
> Going back to my original motivation "excessive health checks due to 
> increasing
> proxy and web application deployment", here is a description of how I can 
> solve
> it using this implementation.
>
> On haproxy I define 2 frontend, one on port 80 and one on port 6777. The
> httpchksrv specification is used to direct health checks back to haproxy on 
> port
> 6777. With haproxy in http mode
>
>         option      httpchksrv    127.0.0.1:6777
>
> Each server specification on the backend for port 80 (production traffic) uses
> a server specification as
>
>          server a1 server:80 weight 20 maxconn 5 check inter 2s
>
> I define a backend of varnish nodes to use with the front end on port 6777.
> I also make sure that the varnish backend uses only L4 health checks.
>
> Health check are passed to varnish from all the proxies consistently hashed on
> the http header X-Check-For via their front end on port 6777. Varnish
> vcl is used to
> obtain the header value 'X-Check-For' and make a health check request to the
> appropriate web host if required, it may return cached health check
> responses according
> the configured TTL.
>
>
> Thanks
> Bhaskar
>
> On Fri, Jan 31, 2014 at 1:46 PM, Bhaskar Maddala <madda...@gmail.com> wrote:
>> Hello,
>>
>>    As the number of haproxy deployments (>20) grows in our infrastructure 
>> along
>> with an increase in the number of backends ~1500 we are beginning to
>> see a non trivial resources allocated to health checks. Each proxy instance
>> health checking each backend every 2 seconds.
>>
>>   In an earlier conversation with Willy I was directed to look into the 
>> options
>> fastinter and on-error configuration options. I have done this but wanted to
>> speak about how others might have addressed this and if there was any
>> interest in implementing something along these lines and gather 
>> ideas/comments
>> on what such an implementation would look like.
>>
>>  We use haproxy as a http load balancer and I have not given any thought
>> about how the following description applies to tcp mode.
>>
>> Currently we http check our backends using
>>
>>     option httpchk GET /_check.php HTTP/1.1\r\nHost:\ www.domain.com
>>
>>   We were considering adding an additional directive to specify a check 
>> server
>> in addition to the httpchk directive
>>
>>     option          httpchk     GET /_health.php HTTP/1.1\r\nHost:\ hdr(Host)
>>     option          chksrv      server hcm-008dad0f 172.16.114.52:80
>>
>> The change would add a dynamic field to the health check request.
>> hdr(Host) (http host header in this instance) is the field used to 
>> communicate
>> the server to be health checked to the external check server.
>>
>> The check server can/will be implemented to cache health check responses from
>> the back ends.
>>
>> One of the justifications for implementing this is the need in my
>> environment to take
>> into consideration factors not available to the backends when
>> responding to a health
>> check. As an example we will be implementing in our check server
>> ability to force
>> success/failure of health checks on groups of backends related in some 
>> manner.
>> We expect this to allow us to avoid brown out scenarios we have
>> encountered in the past.
>>
>> Has anyone considered/achieved something along these lines, or have 
>> suggestions
>> on how we could implement the same?
>>
>> Thanks
>> Bhaskar
From 434317d54ad36e62560454eb0a0f6f43be17b091 Mon Sep 17 00:00:00 2001
From: Bhaskar Maddala <madda...@gmail.com>
Date: Fri, 7 Feb 2014 13:55:35 -0500
Subject: [PATCH] Add ability to externalize health check

Summary:
We add new directives to the http-check keyword

The server option is used to specify an external
health checking server to use for health checks.

Example:
    http-check server <ipv4|ipv6>

The info option is used to specify a http
header to communicate information about the server
being checked to the external health checking server

Example:
    http-check info [header <http-header>]

The default value of the header is 'X-Check-Info'

This option is independent of the server directive. When
used includes a http header in the health check request
of the form

<http-header>: <value>

Finally, we add to the server directive a 'info'
option. This value assigned to this option is passed
to the external health checking server.

Example:
    server id <addr> [info <value>]

Putting it all togeather

backend bck1
    mode http

    # the host header works but wasn't the intent
    option      httpchk   GET /health HTTP/1.1\r\nHost:\ www.hst1.com

    # specify a server to use for the check
    http-check  server chksrv1.dc.hst1.com

    # request for info about the server using the default host header
    # the following 2 lines are equivalent
    # http-check info
    http-check  info X-Check-Info

    # pass in the info using the default
    # the following 2 lines are equivalent
    # server a1 a1.dc.hst1.com:80 weight 20 maxconn 5 check inter 2s
    server a1 a1.dc.hst1.com:80 weight 20 maxconn 5 check inter 2s info a1

    # this is probably a better alternative
    server a1 a1.dc.hst1.com:80 weight 20 maxconn 5 check inter 2s info 
a1.dc.hst1.com
---
 include/common/defaults.h |   2 +
 include/types/proxy.h     |   8 +++-
 include/types/server.h    |   3 ++
 src/cfgparse.c            | 110 ++++++++++++++++++++++++++++++++++++++-------
 src/checks.c              | 112 +++++++++++++++++++++++++++-------------------
 5 files changed, 169 insertions(+), 66 deletions(-)

diff --git a/include/common/defaults.h b/include/common/defaults.h
index f765e90..17bc5d2 100644
--- a/include/common/defaults.h
+++ b/include/common/defaults.h
@@ -131,6 +131,8 @@
 #define DEF_SMTP_CHECK_REQ   "HELO localhost\r\n"
 #define DEF_LDAP_CHECK_REQ   
"\x30\x0c\x02\x01\x01\x60\x07\x02\x01\x03\x04\x00\x80\x00"
 #define DEF_REDIS_CHECK_REQ  "*1\r\n$4\r\nPING\r\n"
+#define DEF_CHECK_HOST_HDR   "X-Check-Info"
+#define DEF_CHECK_HOST_PORT  80
 
 #define DEF_HANA_ONERR         HANA_ONERR_FAILCHK
 #define DEF_HANA_ERRLIMIT      10
diff --git a/include/types/proxy.h b/include/types/proxy.h
index af2a3ab..638b5f7 100644
--- a/include/types/proxy.h
+++ b/include/types/proxy.h
@@ -142,7 +142,8 @@ enum pr_mode {
 #define PR_O2_SRC_ADDR 0x00100000      /* get the source ip and port for logs 
*/
 
 #define PR_O2_FAKE_KA   0x00200000      /* pretend we do keep-alive with 
server eventhough we close */
-/* unused: 0x00400000 */
+#define PR_O2_CHK_INFO  0x00400000             /* include info header and 
value in http health checks */
+
 #define PR_O2_EXP_NONE  0x00000000      /* http-check : no expect rule */
 #define PR_O2_EXP_STS   0x00800000      /* http-check expect status */
 #define PR_O2_EXP_RSTS  0x01000000      /* http-check expect rstatus */
@@ -338,7 +339,10 @@ struct proxy {
        int grace;                              /* grace time after stop 
request */
        struct list tcpcheck_rules;             /* tcp-check send / expect 
rules */
        char *check_req;                        /* HTTP or SSL request to use 
for PR_O_HTTP_CHK|PR_O_SSL3_CHK */
-       int check_len;                          /* Length of the HTTP or SSL3 
request */
+       int check_req_len;                      /* Length of the HTTP or SSL3 
request */
+       struct sockaddr_storage check_addr;     /* the address to check */
+       char *check_for_hdr_name;                       /* HTTP header used to 
identify host being checked */
+       int check_for_hdr_name_len;                     /* Length of the HTTP 
header */
        char *expect_str;                       /* http-check expected content 
: string or text version of the regex */
        regex_t *expect_regex;                  /* http-check expected content 
*/
        struct chunk errmsg[HTTP_ERR_SIZE];     /* default or customized error 
messages for known errors */
diff --git a/include/types/server.h b/include/types/server.h
index 54ab813..ef56a49 100644
--- a/include/types/server.h
+++ b/include/types/server.h
@@ -161,6 +161,9 @@ struct server {
                struct sockaddr_storage addr;   /* the address to check, if 
different from <addr> */
        } check_common;
 
+       char *check_for_hdr_val;                   /* http header value used 
for health checkes */
+       int check_for_hdr_val_len;                      /* length of the http 
header value */
+
        struct check check;                     /* health-check specific 
configuration */
        struct check agent;                     /* agent specific configuration 
*/
 
diff --git a/src/cfgparse.c b/src/cfgparse.c
index 9993c61..7e56df8 100644
--- a/src/cfgparse.c
+++ b/src/cfgparse.c
@@ -1841,12 +1841,19 @@ int cfg_parse_listen(const char *file, int linenum, 
char **args, int kwm)
                if (curproxy->cap & PR_CAP_BE) {
                        curproxy->fullconn = defproxy.fullconn;
                        curproxy->conn_retries = defproxy.conn_retries;
+                       curproxy->check_addr = defproxy.check_addr;
 
                        if (defproxy.check_req) {
-                               curproxy->check_req = calloc(1, 
defproxy.check_len);
-                               memcpy(curproxy->check_req, defproxy.check_req, 
defproxy.check_len);
+                               curproxy->check_req = calloc(1, 
defproxy.check_req_len);
+                               memcpy(curproxy->check_req, defproxy.check_req, 
defproxy.check_req_len);
                        }
-                       curproxy->check_len = defproxy.check_len;
+                       curproxy->check_req_len = defproxy.check_req_len;
+
+                       if (defproxy.check_for_hdr_name) {
+                               curproxy->check_for_hdr_name = calloc(1, 
defproxy.check_for_hdr_name_len);
+                               memcpy(curproxy->check_for_hdr_name, 
defproxy.check_for_hdr_name, defproxy.check_for_hdr_name_len);
+                       }
+                       curproxy->check_for_hdr_name_len = 
defproxy.check_for_hdr_name_len;
 
                        if (defproxy.expect_str) {
                                curproxy->expect_str = 
strdup(defproxy.expect_str);
@@ -1990,6 +1997,8 @@ int cfg_parse_listen(const char *file, int linenum, char 
**args, int kwm)
                free(defproxy.monitor_uri);
                free(defproxy.defbe.name);
                free(defproxy.conn_src.iface_name);
+               free(defproxy.check_for_hdr_name);
+               defproxy.check_for_hdr_name_len = 0;
                free(defproxy.fwdfor_hdr_name);
                defproxy.fwdfor_hdr_len = 0;
                free(defproxy.orgto_hdr_name);
@@ -3631,11 +3640,11 @@ stats_error_parsing:
                        curproxy->options2 |= PR_O2_HTTP_CHK;
                        if (!*args[2]) { /* no argument */
                                curproxy->check_req = strdup(DEF_CHECK_REQ); /* 
default request */
-                               curproxy->check_len = strlen(DEF_CHECK_REQ);
+                               curproxy->check_req_len = strlen(DEF_CHECK_REQ);
                        } else if (!*args[3]) { /* one argument : URI */
                                int reqlen = strlen(args[2]) + strlen("OPTIONS  
HTTP/1.0\r\n") + 1;
                                curproxy->check_req = (char *)malloc(reqlen);
-                               curproxy->check_len = 
snprintf(curproxy->check_req, reqlen,
+                               curproxy->check_req_len = 
snprintf(curproxy->check_req, reqlen,
                                                               "OPTIONS %s 
HTTP/1.0\r\n", args[2]); /* URI to use */
                        } else { /* more arguments : METHOD URI [HTTP_VER] */
                                int reqlen = strlen(args[2]) + strlen(args[3]) 
+ 3 + strlen("\r\n");
@@ -3645,7 +3654,7 @@ stats_error_parsing:
                                        reqlen += strlen("HTTP/1.0");
                    
                                curproxy->check_req = (char *)malloc(reqlen);
-                               curproxy->check_len = 
snprintf(curproxy->check_req, reqlen,
+                               curproxy->check_req_len = 
snprintf(curproxy->check_req, reqlen,
                                                               "%s %s %s\r\n", 
args[2], args[3], *args[4]?args[4]:"HTTP/1.0");
                        }
                }
@@ -3668,18 +3677,18 @@ stats_error_parsing:
 
                        if (!*args[2] || !*args[3]) { /* no argument or 
incomplete EHLO host */
                                curproxy->check_req = 
strdup(DEF_SMTP_CHECK_REQ); /* default request */
-                               curproxy->check_len = 
strlen(DEF_SMTP_CHECK_REQ);
+                               curproxy->check_req_len = 
strlen(DEF_SMTP_CHECK_REQ);
                        } else { /* ESMTP EHLO, or SMTP HELO, and a hostname */
                                if (!strcmp(args[2], "EHLO") || 
!strcmp(args[2], "HELO")) {
                                        int reqlen = strlen(args[2]) + 
strlen(args[3]) + strlen(" \r\n") + 1;
                                        curproxy->check_req = (char 
*)malloc(reqlen);
-                                       curproxy->check_len = 
snprintf(curproxy->check_req, reqlen,
+                                       curproxy->check_req_len = 
snprintf(curproxy->check_req, reqlen,
                                                                       "%s 
%s\r\n", args[2], args[3]); /* HELO hostname */
                                } else {
                                        /* this just hits the default for now, 
but you could potentially expand it to allow for other stuff
                                           though, it's unlikely you'd want to 
send anything other than an EHLO or HELO */
                                        curproxy->check_req = 
strdup(DEF_SMTP_CHECK_REQ); /* default request */
-                                       curproxy->check_len = 
strlen(DEF_SMTP_CHECK_REQ);
+                                       curproxy->check_req_len = 
strlen(DEF_SMTP_CHECK_REQ);
                                }
                        }
                }
@@ -3726,7 +3735,7 @@ stats_error_parsing:
 
                                                free(curproxy->check_req);
                                                curproxy->check_req = packet;
-                                               curproxy->check_len = 
packet_len;
+                                               curproxy->check_req_len = 
packet_len;
 
                                                packet_len = htonl(packet_len);
                                                memcpy(packet, &packet_len, 4);
@@ -3754,7 +3763,7 @@ stats_error_parsing:
 
                        curproxy->check_req = (char *) 
malloc(sizeof(DEF_REDIS_CHECK_REQ) - 1);
                        memcpy(curproxy->check_req, DEF_REDIS_CHECK_REQ, 
sizeof(DEF_REDIS_CHECK_REQ) - 1);
-                       curproxy->check_len = sizeof(DEF_REDIS_CHECK_REQ) - 1;
+                       curproxy->check_req_len = sizeof(DEF_REDIS_CHECK_REQ) - 
1;
                }
 
                else if (!strcmp(args[1], "mysql-check")) {
@@ -3803,7 +3812,7 @@ stats_error_parsing:
 
                                                free(curproxy->check_req);
                                                curproxy->check_req = (char 
*)calloc(1, reqlen);
-                                               curproxy->check_len = reqlen;
+                                               curproxy->check_req_len = 
reqlen;
 
                                                snprintf(curproxy->check_req, 
4, "%c%c%c",
                                                        ((unsigned char) 
packetlen & 0xff),
@@ -3836,7 +3845,7 @@ stats_error_parsing:
 
                        curproxy->check_req = (char *) 
malloc(sizeof(DEF_LDAP_CHECK_REQ) - 1);
                        memcpy(curproxy->check_req, DEF_LDAP_CHECK_REQ, 
sizeof(DEF_LDAP_CHECK_REQ) - 1);
-                       curproxy->check_len = sizeof(DEF_LDAP_CHECK_REQ) - 1;
+                       curproxy->check_req_len = sizeof(DEF_LDAP_CHECK_REQ) - 
1;
                }
                else if (!strcmp(args[1], "tcp-check")) {
                        /* use raw TCPCHK send/expect to check servers' health 
*/
@@ -4079,8 +4088,67 @@ stats_error_parsing:
                                goto out;
                        }
                }
+               else if (!strcmp(args[1], "server")) {
+                       if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, 
args[1], NULL))
+                                                       err_code |= ERR_WARN;
+
+                       /* use a external http check server instead of querying 
the server for health checks */
+                       if (!*args[2]) {
+                               Alert("parsing [%s:%d]: '%s' expects an 
<ipv4|ipv6> address.\n",
+                                         file, linenum, args[1]);
+                               err_code |= ERR_ALERT | ERR_FATAL;
+                               goto out;
+                       }
+
+                       struct sockaddr_storage *sk;
+                       int port1, port2;
+                       struct protocol *proto;
+
+                       sk = str2sa_range(args[2], &port1, &port2, &errmsg, 
NULL);
+                       if (!sk) {
+                               Alert("parsing [%s:%d] : '%s' : %s\n",
+                                         file, linenum, args[2], errmsg);
+                               err_code |= ERR_ALERT | ERR_FATAL;
+                               goto out;
+                       }
+
+                       proto = protocol_by_family(sk->ss_family);
+                       if (!proto || !proto->connect) {
+                               Alert("parsing [%s:%d] : '%s %s' : connect() 
not supported for this address family.\n",
+                                         file, linenum, args[1], args[2]);
+                               err_code |= ERR_ALERT | ERR_FATAL;
+                               goto out;
+                       }
+
+                       if (port1 != port2) {
+                               Alert("parsing [%s:%d] : '%s' : port ranges and 
offsets are not allowed in '%s'\n",
+                                         file, linenum, args[1], args[2]);
+                               err_code |= ERR_ALERT | ERR_FATAL;
+                               goto out;
+                       }
+
+                       if (!port1)
+                               set_host_port(sk, DEF_CHECK_HOST_PORT);
+
+                       curproxy->check_addr = *sk;
+               }
+               else if (!strcmp(args[1], "info")) {
+                       curproxy->options2 |= PR_O2_CHK_INFO;
+                       if (!*args[2]) { /* no argument */
+                               curproxy->check_for_hdr_name = 
strdup(DEF_CHECK_HOST_HDR);
+                               curproxy->check_for_hdr_name_len = 
strlen(DEF_CHECK_HOST_HDR);
+                       } else if (*args[2] && !strcmp(args[2], "header")) {
+                               curproxy->check_for_hdr_name = strdup(args[3]);
+                               curproxy->check_for_hdr_name_len = 
strlen(args[3]);
+                       } else {
+                               Alert("parsing [%s:%d] : '%s' : expect valid 
http header it can be specified using 'header'\n",
+                                         file, linenum, args[1]);
+                               err_code |= ERR_ALERT | ERR_FATAL;
+                               goto out;
+                       }
+               }
                else {
-                       Alert("parsing [%s:%d] : '%s' only supports 
'disable-on-404', 'send-state', 'expect'.\n", file, linenum, args[0]);
+                       Alert("parsing [%s:%d] : '%s' only supports 
'disable-on-404', 'send-state', 'expect', 'server', 'info'.\n", file, linenum, 
args[0]);
                        err_code |= ERR_ALERT | ERR_FATAL;
                        goto out;
                }
@@ -4563,6 +4631,8 @@ stats_error_parsing:
                        newsrv->state = SRV_RUNNING; /* early server setup */
                        newsrv->last_change = now.tv_sec;
                        newsrv->id = strdup(args[1]);
+                       newsrv->check_for_hdr_val = strdup(args[1]);
+                       newsrv->check_for_hdr_val_len = strlen(args[1]);
 
                        /* several ways to check the port component :
                         *  - IP    => port=+0, relative (IPv4 only)
@@ -4812,6 +4882,11 @@ stats_error_parsing:
                                newsrv->check_common.addr = *sk;
                                cur_arg += 2;
                        }
+                       else if (!strcmp(args[cur_arg], "info")) {
+                               newsrv->check_for_hdr_val = strdup(args[cur_arg 
+ 1]);
+                               newsrv->check_for_hdr_val_len = 
strlen(args[cur_arg  + 1]);
+                               cur_arg += 2;
+                       }
                        else if (!strcmp(args[cur_arg], "port")) {
                                newsrv->check.port = atol(args[cur_arg + 1]);
                                cur_arg += 2;
@@ -5258,6 +5333,7 @@ stats_error_parsing:
 #endif
                                newsrv->check.send_proxy |= (newsrv->state & 
SRV_SEND_PROXY);
                        }
+
                        /* try to get the port from check_core.addr if 
check.port not set */
                        if (!newsrv->check.port)
                                newsrv->check.port = 
get_host_port(&newsrv->check_common.addr);
@@ -7078,9 +7154,9 @@ out_uri_auth_compat:
                }
 
                if ((curproxy->options2 & PR_O2_CHK_ANY) == PR_O2_SSL3_CHK) {
-                       curproxy->check_len = sizeof(sslv3_client_hello_pkt) - 
1;
-                       curproxy->check_req = (char 
*)malloc(curproxy->check_len);
-                       memcpy(curproxy->check_req, sslv3_client_hello_pkt, 
curproxy->check_len);
+                       curproxy->check_req_len = 
sizeof(sslv3_client_hello_pkt) - 1;
+                       curproxy->check_req = (char 
*)malloc(curproxy->check_req_len);
+                       memcpy(curproxy->check_req, sslv3_client_hello_pkt, 
curproxy->check_req_len);
                }
 
                /* ensure that cookie capture length is not too large */
diff --git a/src/checks.c b/src/checks.c
index c3051aa..c559307 100644
--- a/src/checks.c
+++ b/src/checks.c
@@ -733,58 +733,65 @@ void __health_adjust(struct server *s, short status)
        }
 }
 
-static int httpchk_build_status_header(struct server *s, char *buffer)
+static int httpchk_build_headers(struct server *s, char* buffer)
 {
        int sv_state;
        int ratio;
-       int hlen = 0;
        const char *srv_hlt_st[7] = { "DOWN", "DOWN %d/%d",
                                      "UP %d/%d", "UP",
                                      "NOLB %d/%d", "NOLB",
                                      "no check" };
+       int hlen = 0;
 
-       memcpy(buffer + hlen, "X-Haproxy-Server-State: ", 24);
-       hlen += 24;
+       if (s->proxy->options2 & PR_O2_CHK_INFO) {
+               hlen += s->proxy->check_for_hdr_name_len + strlen(": ") + 
s->check_for_hdr_val_len + strlen("\r\n");
+               sprintf(buffer, "%s: %s\r\n", s->proxy->check_for_hdr_name, 
s->check_for_hdr_val);
+       }
 
-       if (!(s->check.state & CHK_ST_ENABLED))
-               sv_state = 6;
-       else if (s->state & SRV_RUNNING) {
-               if (s->check.health == s->check.rise + s->check.fall - 1)
-                       sv_state = 3; /* UP */
-               else
-                       sv_state = 2; /* going down */
+       if (s->proxy->options2 & PR_O2_CHK_SNDST) {
+               memcpy(buffer + hlen, "X-Haproxy-Server-State: ", 24);
+               hlen += 24;
 
-               if (s->state & SRV_GOINGDOWN)
-                       sv_state += 2;
-       } else {
-               if (s->check.health)
-                       sv_state = 1; /* going up */
-               else
-                       sv_state = 0; /* DOWN */
-       }
+               if (!(s->check.state & CHK_ST_ENABLED))
+                       sv_state = 6;
+               else if (s->state & SRV_RUNNING) {
+                       if (s->check.health == s->check.rise + s->check.fall - 
1)
+                               sv_state = 3; /* UP */
+                       else
+                               sv_state = 2; /* going down */
 
-       hlen += sprintf(buffer + hlen,
-                            srv_hlt_st[sv_state],
-                            (s->state & SRV_RUNNING) ? (s->check.health - 
s->check.rise + 1) : (s->check.health),
-                            (s->state & SRV_RUNNING) ? (s->check.fall) : 
(s->check.rise));
-
-       hlen += sprintf(buffer + hlen, "; name=%s/%s; node=%s; weight=%d/%d; 
scur=%d/%d; qcur=%d",
-                            s->proxy->id, s->id,
-                            global.node,
-                            (s->eweight * s->proxy->lbprm.wmult + 
s->proxy->lbprm.wdiv - 1) / s->proxy->lbprm.wdiv,
-                            (s->proxy->lbprm.tot_weight * 
s->proxy->lbprm.wmult + s->proxy->lbprm.wdiv - 1) / s->proxy->lbprm.wdiv,
-                            s->cur_sess, s->proxy->beconn - s->proxy->nbpend,
-                            s->nbpend);
-
-       if ((s->state & SRV_WARMINGUP) &&
-           now.tv_sec < s->last_change + s->slowstart &&
-           now.tv_sec >= s->last_change) {
-               ratio = MAX(1, 100 * (now.tv_sec - s->last_change) / 
s->slowstart);
-               hlen += sprintf(buffer + hlen, "; throttle=%d%%", ratio);
-       }
+                       if (s->state & SRV_GOINGDOWN)
+                               sv_state += 2;
+               } else {
+                       if (s->check.health)
+                               sv_state = 1; /* going up */
+                       else
+                               sv_state = 0; /* DOWN */
+               }
+
+               hlen += sprintf(buffer + hlen,
+                                    srv_hlt_st[sv_state],
+                                    (s->state & SRV_RUNNING) ? 
(s->check.health - s->check.rise + 1) : (s->check.health),
+                                    (s->state & SRV_RUNNING) ? (s->check.fall) 
: (s->check.rise));
+
+               hlen += sprintf(buffer + hlen, "; name=%s/%s; node=%s; 
weight=%d/%d; scur=%d/%d; qcur=%d",
+                                    s->proxy->id, s->id,
+                                    global.node,
+                                    (s->eweight * s->proxy->lbprm.wmult + 
s->proxy->lbprm.wdiv - 1) / s->proxy->lbprm.wdiv,
+                                    (s->proxy->lbprm.tot_weight * 
s->proxy->lbprm.wmult + s->proxy->lbprm.wdiv - 1) / s->proxy->lbprm.wdiv,
+                                    s->cur_sess, s->proxy->beconn - 
s->proxy->nbpend,
+                                    s->nbpend);
+
+               if ((s->state & SRV_WARMINGUP) &&
+                   now.tv_sec < s->last_change + s->slowstart &&
+                   now.tv_sec >= s->last_change) {
+                       ratio = MAX(1, 100 * (now.tv_sec - s->last_change) / 
s->slowstart);
+                       hlen += sprintf(buffer + hlen, "; throttle=%d%%", 
ratio);
+               }
 
-       buffer[hlen++] = '\r';
-       buffer[hlen++] = '\n';
+               buffer[hlen++] = '\r';
+               buffer[hlen++] = '\n';
+       }
 
        return hlen;
 }
@@ -1254,7 +1261,7 @@ static void event_srv_chk_r(struct connection *conn)
                if (!done && check->bi->i < 5)
                        goto wait_more_data;
 
-               if (s->proxy->check_len == 0) { // old mode
+               if (s->proxy->check_req_len == 0) { // old mode
                        if (*(check->bi->data + 4) != '\xff') {
                                /* We set the MySQL Version in description for 
information purpose
                                 * FIXME : it can be cool to use MySQL Version 
for other purpose,
@@ -1505,6 +1512,7 @@ static struct task *process_chk(struct task *t)
        int rv;
        int ret;
        int expired = tick_is_expired(t->expire, now_ms);
+       int hlen = 0;
 
        if (!(check->state & CHK_ST_INPROGRESS)) {
                /* no check currently running */
@@ -1539,7 +1547,7 @@ static struct task *process_chk(struct task *t)
                 * its own strings.
                 */
                if (check->type && check->type != PR_O2_TCPCHK_CHK && 
!(check->state & CHK_ST_AGENT)) {
-                       bo_putblk(check->bo, s->proxy->check_req, 
s->proxy->check_len);
+                       bo_putblk(check->bo, s->proxy->check_req, 
s->proxy->check_req_len);
 
                        /* we want to check if this host replies to HTTP or 
SSLv3 requests
                         * so we'll send the request, and won't wake the 
checker up now.
@@ -1550,8 +1558,13 @@ static struct task *process_chk(struct task *t)
                                memcpy(check->bo->data + 11, &gmt_time, 4);
                        }
                        else if ((check->type) == PR_O2_HTTP_CHK) {
-                               if (s->proxy->options2 & PR_O2_CHK_SNDST)
-                                       bo_putblk(check->bo, trash.str, 
httpchk_build_status_header(s, trash.str));
+
+                               /* set up the http request with headers 
correctly */
+                               hlen = httpchk_build_headers(s, trash.str);
+
+                               if (hlen)
+                                       bo_putblk(check->bo, trash.str, hlen);
+
                                bo_putstr(check->bo, "\r\n");
                                *check->bo->p = '\0'; /* to make gdb output 
easier to read */
                        }
@@ -1569,9 +1582,14 @@ static struct task *process_chk(struct task *t)
                if (is_addr(&s->check_common.addr))
                        /* we'll connect to the check addr specified on the 
server */
                        conn->addr.to = s->check_common.addr;
-               else
-                       /* we'll connect to the addr on the server */
-                       conn->addr.to = s->addr;
+               else {
+                       if ((check->type) == PR_O2_HTTP_CHK && 
is_addr(&s->proxy->check_addr))
+                               /* we will connect to the check addr specified 
on the proxy, only http checks*/
+                               conn->addr.to = s->proxy->check_addr;
+                       else
+                               /* we'll connect to the addr on the server */
+                               conn->addr.to = s->addr;
+               }
 
                if (check->port) {
                        set_host_port(&conn->addr.to, check->port);
-- 
1.8.3.4 (Apple Git-47)

Reply via email to