MINOR: tcpcheck: Add support for an option host header value for httpchk option

Support for headers and body hidden in the version for the "option httpchk"
directive was removed. However a Host header is mandatory for HTTP/1.1
requests and some servers may return an error if it is not set. For now, to
add it, an "http-check send" rule must be added. But it is not really handy
to use an extra config line for this purpose.

So now, it is possible to set the host header value, a log-format string, as
extra argument to "option httpchk" directive. It must be the fourth argument:

  option httpchk GET / HTTP/1.1 www.srv.com

While this patch is not a bug fix, it is simple enough to be backported if
necessary. On 2.9 and older, lf_init_expr() does not exist and LIST_INIT() must
be used instead.
This commit is contained in:
Christopher Faulet 2024-10-01 18:40:40 +02:00
parent c39c351a73
commit 27ee292731
3 changed files with 30 additions and 4 deletions

View File

@ -9858,6 +9858,7 @@ option httpchk
option httpchk <uri>
option httpchk <method> <uri>
option httpchk <method> <uri> <version>
option httpchk <method> <uri> <version> <host>
Enables HTTP protocol to check on the servers health
May be used in the following contexts: tcp, http
@ -9879,7 +9880,10 @@ option httpchk <method> <uri> <version>
<version> is the optional HTTP version string. It defaults to "HTTP/1.0"
but some servers might behave incorrectly in HTTP 1.0, so turning
it to HTTP/1.1 may sometimes help. Note that the Host field is
mandatory in HTTP/1.1, use "http-check send" directive to add it.
mandatory in HTTP/1.1.
<host> is the optional HTTP Host header value. It is not set by default.
It is a log-format string.
By default, server health checks only consist in trying to establish a TCP
connection. When "option httpchk" is specified, a complete HTTP request is

View File

@ -8,6 +8,7 @@ server s1 {
expect req.method == OPTIONS
expect req.url == /
expect req.proto == HTTP/1.0
expect req.http.host == <undef>
txresp
} -start
@ -16,6 +17,7 @@ server s2 {
expect req.method == GET
expect req.url == /status
expect req.proto == HTTP/1.1
expect req.http.host == "www.haproxy.org"
txresp
} -start
@ -102,7 +104,7 @@ haproxy h1 -conf {
backend be2
log ${S1_addr}:${S1_port} len 2048 local0
option httpchk GET /status HTTP/1.1
option httpchk GET /status HTTP/1.1 www.haproxy.org
server srv ${s2_addr}:${s2_port} check inter 100ms rise 1 fall 1
backend be3

View File

@ -5081,7 +5081,7 @@ static struct tcpcheck_rule *proxy_parse_httpchk_req(char **args, int cur_arg, s
{
struct tcpcheck_rule *chk = NULL;
struct tcpcheck_http_hdr *hdr = NULL;
char *meth = NULL, *uri = NULL, *vsn = NULL;
char *meth = NULL, *uri = NULL, *vsn = NULL, *host = NULL;
char *hdrs, *body;
hdrs = (*args[cur_arg+2] ? strstr(args[cur_arg+2], "\r\n") : NULL);
@ -5114,6 +5114,8 @@ static struct tcpcheck_rule *proxy_parse_httpchk_req(char **args, int cur_arg, s
uri = args[cur_arg+1];
if (*args[cur_arg+2])
vsn = args[cur_arg+2];
if (*args[cur_arg+3])
host = args[cur_arg+3];
if (meth) {
chk->send.http.meth.meth = find_http_meth(meth, strlen(meth));
@ -5138,6 +5140,24 @@ static struct tcpcheck_rule *proxy_parse_httpchk_req(char **args, int cur_arg, s
goto error;
}
}
if (host) {
hdr = calloc(1, sizeof(*hdr));
if (!hdr) {
memprintf(errmsg, "out of memory");
goto error;
}
lf_expr_init(&hdr->value);
hdr->name = istdup(ist("host"));
if (!isttest(hdr->name)) {
memprintf(errmsg, "out of memory");
goto error;
}
if (!parse_logformat_string(host, px, &hdr->value, 0, SMP_VAL_BE_CHK_RUL, errmsg))
goto error;
LIST_APPEND(&chk->send.http.hdrs, &hdr->list);
hdr = NULL;
}
return chk;
@ -5160,7 +5180,7 @@ int proxy_parse_httpchk_opt(char **args, int cur_arg, struct proxy *curpx, const
if (warnifnotcap(curpx, PR_CAP_BE, file, line, args[cur_arg+1], NULL))
err_code |= ERR_WARN;
if (alertif_too_many_args_idx(3, 1, file, line, args, &err_code))
if (alertif_too_many_args_idx(4, 1, file, line, args, &err_code))
goto out;
chk = proxy_parse_httpchk_req(args, cur_arg+2, curpx, &errmsg);