MINOR: checks: Simplify matching on HTTP headers in HTTP expect rules

Extra parameters on http-check expect rules, for the header matching method, to
use log-format string or to match full header line have been removed. There is
now separate matching methods to match a full header line or to match each
comma-separated values. "http-check expect fhdr" must be used in the first case,
and "http-check expect hdr" in the second one. In addition, to match log-format
header name or value, "-lf" suffix must be added to "name" or "value"
keyword. For intance:

   http-check expect hdr name "set-cookie" value-lf -m beg "sessid=%[var(check.cookie)]"

Thanks to this changes, each parameter may only be interpreted in one way.
This commit is contained in:
Christopher Faulet 2020-05-05 20:23:13 +02:00
parent b50b3e6d0a
commit b5594265d2
3 changed files with 72 additions and 69 deletions

View File

@ -4560,8 +4560,8 @@ http-check expect [min-recv <int>] [comment <msg>]
log-format string.
<match> is a keyword indicating how to look for a specific pattern in the
response. The keyword may be one of "status", "rstatus",
"string", or "rstring". The keyword may be preceded by an
response. The keyword may be one of "status", "rstatus", "hdr",
"fhdr", "string", or "rstring". The keyword may be preceded by an
exclamation mark ("!") to negate the match. Spaces are allowed
between the exclamation mark and the keyword. See below for more
details on the supported keywords.
@ -4592,8 +4592,8 @@ http-check expect [min-recv <int>] [comment <msg>]
will be considered invalid if the status code matches.
This is mostly used to check for multiple codes.
header name [ -m <meth> ] <name> [log-format]
[ value [ -m <meth> ] <value> [log-format] [full] ] :
hdr { name | name-lf } [ -m <meth> ] <name>
[ { value | value-lf } [ -m <meth> ] <value> :
test the specified header pattern on the HTTP response
headers. The name pattern is mandatory but the value
pattern is optional. If not specified, only the header
@ -4602,14 +4602,20 @@ http-check expect [min-recv <int>] [comment <msg>]
matching methods are "str" (exact match), "beg" (prefix
match), "end" (suffix match), "sub" (substring match) or
"reg" (regex match). If not specified, exact matching
method is used. If the "log-format" option is used, the
pattern (<name> or <value>) is evaluated as a log-format
string. This option cannot be used with the regex
matching method. Finally, by default, the header value is
considered as comma-separated list. Each part may be
tested. The "full" option may be used to test the full
header line. Note that matchings are case insensitive on
the header names.
method is used. If the "name-lf" parameter is used,
<name> is evaluated as a log-format string. If "value-lf"
parameter is used, <value> is evaluated as a log-format
string. These parameters cannot be used with the regex
matching method. Finally, the header value is considered
as comma-separated list. Note that matchings are case
insensitive on the header names.
fhdr { name | name-lf } [ -m <meth> ] <name>
[ { value | value-lf } [ -m <meth> ] <value> :
test the specified full header pattern on the HTTP
response headers. It does exactly the same than "hdr"
keyword, except the full header value is tested, commas
are not considered as delimiters.
string <string> : test the exact string match in the HTTP response body.
A health check response will be considered valid if the

View File

@ -39,26 +39,26 @@ haproxy h1 -conf {
option httpchk
http-check expect status 200-399
http-check expect header name "x-test1"
http-check expect header name -m str "X-Test2"
http-check expect header name -m beg "X-Begin-"
http-check expect header name -m end "-End"
http-check expect header name -m sub "-Sub-"
http-check expect header name -m reg "^[a-z]+-Reg-[a-z]+[0-9]\$"
http-check expect hdr name "x-test1"
http-check expect hdr name -m str "X-Test2"
http-check expect hdr name -m beg "X-Begin-"
http-check expect hdr name -m end "-End"
http-check expect hdr name -m sub "-Sub-"
http-check expect hdr name -m reg "^[a-z]+-Reg-[a-z]+[0-9]\$"
http-check set-var(check.hdr_name) res.fhdr(x-hdr-name)
http-check expect header name -m str "%[var(check.hdr_name)]" log-format
http-check expect header name -m str "%[res.fhdr(x-hdr-name)]" log-format
http-check expect hdr name-lf -m str "%[var(check.hdr_name)]"
http-check expect hdr name-lf -m str "%[res.fhdr(x-hdr-name)]"
http-check expect header name "x-test1" value "true, next value" full
http-check expect header name "x-test2" value -m str "true"
http-check expect header name -m beg "x-test" value -m beg "begin-"
http-check expect header name -m beg "x-test" value -m end "-end"
http-check expect header name -m beg "x-test" value -m sub "-sub-"
http-check expect header name -m beg "x-test" value -m reg "^value-reg-[A-Z0-9]+\$"
http-check expect header name -m beg "x-test" value -m reg "value-reg-[A-Z0-9]+" full
http-check expect fhdr name "x-test1" value "true, next value"
http-check expect hdr name "x-test2" value -m str "true"
http-check expect hdr name -m beg "x-test" value -m beg "begin-"
http-check expect hdr name -m beg "x-test" value -m end "-end"
http-check expect hdr name -m beg "x-test" value -m sub "-sub-"
http-check expect hdr name -m beg "x-test" value -m reg "^value-reg-[A-Z0-9]+\$"
http-check expect fhdr name -m beg "x-test" value -m reg "value-reg-[A-Z0-9]+"
http-check set-var(check.hdr_value) str(x-test1)
http-check expect header name -m beg "x-" value -m str "%[var(check.hdr_value)]" log-format
http-check expect header name -m beg "x-" value -m str "%[res.fhdr(x-hdr-name)]" log-format full
http-check expect hdr name -m beg "x-" value-lf -m str "%[var(check.hdr_value)]"
http-check expect fhdr name -m beg "x-" value-lf -m str "%[res.fhdr(x-hdr-name)]"
server srv ${s1_addr}:${s1_port} check inter 100ms rise 1 fall 1
} -start

View File

@ -4319,7 +4319,7 @@ static struct tcpcheck_rule *parse_tcpcheck_expect(char **args, int cur_arg, str
}
type = TCPCHK_EXPECT_CUSTOM;
}
else if (strcmp(args[cur_arg], "header") == 0) {
else if (strcmp(args[cur_arg], "hdr") == 0 || strcmp(args[cur_arg], "fhdr") == 0) {
int orig_arg = cur_arg;
if (proto != TCPCHK_RULES_HTTP_CHK)
@ -4330,12 +4330,20 @@ static struct tcpcheck_rule *parse_tcpcheck_expect(char **args, int cur_arg, str
}
type = TCPCHK_EXPECT_HTTP_HEADER;
if (strcmp(args[cur_arg], "fhdr") == 0)
flags |= TCPCHK_EXPT_FL_HTTP_HVAL_FULL;
/* Parse the name pattern, mandatory */
if (!*(args[cur_arg+1]) || !*(args[cur_arg+2]) || strcmp(args[cur_arg+1], "name") != 0) {
memprintf(errmsg, "'%s' expects at the keyword name as first argument followed by a pattern",
if (!*(args[cur_arg+1]) || !*(args[cur_arg+2]) ||
(strcmp(args[cur_arg+1], "name") != 0 && strcmp(args[cur_arg+1], "name-lf") != 0)) {
memprintf(errmsg, "'%s' expects at the name keyword as first argument followed by a pattern",
args[orig_arg]);
goto error;
}
if (strcmp(args[cur_arg+1], "name-lf") == 0)
flags |= TCPCHK_EXPT_FL_HTTP_HNAME_FMT;
cur_arg += 2;
if (strcmp(args[cur_arg], "-m") == 0) {
if (!*(args[cur_arg+1])) {
@ -4351,8 +4359,14 @@ static struct tcpcheck_rule *parse_tcpcheck_expect(char **args, int cur_arg, str
flags |= TCPCHK_EXPT_FL_HTTP_HNAME_END;
else if (strcmp(args[cur_arg+1], "sub") == 0)
flags |= TCPCHK_EXPT_FL_HTTP_HNAME_SUB;
else if (strcmp(args[cur_arg+1], "reg") == 0)
else if (strcmp(args[cur_arg+1], "reg") == 0) {
if (flags & TCPCHK_EXPT_FL_HTTP_HNAME_FMT) {
memprintf(errmsg, "'%s': log-format string is not supported with a regex matching method",
args[orig_arg]);
goto error;
}
flags |= TCPCHK_EXPT_FL_HTTP_HNAME_REG;
}
else {
memprintf(errmsg, "'%s' : '%s' only supports 'str', 'beg', 'end', 'sub' or 'reg' (got '%s')",
args[orig_arg], args[cur_arg], args[cur_arg+1]);
@ -4364,29 +4378,17 @@ static struct tcpcheck_rule *parse_tcpcheck_expect(char **args, int cur_arg, str
flags |= TCPCHK_EXPT_FL_HTTP_HNAME_STR;
npat = args[cur_arg];
if (!(*args[cur_arg+1])) {
flags |= TCPCHK_EXPT_FL_HTTP_HVAL_NONE;
goto next;
}
if (strcmp(args[cur_arg+1], "log-format") == 0) {
if (flags & TCPCHK_EXPT_FL_HTTP_HNAME_REG) {
memprintf(errmsg, "'%s': '%s' cannot be used with a regex matching pattern",
args[orig_arg], args[cur_arg+1]);
goto error;
}
flags |= TCPCHK_EXPT_FL_HTTP_HNAME_FMT;
cur_arg++;
}
if (!(*args[cur_arg+1]) || strcmp(args[cur_arg+1], "value") != 0) {
if (!*(args[cur_arg+1]) ||
(strcmp(args[cur_arg+1], "value") != 0 && strcmp(args[cur_arg+1], "value-lf") != 0)) {
flags |= TCPCHK_EXPT_FL_HTTP_HVAL_NONE;
goto next;
}
if (strcmp(args[cur_arg+1], "value-lf") == 0)
flags |= TCPCHK_EXPT_FL_HTTP_HVAL_FMT;
/* Parse the value pattern, optionnal */
cur_arg += 2;
if (strcmp(args[cur_arg], "-m") == 0) {
if (strcmp(args[cur_arg+2], "-m") == 0) {
cur_arg += 2;
if (!*(args[cur_arg+1])) {
memprintf(errmsg, "'%s' : '%s' expects at a matching pattern ('str', 'beg', 'end', 'sub' or 'reg')",
args[orig_arg], args[cur_arg]);
@ -4400,34 +4402,29 @@ static struct tcpcheck_rule *parse_tcpcheck_expect(char **args, int cur_arg, str
flags |= TCPCHK_EXPT_FL_HTTP_HVAL_END;
else if (strcmp(args[cur_arg+1], "sub") == 0)
flags |= TCPCHK_EXPT_FL_HTTP_HVAL_SUB;
else if (strcmp(args[cur_arg+1], "reg") == 0)
else if (strcmp(args[cur_arg+1], "reg") == 0) {
if (flags & TCPCHK_EXPT_FL_HTTP_HVAL_FMT) {
memprintf(errmsg, "'%s': log-format string is not supported with a regex matching method",
args[orig_arg]);
goto error;
}
flags |= TCPCHK_EXPT_FL_HTTP_HVAL_REG;
}
else {
memprintf(errmsg, "'%s' : '%s' only supports 'str', 'beg', 'end', 'sub' or 'reg' (got '%s')",
args[orig_arg], args[cur_arg], args[cur_arg+1]);
goto error;
}
cur_arg += 2;
}
else
flags |= TCPCHK_EXPT_FL_HTTP_HVAL_STR;
vpat = args[cur_arg];
while (*args[cur_arg+1]) {
if (strcmp(args[cur_arg+1], "log-format") == 0) {
if (flags & TCPCHK_EXPT_FL_HTTP_HVAL_REG) {
memprintf(errmsg, "'%s': '%s' cannot be used with a regex matching pattern",
args[orig_arg], args[cur_arg+1]);
goto error;
}
flags |= TCPCHK_EXPT_FL_HTTP_HVAL_FMT;
}
else if (strcmp(args[cur_arg+1], "full") == 0)
flags |= TCPCHK_EXPT_FL_HTTP_HVAL_FULL;
else
break;
cur_arg++;
if (!*(args[cur_arg+2])) {
memprintf(errmsg, "'%s' expect a pattern with the value keyword", args[orig_arg]);
goto error;
}
vpat = args[cur_arg+2];
cur_arg += 2;
}
else if (strcmp(args[cur_arg], "comment") == 0) {
if (in_pattern) {
@ -4574,7 +4571,7 @@ static struct tcpcheck_rule *parse_tcpcheck_expect(char **args, int cur_arg, str
if (proto == TCPCHK_RULES_HTTP_CHK) {
bad_http_kw:
memprintf(errmsg, "'only supports min-recv, [!]string', '[!]rstring', '[!]string-lf', '[!]status', "
"'[!]rstatus', [!]header or comment but got '%s' as argument.", args[cur_arg]);
"'[!]rstatus', [!]hdr, [!]fhdr or comment but got '%s' as argument.", args[cur_arg]);
}
else {
bad_tcp_kw: