MINOR: checks: Add support of HTTP response sample fetches

HTPP sample fetches acting on the response can now be called from any sample
expression or log-format string in a tcp-check based ruleset. To avoid any
ambiguities, all these sample fetches are in the check scope, for instance
check.hdr() or check.cook().
diff --git a/doc/configuration.txt b/doc/configuration.txt
index 4a1c150..87cc691 100644
--- a/doc/configuration.txt
+++ b/doc/configuration.txt
@@ -17546,6 +17546,124 @@
   (check input buffer is filled on tcp-check expect rules and reset on
   tcp-check send rules).
 
+check.body : binary
+  Returns the available body of the HTTP response in the context of a
+  http-check health check as a block of data.
+
+check.body_param([<name>) : string
+  Assumes the body of the HTTP response in the context of a http-check health
+  check is url-encoded. This extracts the first occurrence of the parameter
+  <name> in the body, which ends before '&'. The parameter name is
+  case-sensitive. If no name is given, any parameter will match, and the first
+  one will be returned. The result is a string corresponding to the value of
+  the parameter <name> as presented in the request body (no URL decoding is
+  performed).
+
+check.body_len : integer
+  Returns the length in bytes of the available body of the HTTP response in the
+  context of a http-check health check. It may be lower than the advertised
+  length if the body is larger than the buffer.
+
+check.body_size : integer
+  Returns the advertised length of the HTTP response's body in bytes in the
+  context of a http-check health check. It will represent the advertised
+  Content-Length header, or the size of the available body in case of chunked
+  encoding.
+
+check.cook([<name>]) : string
+  Extracts the last occurrence of the cookie name <name> on a "Set-Cookie"
+  header line from the HTTP response in the context of a http-check health
+  check, and returns its value as string. If no name is specified, the first
+  cookie value is returned.
+
+check.cook_cnt([<name>]) : integer
+  Returns an integer value representing the number of occurrences of the cookie
+  <name> in the HTTP response in the context of a http-check health check, or
+  all cookies if <name> is not specified.
+
+check.cook_val([<name>]) : integer
+  Extracts the last occurrence of the cookie name <name> on a "Set-Cookie"
+  header line from the HTTP response in the context of a http-check health
+  check, and converts its value to an integer which is returned. If no name is
+  specified, the first cookie value is returned.
+
+check.fhdr(<name>[,<occ>]) : string
+  Extracts the last occurrence of header <name> in an HTTP response in the
+  context of a http-check health check. Optionally, a specific occurrence might
+  be specified as a position number.  Positive values indicate a position from
+  the first occurrence, with 1 being the first one. Negative values indicate
+  positions relative to the last one, with -1 being the last one. It differs
+  from check.hdr() in that any commas present in the value are returned and are
+  not used as delimiters.
+
+check.fhdr_cnt([<name>]) : integer
+  Returns an integer value representing the number of occurrences of response
+  header field name <name>, or the total number of header fields if <name> is
+  not specified, in the context of a http-check health check. Contrary to its
+  check.hdr_cnt() cousin, this function returns the number of full line headers
+  and does not stop on commas.
+
+check.hdr([<name>[,<occ>]]) : string
+
+  Extracts the last occurrence of header <name> in an HTTP response in the
+  context of a http-check health check. Optionally, a specific occurrence might
+  be specified as a position number.  Positive values indicate a position from
+  the first occurrence, with 1 being the first one. Negative values indicate
+  positions relative to the last one, with -1 being the last one. A typical use
+  is with the X-Forwarded-For header once converted to IP, associated with an
+  IP stick-table. The function considers any comma as a delimiter for distinct
+  values. If full-line headers are desired instead, use check.fhdr(). Please
+  carefully check RFC7231 to know how certain headers are supposed to be
+  parsed. Also, some of them are case insensitive (e.g. Connection).
+
+check.hdr_cnt([<name>]) : integer
+  Returns an integer value representing the number of occurrences of response
+  header field name <name>, or the total number of header field values if
+  <name> is not specified, in the context of a http-check health check. It is
+  important to remember that one header line may count as several headers if it
+  has several values. The function considers any comma as a delimiter for
+  distinct values. If full-line headers are desired instead, check.fhdr_cnt()
+  should be used instead. See "check.hdr" for more information on header
+  matching.
+
+check.hdr_ip([<name>[,<occ>]]) : ip
+  Extracts the last occurrence of header <name> in an HTTP response in the
+  context of a http-check health check, converts it to an IPv4 or IPv6 address
+  and returns this address. If <name> is omitted, every value of every header
+  is checked. Optionally, a specific occurrence might be specified as a
+  position number. Positive values indicate a position from the first
+  occurrence, with 1 being the first one. Negative values indicate positions
+  relative to the last one, with -1 being the last one. A typical use is with
+  the X-Forwarded-For and X-Client-IP headers.
+
+check.hdr_val([<name>[,<occ>]]) : integer
+  Extracts the last occurrence of header <name> in an HTTP response in the
+  context of a http-check health check, and converts it to an integer value. If
+  <name> is omitted, every value of every header is checked.  Optionally, a
+  specific occurrence might be specified as a position number.  Positive values
+  indicate a position from the first occurrence, with 1 being the first
+  one. Negative values indicate positions relative to the last one, with -1
+  being the last one. A typical use is with the X-Forwarded-For header.
+
+check.hdrs : string
+  Returns the headers in the HTTP response in the context of a http-check
+  health check as string including the last empty line separating headers from
+  the response body. The last empty line can be used to detect a truncated
+  header block.
+
+check.hdrs_bin : binary
+  Returns the headers in the HTTP response in the context of a http-check
+  health check in preparsed binary form.
+
+check.status : integer
+  Returns an integer containing the HTTP status code of the HTTP response in
+  the context of a http-check health check, for example, 302.
+
+check.ver : string (deprecated)
+  Returns the version string from the HTTP response in the context of a
+  http-check health check, for example "1.1".
+
+
 7.3.8. Fetching samples for developers
 ---------------------------------------
 
diff --git a/src/http_fetch.c b/src/http_fetch.c
index bf1d3e9..f6a948d 100644
--- a/src/http_fetch.c
+++ b/src/http_fetch.c
@@ -386,7 +386,8 @@
 static int smp_fetch_stver(const struct arg *args, struct sample *smp, const char *kw, void *private)
 {
 	struct channel *chn = SMP_RES_CHN(smp);
-	struct htx *htx = smp_prefetch_htx(smp, chn, NULL, 1);
+	struct check *check = ((kw[0] == 'c' && smp->sess) ? objt_check(smp->sess->origin) : NULL);
+	struct htx *htx = smp_prefetch_htx(smp, chn, check, 1);
 	struct htx_sl *sl;
 	char *ptr;
 	int len;
@@ -414,7 +415,8 @@
 static int smp_fetch_stcode(const struct arg *args, struct sample *smp, const char *kw, void *private)
 {
 	struct channel *chn = SMP_RES_CHN(smp);
-	struct htx *htx = smp_prefetch_htx(smp, chn, NULL, 1);
+	struct check *check = ((kw[0] == 'c' && smp->sess) ? objt_check(smp->sess->origin) : NULL);
+	struct htx *htx = smp_prefetch_htx(smp, chn, check, 1);
 	struct htx_sl *sl;
 	char *ptr;
 	int len;
@@ -460,7 +462,8 @@
 static int smp_fetch_hdrs(const struct arg *args, struct sample *smp, const char *kw, void *private)
 {
 	struct channel *chn = SMP_REQ_CHN(smp);
-	struct htx *htx = smp_prefetch_htx(smp, chn, NULL, 1);
+	struct check *check = ((kw[0] == 'c' && smp->sess) ? objt_check(smp->sess->origin) : NULL);
+	struct htx *htx = smp_prefetch_htx(smp, chn, check, 1);
 	struct buffer *temp;
 	int32_t pos;
 
@@ -505,7 +508,8 @@
 static int smp_fetch_hdrs_bin(const struct arg *args, struct sample *smp, const char *kw, void *private)
 {
 	struct channel *chn = SMP_REQ_CHN(smp);
-	struct htx *htx = smp_prefetch_htx(smp, chn, NULL, 1);
+	struct check *check = ((kw[0] == 'c' && smp->sess) ? objt_check(smp->sess->origin) : NULL);
+	struct htx *htx = smp_prefetch_htx(smp, chn, check, 1);
 	struct buffer *temp;
 	char *p, *end;
 	int32_t pos;
@@ -572,7 +576,8 @@
 static int smp_fetch_body(const struct arg *args, struct sample *smp, const char *kw, void *private)
 {
 	struct channel *chn = SMP_REQ_CHN(smp);
-	struct htx *htx = smp_prefetch_htx(smp, chn, NULL, 1);
+	struct check *check = ((kw[0] == 'c' && smp->sess) ? objt_check(smp->sess->origin) : NULL);
+	struct htx *htx = smp_prefetch_htx(smp, chn, check, 1);
 	struct buffer *temp;
 	int32_t pos;
 
@@ -605,7 +610,8 @@
 static int smp_fetch_body_len(const struct arg *args, struct sample *smp, const char *kw, void *private)
 {
 	struct channel *chn = SMP_REQ_CHN(smp);
-	struct htx *htx = smp_prefetch_htx(smp, chn, NULL, 1);
+	struct check *check = ((kw[0] == 'c' && smp->sess) ? objt_check(smp->sess->origin) : NULL);
+	struct htx *htx = smp_prefetch_htx(smp, chn, check, 1);
 	int32_t pos;
 	unsigned long long len = 0;
 
@@ -636,7 +642,8 @@
 static int smp_fetch_body_size(const struct arg *args, struct sample *smp, const char *kw, void *private)
 {
 	struct channel *chn = SMP_REQ_CHN(smp);
-	struct htx *htx = smp_prefetch_htx(smp, chn, NULL, 1);
+	struct check *check = ((kw[0] == 'c' && smp->sess) ? objt_check(smp->sess->origin) : NULL);
+	struct htx *htx = smp_prefetch_htx(smp, chn, check, 1);
 	int32_t pos;
 	unsigned long long len = 0;
 
@@ -732,7 +739,8 @@
 {
 	/* possible keywords: req.fhdr, res.fhdr */
 	struct channel *chn = ((kw[2] == 'q') ? SMP_REQ_CHN(smp) : SMP_RES_CHN(smp));
-	struct htx *htx = smp_prefetch_htx(smp, chn, NULL, 1);
+	struct check *check = ((kw[0] == 'c' && smp->sess) ? objt_check(smp->sess->origin) : NULL);
+	struct htx *htx = smp_prefetch_htx(smp, chn, check, 1);
 	struct http_hdr_ctx *ctx = smp->ctx.a[0];
 	struct ist name;
 	int occ = 0;
@@ -785,7 +793,8 @@
 {
 	/* possible keywords: req.fhdr_cnt, res.fhdr_cnt */
 	struct channel *chn = ((kw[2] == 'q') ? SMP_REQ_CHN(smp) : SMP_RES_CHN(smp));
-	struct htx *htx = smp_prefetch_htx(smp, chn, NULL, 1);
+	struct check *check = ((kw[0] == 'c' && smp->sess) ? objt_check(smp->sess->origin) : NULL);
+	struct htx *htx = smp_prefetch_htx(smp, chn, check, 1);
 	struct http_hdr_ctx ctx;
 	struct ist name;
 	int cnt;
@@ -815,7 +824,8 @@
 {
 	/* possible keywords: req.hdr_names, res.hdr_names */
 	struct channel *chn = ((kw[2] == 'q') ? SMP_REQ_CHN(smp) : SMP_RES_CHN(smp));
-	struct htx *htx = smp_prefetch_htx(smp, chn, NULL, 1);
+	struct check *check = ((kw[0] == 'c' && smp->sess) ? objt_check(smp->sess->origin) : NULL);
+	struct htx *htx = smp_prefetch_htx(smp, chn, check, 1);
 	struct buffer *temp;
 	char del = ',';
 
@@ -860,7 +870,8 @@
 {
 	/* possible keywords: req.hdr / hdr, res.hdr / shdr */
 	struct channel *chn = ((kw[0] == 'h' || kw[2] == 'q') ? SMP_REQ_CHN(smp) : SMP_RES_CHN(smp));
-	struct htx *htx = smp_prefetch_htx(smp, chn, NULL, 1);
+	struct check *check = ((kw[0] == 'c' && smp->sess) ? objt_check(smp->sess->origin) : NULL);
+	struct htx *htx = smp_prefetch_htx(smp, chn, check, 1);
 	struct http_hdr_ctx *ctx = smp->ctx.a[0];
 	struct ist name;
 	int occ = 0;
@@ -923,7 +934,8 @@
 {
 	/* possible keywords: req.hdr_cnt / hdr_cnt, res.hdr_cnt / shdr_cnt */
 	struct channel *chn = ((kw[0] == 'h' || kw[2] == 'q') ? SMP_REQ_CHN(smp) : SMP_RES_CHN(smp));
-	struct htx *htx = smp_prefetch_htx(smp, chn, NULL, 1);
+	struct check *check = ((kw[0] == 'c' && smp->sess) ? objt_check(smp->sess->origin) : NULL);
+	struct htx *htx = smp_prefetch_htx(smp, chn, check, 1);
 	struct http_hdr_ctx ctx;
 	struct ist name;
 	int cnt;
@@ -1546,7 +1558,8 @@
 {
 	/* possible keywords: req.cookie / cookie / cook, res.cookie / scook / set-cookie */
 	struct channel *chn = ((kw[0] == 'c' || kw[2] == 'q') ? SMP_REQ_CHN(smp) : SMP_RES_CHN(smp));
-	struct htx *htx = smp_prefetch_htx(smp, chn, NULL, 1);
+	struct check *check = ((kw[0] == 'c' && smp->sess) ? objt_check(smp->sess->origin) : NULL);
+	struct htx *htx = smp_prefetch_htx(smp, chn, check, 1);
 	struct http_hdr_ctx *ctx = smp->ctx.a[2];
 	struct ist hdr;
 	int occ = 0;
@@ -1565,7 +1578,7 @@
 	if (!htx)
 		return 0;
 
-	hdr = (!(chn->flags & CF_ISRESP) ? ist("Cookie") : ist("Set-Cookie"));
+	hdr = (!(check || (chn && chn->flags & CF_ISRESP)) ? ist("Cookie") : ist("Set-Cookie"));
 
 	if (!occ && !(smp->opt & SMP_OPT_ITERATE))
 		/* no explicit occurrence and single fetch => last cookie by default */
@@ -1643,7 +1656,8 @@
 {
 	/* possible keywords: req.cook_cnt / cook_cnt, res.cook_cnt / scook_cnt */
 	struct channel *chn = ((kw[0] == 'c' || kw[2] == 'q') ? SMP_REQ_CHN(smp) : SMP_RES_CHN(smp));
-	struct htx *htx = smp_prefetch_htx(smp, chn, NULL, 1);
+	struct check *check = ((kw[0] == 'c' && smp->sess) ? objt_check(smp->sess->origin) : NULL);
+	struct htx *htx = smp_prefetch_htx(smp, chn, check, 1);
 	struct http_hdr_ctx ctx;
 	struct ist hdr;
 	char *val_beg, *val_end;
@@ -1655,7 +1669,7 @@
 	if (!htx)
 		return 0;
 
-	hdr = (!(chn->flags & CF_ISRESP) ? ist("Cookie") : ist("Set-Cookie"));
+	hdr = (!(check || (chn && chn->flags & CF_ISRESP)) ? ist("Cookie") : ist("Set-Cookie"));
 
 	val_end = val_beg = NULL;
 	ctx.blk = NULL;
@@ -1822,6 +1836,7 @@
 static int smp_fetch_body_param(const struct arg *args, struct sample *smp, const char *kw, void *private)
 {
 	struct channel *chn = SMP_REQ_CHN(smp);
+	struct check *check = ((kw[0] == 'c' && smp->sess) ? objt_check(smp->sess->origin) : NULL);
 	const char *name;
 	int name_len;
 
@@ -1836,7 +1851,7 @@
 	}
 
 	if (!smp->ctx.a[0]) { // first call, find the query string
-		struct htx *htx = smp_prefetch_htx(smp, chn, NULL, 1);
+		struct htx *htx = smp_prefetch_htx(smp, chn, check, 1);
 		struct buffer *temp;
 		int32_t pos;
 
@@ -2114,6 +2129,26 @@
 	{ "url_param",          smp_fetch_url_param,          ARG2(0,STR,STR),  NULL,    SMP_T_STR,  SMP_USE_HRQHV },
 	{ "urlp"     ,          smp_fetch_url_param,          ARG2(0,STR,STR),  NULL,    SMP_T_STR,  SMP_USE_HRQHV },
 	{ "urlp_val",           smp_fetch_url_param_val,      ARG2(0,STR,STR),  NULL,    SMP_T_SINT, SMP_USE_HRQHV },
+
+
+	{ "check.ver",          smp_fetch_stver,              0,                NULL,    SMP_T_STR,  SMP_USE_INTRN },
+	{ "check.status",       smp_fetch_stcode,             0,                NULL,    SMP_T_SINT, SMP_USE_INTRN },
+	{ "check.hdrs",         smp_fetch_hdrs,               0,                NULL,    SMP_T_BIN,  SMP_USE_INTRN },
+	{ "check.hdrs_bin",     smp_fetch_hdrs_bin,           0,                NULL,    SMP_T_BIN,  SMP_USE_INTRN },
+	{ "check.body",         smp_fetch_body,               0,                NULL,    SMP_T_BIN,  SMP_USE_INTRN },
+	{ "check.body_len",     smp_fetch_body_len,           0,                NULL,    SMP_T_SINT, SMP_USE_INTRN },
+	{ "check.body_size",    smp_fetch_body_size,          0,                NULL,    SMP_T_SINT, SMP_USE_INTRN },
+	{ "check.body_param",   smp_fetch_body_param,         ARG1(0,STR),      NULL,    SMP_T_BIN,  SMP_USE_INTRN },
+	{ "check.fhdr",         smp_fetch_fhdr,               ARG2(0,STR,SINT), val_hdr, SMP_T_STR,  SMP_USE_INTRN },
+	{ "check.fhdr_cnt",     smp_fetch_fhdr_cnt,           ARG1(0,STR),      NULL,    SMP_T_SINT, SMP_USE_INTRN },
+	{ "check.hdr",          smp_fetch_hdr,                ARG2(0,STR,SINT), val_hdr, SMP_T_STR,  SMP_USE_INTRN },
+	{ "check.hdr_cnt",      smp_fetch_hdr_cnt,            ARG1(0,STR),      NULL,    SMP_T_SINT, SMP_USE_INTRN },
+	{ "check.hdr_ip",       smp_fetch_hdr_ip,             ARG2(0,STR,SINT), val_hdr, SMP_T_IPV4, SMP_USE_INTRN },
+	{ "check.hdr_names",    smp_fetch_hdr_names,          ARG1(0,STR),      NULL,    SMP_T_STR,  SMP_USE_INTRN },
+	{ "check.hdr_val",      smp_fetch_hdr_val,            ARG2(0,STR,SINT), val_hdr, SMP_T_SINT, SMP_USE_INTRN },
+	{ "check.cook",         smp_fetch_cookie,             ARG1(0,STR),      NULL,    SMP_T_STR,  SMP_USE_INTRN },
+	{ "check.cook_cnt",     smp_fetch_cookie_cnt,         ARG1(0,STR),      NULL,    SMP_T_SINT, SMP_USE_INTRN },
+	{ "check.cook_val",     smp_fetch_cookie_val,         ARG1(0,STR),      NULL,    SMP_T_SINT, SMP_USE_INTRN },
 	{ /* END */ },
 }};