diff --git a/doc/configuration.txt b/doc/configuration.txt index 0a3206423..763e4ad7a 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -17506,14 +17506,31 @@ placed in the dedicated scope "check". Other sample fetches may also be called when an health-check is performed if it makes sense and if the sample fetch was adapted to be called in this context. -check.payload(,) : binary - This extracts a binary block of bytes and starting at byte - in the check input buffer. As a special case, if the argument is - zero, then the whole buffer from to the end is extracted. This can - be called from a tcp-check expect rule, or eventually from a set-var rule - after an expect rule and before a send rule (check input buffer is filled on +check.len : integer + Returns an integer value corresponding to the number of bytes present in the + check input buffer, containing the data received from the server. This can be + called from a tcp-check expect rule, or eventually from a set-var rule after + an expect rule and before a send rule (check input buffer is filled on tcp-check expect rules and reset on tcp-check send rules). +check.payload(,) : binary + This extracts a binary block of bytes and starting at byte + in the check input buffer, containing data received from the server. As a + special case, if the argument is zero, then the whole buffer from + to the end is extracted. This can be called from a tcp-check expect + rule, or eventually from a set-var rule after an expect rule and before a + send rule (check input buffer is filled on tcp-check expect rules and reset + on tcp-check send rules). + +check.payload_lv(,[,]) : binary + This extracts a binary block whose size is specified at for + bytes, and which starts at if specified or just after the + length in the check input buffer, containing data received from the + server. The parameter also supports relative offsets if prepended + with a '+' or '-' sign. This can be called from a tcp-check expect rule, or + eventually from a set-var rule after an expect rule and before a send rule + (check input buffer is filled on tcp-check expect rules and reset on + tcp-check send rules). 7.3.8. Fetching samples for developers --------------------------------------- diff --git a/src/checks.c b/src/checks.c index 7c75a1d84..1249b2410 100644 --- a/src/checks.c +++ b/src/checks.c @@ -1087,8 +1087,10 @@ static void tcpcheck_expect_onerror_message(struct buffer *msg, struct check *ch */ if (rule->expect.status_expr) { smp = sample_fetch_as_type(check->proxy, check->sess, NULL, SMP_OPT_DIR_RES | SMP_OPT_FINAL, - rule->expect.status_expr, SMP_T_SINT); - if (smp) + rule->expect.status_expr, SMP_T_STR); + + if (smp && sample_casts[smp->data.type][SMP_T_SINT] && + sample_casts[smp->data.type][SMP_T_SINT](smp)) check->code = smp->data.u.sint; } @@ -1122,8 +1124,10 @@ static void tcpcheck_expect_onsuccess_message(struct buffer *msg, struct check * */ if (rule->expect.status_expr) { smp = sample_fetch_as_type(check->proxy, check->sess, NULL, SMP_OPT_DIR_RES | SMP_OPT_FINAL, - rule->expect.status_expr, SMP_T_SINT); - if (smp) + rule->expect.status_expr, SMP_T_STR); + + if (smp && sample_casts[smp->data.type][SMP_T_SINT] && + sample_casts[smp->data.type][SMP_T_SINT](smp)) check->code = smp->data.u.sint; } @@ -5489,38 +5493,8 @@ void send_email_alert(struct server *s, int level, const char *format, ...) /**************************************************************************/ /************************** Check sample fetches **************************/ /**************************************************************************/ -/* extracts check payload at a fixed position and length */ -static int -smp_fetch_chk_payload(const struct arg *arg_p, struct sample *smp, const char *kw, void *private) -{ - unsigned int buf_offset = ((arg_p[0].type == ARGT_SINT) ? arg_p[0].data.sint : 0); - unsigned int buf_size = ((arg_p[1].type == ARGT_SINT) ? arg_p[1].data.sint : 0); - struct check *check = (smp->sess ? objt_check(smp->sess->origin) : NULL); - struct buffer *buf; - - if (!check) - return 0; - - buf = &check->bi; - if (buf_offset > b_data(buf)) - goto no_match; - if (buf_offset + buf_size > b_data(buf)) - buf_size = 0; - - /* init chunk as read only */ - smp->data.type = SMP_T_STR; - smp->flags = SMP_F_VOLATILE | SMP_F_CONST; - chunk_initlen(&smp->data.u.str, b_head(buf) + buf_offset, 0, (buf_size ? buf_size : (b_data(buf) - buf_offset))); - - return 1; - - no_match: - smp->flags = 0; - return 0; -} static struct sample_fetch_kw_list smp_kws = {ILH, { - { "check.payload", smp_fetch_chk_payload, ARG2(0,SINT,SINT), NULL, SMP_T_STR, SMP_USE_INTRN }, { /* END */ }, }}; @@ -5873,7 +5847,7 @@ int proxy_parse_redis_check_opt(char **args, int cur_arg, struct proxy *curpx, s chk = parse_tcpcheck_expect((char *[]){"tcp-check", "expect", "string", redis_res, "error-status", "L7STS", - "on-error", "%[check.payload(),cut_crlf]", + "on-error", "%[check.payload(0,0),cut_crlf]", "on-success", "Redis server is ok", ""}, 1, curpx, &rs->rules, TCPCHK_RULES_REDIS_CHK, file, line, &errmsg); @@ -6075,7 +6049,7 @@ int proxy_parse_smtpchk_opt(char **args, int cur_arg, struct proxy *curpx, struc chk = parse_tcpcheck_expect((char *[]){"tcp-check", "expect", "rstring", "^[0-9]{3}[ \r]", "min-recv", "4", "error-status", "L7RSP", - "on-error", "%[check.payload(),cut_crlf]", + "on-error", "%[check.payload(0,0),cut_crlf]", ""}, 1, curpx, &rs->rules, TCPCHK_RULES_SMTP_CHK, file, line, &errmsg); if (!chk) { diff --git a/src/payload.c b/src/payload.c index 5665794bc..43cf2fb7f 100644 --- a/src/payload.c +++ b/src/payload.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -48,19 +49,23 @@ smp_fetch_wait_end(const struct arg *args, struct sample *smp, const char *kw, v static int smp_fetch_len(const struct arg *args, struct sample *smp, const char *kw, void *private) { - struct channel *chn; - - if (!smp->strm) - return 0; - - chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : &smp->strm->req; - smp->data.type = SMP_T_SINT; - if (IS_HTX_STRM(smp->strm)) { - struct htx *htx = htxbuf(&chn->buf); - smp->data.u.sint = htx->data - co_data(chn); + if (smp->strm) { + struct channel *chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : &smp->strm->req; + if (IS_HTX_STRM(smp->strm)) { + struct htx *htx = htxbuf(&chn->buf); + smp->data.u.sint = htx->data - co_data(chn); + } + else + smp->data.u.sint = ci_data(chn); + } + else if (smp->sess && obj_type(smp->sess->origin) == OBJ_TYPE_CHECK) { + struct check *check = __objt_check(smp->sess->origin); + smp->data.u.sint = ((check->cs && IS_HTX_CS(check->cs)) ? (htxbuf(&check->bi))->data: b_data(&check->bi)); } else - smp->data.u.sint = ci_data(chn); + return 0; + + smp->data.type = SMP_T_SINT; smp->flags = SMP_F_VOLATILE | SMP_F_MAY_CHANGE; return 1; } @@ -959,22 +964,35 @@ smp_fetch_payload_lv(const struct arg *arg_p, struct sample *smp, const char *kw unsigned int len_size = arg_p[1].data.sint; unsigned int buf_offset; unsigned int buf_size = 0; - struct channel *chn; + struct channel *chn = NULL; + char *head = NULL; + size_t max, data; int i; /* Format is (len offset, len size, buf offset) or (len offset, len size) */ /* by default buf offset == len offset + len size */ /* buf offset could be absolute or relative to len offset + len size if prefixed by + or - */ - if (!smp->strm) + if (smp->strm) { + chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : &smp->strm->req; + head = ci_head(chn); + data = ci_data(chn); + max = global.tune.bufsize; + } + else if (smp->sess && obj_type(smp->sess->origin) == OBJ_TYPE_CHECK) { + struct buffer *buf = &(__objt_check(smp->sess->origin)->bi); + head = b_head(buf); + data = b_data(buf); + max = global.tune.chksize; + } + if (!head) return 0; - chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : &smp->strm->req; - if (len_offset + len_size > ci_data(chn)) + if (len_offset + len_size > data) goto too_short; for (i = 0; i < len_size; i++) { - buf_size = (buf_size << 8) + ((unsigned char *)ci_head(chn))[i + len_offset]; + buf_size = (buf_size << 8) + ((unsigned char *)head)[i + len_offset]; } /* buf offset may be implicit, absolute or relative. If the LSB @@ -988,19 +1006,19 @@ smp_fetch_payload_lv(const struct arg *arg_p, struct sample *smp, const char *kw buf_offset = arg_p[2].data.sint >> 1; } - if (!buf_size || buf_size > global.tune.bufsize || buf_offset + buf_size > global.tune.bufsize) { + if (!buf_size || buf_size > max || buf_offset + buf_size > max) { /* will never match */ smp->flags = 0; return 0; } - if (buf_offset + buf_size > ci_data(chn)) + if (buf_offset + buf_size > data) goto too_short; /* init chunk as read only */ smp->data.type = SMP_T_BIN; smp->flags = SMP_F_VOLATILE | SMP_F_CONST; - chunk_initlen(&smp->data.u.str, ci_head(chn) + buf_offset, 0, buf_size); + chunk_initlen(&smp->data.u.str, head + buf_offset, 0, buf_size); return 1; too_short: @@ -1014,31 +1032,44 @@ smp_fetch_payload(const struct arg *arg_p, struct sample *smp, const char *kw, v { unsigned int buf_offset = arg_p[0].data.sint; unsigned int buf_size = arg_p[1].data.sint; - struct channel *chn; + struct channel *chn = NULL; + char *head = NULL; + size_t max, data; - if (!smp->strm) + if (smp->strm) { + chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : &smp->strm->req; + head = ci_head(chn); + data = ci_data(chn); + max = global.tune.bufsize; + } + else if (smp->sess && obj_type(smp->sess->origin) == OBJ_TYPE_CHECK) { + struct buffer *buf = &(__objt_check(smp->sess->origin)->bi); + head = b_head(buf); + data = b_data(buf); + max = global.tune.chksize; + } + if (!head) return 0; - chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : &smp->strm->req; - if (buf_size > global.tune.bufsize || buf_offset + buf_size > global.tune.bufsize) { + if (buf_size > max || buf_offset + buf_size > max) { /* will never match */ smp->flags = 0; return 0; } - - if (buf_offset + buf_size > ci_data(chn)) + if (buf_offset + buf_size > data) goto too_short; /* init chunk as read only */ smp->data.type = SMP_T_BIN; smp->flags = SMP_F_VOLATILE | SMP_F_CONST; - chunk_initlen(&smp->data.u.str, ci_head(chn) + buf_offset, 0, buf_size ? buf_size : (ci_data(chn) - buf_offset)); - if (!buf_size && channel_may_recv(chn) && !channel_input_closed(chn)) + chunk_initlen(&smp->data.u.str, head + buf_offset, 0, buf_size ? buf_size : (data - buf_offset)); + + if (!buf_size && chn && channel_may_recv(chn) && !channel_input_closed(chn)) smp->flags |= SMP_F_MAY_CHANGE; return 1; - too_short: + too_short: smp->flags = SMP_F_MAY_CHANGE | SMP_F_CONST; return 0; } @@ -1328,6 +1359,10 @@ static struct sample_fetch_kw_list smp_kws = {ILH, { { "res.payload_lv", smp_fetch_payload_lv, ARG3(2,SINT,SINT,STR), val_payload_lv, SMP_T_BIN, SMP_USE_L6RES }, { "res.ssl_hello_type", smp_fetch_ssl_hello_type, 0, NULL, SMP_T_SINT, SMP_USE_L6RES }, { "wait_end", smp_fetch_wait_end, 0, NULL, SMP_T_BOOL, SMP_USE_INTRN }, + + { "check.len", smp_fetch_len, 0, NULL, SMP_T_SINT, SMP_USE_INTRN }, + { "check.payload", smp_fetch_payload, ARG2(2,SINT,SINT), NULL, SMP_T_BIN, SMP_USE_INTRN }, + { "check.payload_lv", smp_fetch_payload_lv, ARG3(2,SINT,SINT,STR), val_payload_lv, SMP_T_BIN, SMP_USE_INTRN }, { /* END */ }, }};