mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-09-24 23:31:40 +02:00
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().
This commit is contained in:
parent
d92ea7f5e7
commit
16032ab44a
@ -17546,6 +17546,124 @@ check.payload_lv(<offset1>,<length>[,<offset2>]) : binary
|
||||
(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
|
||||
---------------------------------------
|
||||
|
||||
|
@ -386,7 +386,8 @@ static int smp_fetch_rqver(const struct arg *args, struct sample *smp, const cha
|
||||
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_stver(const struct arg *args, struct sample *smp, const cha
|
||||
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_uniqueid(const struct arg *args, struct sample *smp, const
|
||||
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(const struct arg *args, struct sample *smp, const char
|
||||
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_hdrs_bin(const struct arg *args, struct sample *smp, const
|
||||
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(const struct arg *args, struct sample *smp, const char
|
||||
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_len(const struct arg *args, struct sample *smp, const
|
||||
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 @@ static int smp_fetch_fhdr(const struct arg *args, struct sample *smp, const char
|
||||
{
|
||||
/* 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 @@ static int smp_fetch_fhdr_cnt(const struct arg *args, struct sample *smp, const
|
||||
{
|
||||
/* 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 @@ static int smp_fetch_hdr_names(const struct arg *args, struct sample *smp, const
|
||||
{
|
||||
/* 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 @@ static int smp_fetch_hdr(const struct arg *args, struct sample *smp, const char
|
||||
{
|
||||
/* 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 @@ static int smp_fetch_hdr_cnt(const struct arg *args, struct sample *smp, const c
|
||||
{
|
||||
/* 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 @@ static int smp_fetch_cookie(const struct arg *args, struct sample *smp, const ch
|
||||
{
|
||||
/* 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 @@ static int smp_fetch_cookie(const struct arg *args, struct sample *smp, const ch
|
||||
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 @@ static int smp_fetch_cookie_cnt(const struct arg *args, struct sample *smp, cons
|
||||
{
|
||||
/* 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 @@ static int smp_fetch_cookie_cnt(const struct arg *args, struct sample *smp, cons
|
||||
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_url_param(const struct arg *args, struct sample *smp, const
|
||||
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 @@ static int smp_fetch_body_param(const struct arg *args, struct sample *smp, cons
|
||||
}
|
||||
|
||||
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 @@ static struct sample_fetch_kw_list sample_fetch_keywords = {ILH, {
|
||||
{ "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 */ },
|
||||
}};
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user