MINOR: http-htx: Add some htx sample fetches for debugging purpose
These sample fetches are internal and must be used for debugging purpose. Idea
is to have a way to add some checks on the HTX content from http rules. The main
purpose is to ease reg-tests writing.
diff --git a/src/http_htx.c b/src/http_htx.c
index 71a952d..f9137db 100644
--- a/src/http_htx.c
+++ b/src/http_htx.c
@@ -17,7 +17,10 @@
#include <common/http.h>
#include <common/htx.h>
+#include <proto/arg.h>
#include <proto/http_htx.h>
+#include <proto/http_fetch.h>
+#include <proto/sample.h>
struct buffer http_err_chunks[HTTP_ERR_SIZE];
@@ -828,3 +831,513 @@
}
REGISTER_CONFIG_POSTPARSER("http_htx", http_htx_init);
+
+/************************************************************************/
+/* HTX sample fetches */
+/************************************************************************/
+
+/* Returns 1 if a stream is an HTX stream. Otherwise, it returns 0. */
+static int
+smp_fetch_is_htx(const struct arg *arg_p, struct sample *smp, const char *kw, void *private)
+{
+ if (!smp->strm)
+ return 0;
+
+ smp->data.u.sint = !!IS_HTX_STRM(smp->strm);
+ smp->data.type = SMP_T_BOOL;
+ return 1;
+}
+
+/* Returns the number of blocks in an HTX message. The channel is chosen
+ * depending on the sample direction. */
+static int
+smp_fetch_htx_nbblks(const struct arg *arg_p, struct sample *smp, const char *kw, void *private)
+{
+ struct channel *chn;
+ struct htx *htx;
+
+ if (!smp->strm)
+ return 0;
+
+ chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : &smp->strm->req;
+ htx = smp_prefetch_htx(smp, chn, 0);
+ if (!htx)
+ return 0;
+
+ smp->data.u.sint = htx_nbblks(htx);
+ smp->data.type = SMP_T_SINT;
+ smp->flags = SMP_F_VOLATILE | SMP_F_MAY_CHANGE;
+ return 1;
+}
+
+/* Returns the size of an HTX message. The channel is chosen depending on the
+ * sample direction. */
+static int
+smp_fetch_htx_size(const struct arg *arg_p, struct sample *smp, const char *kw, void *private)
+{
+ struct channel *chn;
+ struct htx *htx;
+
+ if (!smp->strm)
+ return 0;
+
+ chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : &smp->strm->req;
+ htx = smp_prefetch_htx(smp, chn, 0);
+ if (!htx)
+ return 0;
+
+ smp->data.u.sint = htx->size;
+ smp->data.type = SMP_T_SINT;
+ smp->flags = SMP_F_VOLATILE | SMP_F_MAY_CHANGE;
+ return 1;
+}
+
+/* Returns the data size of an HTX message. The channel is chosen depending on the
+ * sample direction. */
+static int
+smp_fetch_htx_data(const struct arg *arg_p, struct sample *smp, const char *kw, void *private)
+{
+ struct channel *chn;
+ struct htx *htx;
+
+ if (!smp->strm)
+ return 0;
+
+ chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : &smp->strm->req;
+ htx = smp_prefetch_htx(smp, chn, 0);
+ if (!htx)
+ return 0;
+
+ smp->data.u.sint = htx->data;
+ smp->data.type = SMP_T_SINT;
+ smp->flags = SMP_F_VOLATILE | SMP_F_MAY_CHANGE;
+ return 1;
+}
+
+/* Returns the used space (data+meta) of an HTX message. The channel is chosen
+ * depending on the sample direction. */
+static int
+smp_fetch_htx_used(const struct arg *arg_p, struct sample *smp, const char *kw, void *private)
+{
+ struct channel *chn;
+ struct htx *htx;
+
+ if (!smp->strm)
+ return 0;
+
+ chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : &smp->strm->req;
+ htx = smp_prefetch_htx(smp, chn, 0);
+ if (!htx)
+ return 0;
+
+ smp->data.u.sint = htx_used_space(htx);
+ smp->data.type = SMP_T_SINT;
+ smp->flags = SMP_F_VOLATILE | SMP_F_MAY_CHANGE;
+ return 1;
+}
+
+/* Returns the free space (size-used) of an HTX message. The channel is chosen
+ * depending on the sample direction. */
+static int
+smp_fetch_htx_free(const struct arg *arg_p, struct sample *smp, const char *kw, void *private)
+{
+ struct channel *chn;
+ struct htx *htx;
+
+ if (!smp->strm)
+ return 0;
+
+ chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : &smp->strm->req;
+ htx = smp_prefetch_htx(smp, chn, 0);
+ if (!htx)
+ return 0;
+
+ smp->data.u.sint = htx_free_space(htx);
+ smp->data.type = SMP_T_SINT;
+ smp->flags = SMP_F_VOLATILE | SMP_F_MAY_CHANGE;
+ return 1;
+}
+
+/* Returns the free space for data (free-sizeof(blk)) of an HTX message. The
+ * channel is chosen depending on the sample direction. */
+static int
+smp_fetch_htx_free_data(const struct arg *arg_p, struct sample *smp, const char *kw, void *private)
+{
+ struct channel *chn;
+ struct htx *htx;
+
+ if (!smp->strm)
+ return 0;
+
+ chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : &smp->strm->req;
+ htx = smp_prefetch_htx(smp, chn, 0);
+ if (!htx)
+ return 0;
+
+ smp->data.u.sint = htx_free_data_space(htx);
+ smp->data.type = SMP_T_SINT;
+ smp->flags = SMP_F_VOLATILE | SMP_F_MAY_CHANGE;
+ return 1;
+}
+
+/* Returns 1 if the HTX message contains an EOM block. Otherwise it returns
+ * 0. Concretely, it only checks the tail. The channel is chosen depending on
+ * the sample direction. */
+static int
+smp_fetch_htx_has_eom(const struct arg *arg_p, struct sample *smp, const char *kw, void *private)
+{
+ struct channel *chn;
+ struct htx *htx;
+
+ if (!smp->strm)
+ return 0;
+
+ chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : &smp->strm->req;
+ htx = smp_prefetch_htx(smp, chn, 0);
+ if (!htx)
+ return 0;
+
+ smp->data.u.sint = (htx_get_tail_type(htx) == HTX_BLK_EOM);
+ smp->data.type = SMP_T_BOOL;
+ smp->flags = SMP_F_VOLATILE | SMP_F_MAY_CHANGE;
+ return 1;
+}
+
+/* Returns the type of a specific HTX block, if found in the message. Otherwise
+ * HTX_BLK_UNUSED is returned. Any positive integer (>= 0) is supported or
+ * "head", "tail" or "first". The channel is chosen depending on the sample
+ * direction. */
+static int
+smp_fetch_htx_blk_type(const struct arg *arg_p, struct sample *smp, const char *kw, void *private)
+{
+ struct channel *chn;
+ struct htx *htx;
+ enum htx_blk_type type;
+ int32_t pos;
+
+ if (!smp->strm || !arg_p)
+ return 0;
+
+ chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : &smp->strm->req;
+ htx = smp_prefetch_htx(smp, chn, 0);
+ if (!htx)
+ return 0;
+
+ pos = arg_p[0].data.sint;
+ if (pos == -1)
+ type = htx_get_head_type(htx);
+ else if (pos == -2)
+ type = htx_get_tail_type(htx);
+ else if (pos == -3)
+ type = htx_get_first_type(htx);
+ else
+ type = ((pos >= htx->head && pos <= htx->tail)
+ ? htx_get_blk_type(htx_get_blk(htx, pos))
+ : HTX_BLK_UNUSED);
+
+ chunk_initstr(&smp->data.u.str, htx_blk_type_str(type));
+ smp->data.type = SMP_T_STR;
+ smp->flags = SMP_F_CONST | SMP_F_VOLATILE | SMP_F_MAY_CHANGE;
+ return 1;
+}
+
+/* Returns the size of a specific HTX block, if found in the message. Otherwise
+ * 0 is returned. Any positive integer (>= 0) is supported or "head", "tail" or
+ * "first". The channel is chosen depending on the sample direction. */
+static int
+smp_fetch_htx_blk_size(const struct arg *arg_p, struct sample *smp, const char *kw, void *private)
+{
+ struct channel *chn;
+ struct htx *htx;
+ struct htx_blk *blk;
+ int32_t pos;
+
+ if (!smp->strm || !arg_p)
+ return 0;
+
+ chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : &smp->strm->req;
+ htx = smp_prefetch_htx(smp, chn, 0);
+ if (!htx)
+ return 0;
+
+ pos = arg_p[0].data.sint;
+ if (pos == -1)
+ blk = htx_get_head_blk(htx);
+ else if (pos == -2)
+ blk = htx_get_tail_blk(htx);
+ else if (pos == -3)
+ blk = htx_get_first_blk(htx);
+ else
+ blk = ((pos >= htx->head && pos <= htx->tail) ? htx_get_blk(htx, pos) : NULL);
+
+ smp->data.u.sint = (blk ? htx_get_blksz(blk) : 0);
+ smp->data.type = SMP_T_SINT;
+ smp->flags = SMP_F_VOLATILE | SMP_F_MAY_CHANGE;
+ return 1;
+}
+
+/* Returns the start-line if the selected HTX block exists and is a
+ * start-line. Otherwise 0 an empty string. Any positive integer (>= 0) is
+ * supported or "head", "tail" or "first". The channel is chosen depending on
+ * the sample direction. */
+static int
+smp_fetch_htx_blk_stline(const struct arg *arg_p, struct sample *smp, const char *kw, void *private)
+{
+ struct buffer *temp;
+ struct channel *chn;
+ struct htx *htx;
+ struct htx_blk *blk;
+ struct htx_sl *sl;
+ int32_t pos;
+
+ if (!smp->strm || !arg_p)
+ return 0;
+
+ chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : &smp->strm->req;
+ htx = smp_prefetch_htx(smp, chn, 0);
+ if (!htx)
+ return 0;
+
+ pos = arg_p[0].data.sint;
+ if (pos == -1)
+ blk = htx_get_head_blk(htx);
+ else if (pos == -2)
+ blk = htx_get_tail_blk(htx);
+ else if (pos == -3)
+ blk = htx_get_first_blk(htx);
+ else
+ blk = ((pos >= htx->head && pos <= htx->tail) ? htx_get_blk(htx, pos) : NULL);
+
+ if (!blk || (htx_get_blk_type(blk) != HTX_BLK_REQ_SL && htx_get_blk_type(blk) != HTX_BLK_RES_SL)) {
+ smp->data.u.str.size = 0;
+ smp->data.u.str.area = "";
+ smp->data.u.str.data = 0;
+ }
+ else {
+ sl = htx_get_blk_ptr(htx, blk);
+
+ temp = get_trash_chunk();
+ chunk_istcat(temp, htx_sl_p1(sl));
+ temp->area[temp->data++] = ' ';
+ chunk_istcat(temp, htx_sl_p2(sl));
+ temp->area[temp->data++] = ' ';
+ chunk_istcat(temp, htx_sl_p3(sl));
+
+ smp->data.u.str = *temp;
+ }
+
+ smp->data.type = SMP_T_STR;
+ smp->flags = SMP_F_VOLATILE | SMP_F_MAY_CHANGE;
+ return 1;
+}
+
+/* Returns the header name if the selected HTX block exists and is a header or a
+ * trailer. Otherwise 0 an empty string. Any positive integer (>= 0) is
+ * supported or "head", "tail" or "first". The channel is chosen depending on
+ * the sample direction. */
+static int
+smp_fetch_htx_blk_hdrname(const struct arg *arg_p, struct sample *smp, const char *kw, void *private)
+{
+ struct channel *chn;
+ struct htx *htx;
+ struct htx_blk *blk;
+ int32_t pos;
+
+ if (!smp->strm || !arg_p)
+ return 0;
+
+ chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : &smp->strm->req;
+ htx = smp_prefetch_htx(smp, chn, 0);
+ if (!htx)
+ return 0;
+
+ pos = arg_p[0].data.sint;
+ if (pos == -1)
+ blk = htx_get_head_blk(htx);
+ else if (pos == -2)
+ blk = htx_get_tail_blk(htx);
+ else if (pos == -3)
+ blk = htx_get_first_blk(htx);
+ else
+ blk = ((pos >= htx->head && pos <= htx->tail) ? htx_get_blk(htx, pos) : NULL);
+
+ if (!blk || (htx_get_blk_type(blk) != HTX_BLK_HDR && htx_get_blk_type(blk) != HTX_BLK_TLR)) {
+ smp->data.u.str.size = 0;
+ smp->data.u.str.area = "";
+ smp->data.u.str.data = 0;
+ }
+ else {
+ struct ist name = htx_get_blk_name(htx, blk);
+
+ chunk_initlen(&smp->data.u.str, name.ptr, name.len, name.len);
+ }
+ smp->data.type = SMP_T_STR;
+ smp->flags = SMP_F_CONST | SMP_F_VOLATILE | SMP_F_MAY_CHANGE;
+ return 1;
+}
+
+/* Returns the header value if the selected HTX block exists and is a header or
+ * a trailer. Otherwise 0 an empty string. Any positive integer (>= 0) is
+ * supported or "head", "tail" or "first". The channel is chosen depending on
+ * the sample direction. */
+static int
+smp_fetch_htx_blk_hdrval(const struct arg *arg_p, struct sample *smp, const char *kw, void *private)
+{
+ struct channel *chn;
+ struct htx *htx;
+ struct htx_blk *blk;
+ int32_t pos;
+
+ if (!smp->strm || !arg_p)
+ return 0;
+
+ chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : &smp->strm->req;
+ htx = smp_prefetch_htx(smp, chn, 0);
+ if (!htx)
+ return 0;
+
+ pos = arg_p[0].data.sint;
+ if (pos == -1)
+ blk = htx_get_head_blk(htx);
+ else if (pos == -2)
+ blk = htx_get_tail_blk(htx);
+ else if (pos == -3)
+ blk = htx_get_first_blk(htx);
+ else
+ blk = ((pos >= htx->head && pos <= htx->tail) ? htx_get_blk(htx, pos) : NULL);
+
+ if (!blk || (htx_get_blk_type(blk) != HTX_BLK_HDR && htx_get_blk_type(blk) != HTX_BLK_TLR)) {
+ smp->data.u.str.size = 0;
+ smp->data.u.str.area = "";
+ smp->data.u.str.data = 0;
+ }
+ else {
+ struct ist val = htx_get_blk_value(htx, blk);
+
+ chunk_initlen(&smp->data.u.str, val.ptr, val.len, val.len);
+ }
+ smp->data.type = SMP_T_STR;
+ smp->flags = SMP_F_CONST | SMP_F_VOLATILE | SMP_F_MAY_CHANGE;
+ return 1;
+}
+
+/* Returns the value if the selected HTX block exists and is a data
+ * block. Otherwise 0 an empty string. Any positive integer (>= 0) is supported
+ * or "head", "tail" or "first". The channel is chosen depending on the sample
+ * direction. */
+static int
+smp_fetch_htx_blk_val(const struct arg *arg_p, struct sample *smp, const char *kw, void *private)
+{
+ struct channel *chn;
+ struct htx *htx;
+ struct htx_blk *blk;
+ int32_t pos;
+
+ if (!smp->strm || !arg_p)
+ return 0;
+
+ chn = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) ? &smp->strm->res : &smp->strm->req;
+ htx = smp_prefetch_htx(smp, chn, 0);
+ if (!htx)
+ return 0;
+
+ pos = arg_p[0].data.sint;
+ if (pos == -1)
+ blk = htx_get_head_blk(htx);
+ else if (pos == -2)
+ blk = htx_get_tail_blk(htx);
+ else if (pos == -3)
+ blk = htx_get_first_blk(htx);
+ else
+ blk = ((pos >= htx->head && pos <= htx->tail) ? htx_get_blk(htx, pos) : NULL);
+
+ if (!blk || htx_get_blk_type(blk) != HTX_BLK_DATA) {
+ smp->data.u.str.size = 0;
+ smp->data.u.str.area = "";
+ smp->data.u.str.data = 0;
+ }
+ else {
+ struct ist val = htx_get_blk_value(htx, blk);
+
+ chunk_initlen(&smp->data.u.str, val.ptr, val.len, val.len);
+ }
+ smp->data.type = SMP_T_STR;
+ smp->flags = SMP_F_CONST | SMP_F_VOLATILE | SMP_F_MAY_CHANGE;
+ return 1;
+}
+
+/* This function is used to validate the arguments passed to any "htx_blk" fetch
+ * keywords. An argument is expected by these keywords. It must be a positive
+ * integer or on of the following strings: "head", "tail" or "first". It returns
+ * 0 on error, and a non-zero value if OK.
+ */
+int val_blk_arg(struct arg *arg, char **err_msg)
+{
+ if (arg[0].type != ARGT_STR || !arg[0].data.str.data) {
+ memprintf(err_msg, "a block position is expected (> 0) or a special block name (head, tail, first)");
+ return 0;
+ }
+ if (arg[0].data.str.data == 4 && !strncmp(arg[0].data.str.area, "head", 4)) {
+ free(arg[0].data.str.area);
+ arg[0].type = ARGT_SINT;
+ arg[0].data.sint = -1;
+ }
+ else if (arg[0].data.str.data == 4 && !strncmp(arg[0].data.str.area, "tail", 4)) {
+ free(arg[0].data.str.area);
+ arg[0].type = ARGT_SINT;
+ arg[0].data.sint = -2;
+ }
+ else if (arg[0].data.str.data == 5 && !strncmp(arg[0].data.str.area, "first", 5)) {
+ free(arg[0].data.str.area);
+ arg[0].type = ARGT_SINT;
+ arg[0].data.sint = -3;
+ }
+ else {
+ int pos;
+
+ for (pos = 0; pos < arg[0].data.str.data; pos++) {
+ if (!isdigit(arg[0].data.str.area[pos])) {
+ memprintf(err_msg, "invalid block position");
+ return 0;
+ }
+ }
+
+ pos = strl2uic(arg[0].data.str.area, arg[0].data.str.data);
+ if (pos < 0) {
+ memprintf(err_msg, "block position must not be negative");
+ return 0;
+ }
+ free(arg[0].data.str.area);
+ arg[0].type = ARGT_SINT;
+ arg[0].data.sint = pos;
+ }
+
+ return 1;
+}
+
+
+/* Note: must not be declared <const> as its list will be overwritten.
+ * Note: htx sample fetches should only used for developpement purpose.
+ */
+static struct sample_fetch_kw_list sample_fetch_keywords = {ILH, {
+ { "strm.is_htx", smp_fetch_is_htx, 0, NULL, SMP_T_BOOL, SMP_USE_L6REQ },
+
+ { "htx.nbblks", smp_fetch_htx_nbblks, 0, NULL, SMP_T_SINT, SMP_USE_HRQHV|SMP_USE_HRSHV},
+ { "htx.size", smp_fetch_htx_size, 0, NULL, SMP_T_SINT, SMP_USE_HRQHV|SMP_USE_HRSHV},
+ { "htx.data", smp_fetch_htx_data, 0, NULL, SMP_T_SINT, SMP_USE_HRQHV|SMP_USE_HRSHV},
+ { "htx.used", smp_fetch_htx_used, 0, NULL, SMP_T_SINT, SMP_USE_HRQHV|SMP_USE_HRSHV},
+ { "htx.free", smp_fetch_htx_free, 0, NULL, SMP_T_SINT, SMP_USE_HRQHV|SMP_USE_HRSHV},
+ { "htx.free_data", smp_fetch_htx_free_data, 0, NULL, SMP_T_SINT, SMP_USE_HRQHV|SMP_USE_HRSHV},
+ { "htx.has_eom", smp_fetch_htx_has_eom, 0, NULL, SMP_T_BOOL, SMP_USE_HRQHV|SMP_USE_HRSHV},
+
+ { "htx_blk.type", smp_fetch_htx_blk_type, ARG1(1,STR), val_blk_arg, SMP_T_STR, SMP_USE_HRQHV|SMP_USE_HRSHV},
+ { "htx_blk.size", smp_fetch_htx_blk_size, ARG1(1,STR), val_blk_arg, SMP_T_SINT, SMP_USE_HRQHV|SMP_USE_HRSHV},
+ { "htx_blk.start_line", smp_fetch_htx_blk_stline, ARG1(1,STR), val_blk_arg, SMP_T_STR, SMP_USE_HRQHV|SMP_USE_HRSHV},
+ { "htx_blk.hdrname", smp_fetch_htx_blk_hdrname, ARG1(1,STR), val_blk_arg, SMP_T_STR, SMP_USE_HRQHV|SMP_USE_HRSHV},
+ { "htx_blk.hdrval", smp_fetch_htx_blk_hdrval, ARG1(1,STR), val_blk_arg, SMP_T_STR, SMP_USE_HRQHV|SMP_USE_HRSHV},
+ { "htx_blk.val", smp_fetch_htx_blk_val, ARG1(1,STR), val_blk_arg, SMP_T_STR, SMP_USE_HRQHV|SMP_USE_HRSHV},
+
+ { /* END */ },
+}};
+
+INITCALL1(STG_REGISTER, sample_register_fetches, &sample_fetch_keywords);