MINOR: http: add the new sample fetches req.hdr_names and res.hdr_names
These new sample fetches retrieve the list of header names as they appear
in the request or response. This can be used for debugging, for statistics
as well as an aid to better detect the presence of proxies or plugins on
some browsers, which alter the request compared to a regular browser by
adding or reordering headers.
diff --git a/doc/configuration.txt b/doc/configuration.txt
index 971c26e..bb7d567 100644
--- a/doc/configuration.txt
+++ b/doc/configuration.txt
@@ -12218,6 +12218,12 @@
using the "found" matching method. This fetch is the completemnt of "path"
which stops before the question mark.
+req.hdr_names([<delim>]) : string
+ This builds a string made from the concatenation of all header names as they
+ appear in the request when the rule is evaluated. The default delimiter is
+ the comma (',') but it may be overridden as an optional argument <delim>. In
+ this case, only the first character of <delim> is considered.
+
req.ver : string
req_ver : string (deprecated)
Returns the version string from the HTTP request, for example "1.1". This can
@@ -12314,6 +12320,12 @@
Negative values indicate positions relative to the last one, with -1 being
the last one. This can be useful to learn some data into a stick table.
+res.hdr_names([<delim>]) : string
+ This builds a string made from the concatenation of all header names as they
+ appear in the response when the rule is evaluated. The default delimiter is
+ the comma (',') but it may be overridden as an optional argument <delim>. In
+ this case, only the first character of <delim> is considered.
+
res.hdr_val([<name>[,<occ>]]) : integer
shdr_val([<name>[,<occ>]]) : integer (deprecated)
This extracts the last occurrence of header <name> in an HTTP response, and
diff --git a/src/proto_http.c b/src/proto_http.c
index 0a6ef9f..4484bcf 100644
--- a/src/proto_http.c
+++ b/src/proto_http.c
@@ -10232,6 +10232,39 @@
return 1;
}
+static int
+smp_fetch_hdr_names(struct proxy *px, struct session *l4, void *l7, unsigned int opt,
+ const struct arg *args, struct sample *smp, const char *kw)
+{
+ struct http_txn *txn = l7;
+ struct hdr_idx *idx = &txn->hdr_idx;
+ struct hdr_ctx ctx;
+ const struct http_msg *msg = ((opt & SMP_OPT_DIR) == SMP_OPT_DIR_REQ) ? &txn->req : &txn->rsp;
+ struct chunk *temp;
+ char del = ',';
+
+ if (args && args->type == ARGT_STR)
+ del = *args[0].data.str.str;
+
+ CHECK_HTTP_MESSAGE_FIRST();
+
+ temp = get_trash_chunk();
+
+ ctx.idx = 0;
+ while (http_find_next_header(msg->chn->buf->p, idx, &ctx)) {
+ if (temp->len)
+ temp->str[temp->len++] = del;
+ memcpy(temp->str + temp->len, ctx.line, ctx.del);
+ temp->len += ctx.del;
+ }
+
+ smp->type = SMP_T_STR;
+ smp->data.str.str = temp->str;
+ smp->data.str.len = temp->len;
+ smp->flags = SMP_F_VOL_HDR;
+ return 1;
+}
+
/* Fetch an HTTP header. A pointer to the beginning of the value is returned.
* Accepts an optional argument of type string containing the header field name,
* and an optional argument of type signed or unsigned integer to request an
@@ -11884,6 +11917,7 @@
{ "req.hdr", smp_fetch_hdr, ARG2(0,STR,SINT), val_hdr, SMP_T_STR, SMP_USE_HRQHV },
{ "req.hdr_cnt", smp_fetch_hdr_cnt, ARG1(0,STR), NULL, SMP_T_UINT, SMP_USE_HRQHV },
{ "req.hdr_ip", smp_fetch_hdr_ip, ARG2(0,STR,SINT), val_hdr, SMP_T_IPV4, SMP_USE_HRQHV },
+ { "req.hdr_names", smp_fetch_hdr_names, ARG1(0,STR), NULL, SMP_T_STR, SMP_USE_HRQHV },
{ "req.hdr_val", smp_fetch_hdr_val, ARG2(0,STR,SINT), val_hdr, SMP_T_UINT, SMP_USE_HRQHV },
/* explicit req.{cook,hdr} are used to force the fetch direction to be response-only */
@@ -11896,6 +11930,7 @@
{ "res.hdr", smp_fetch_hdr, ARG2(0,STR,SINT), val_hdr, SMP_T_STR, SMP_USE_HRSHV },
{ "res.hdr_cnt", smp_fetch_hdr_cnt, ARG1(0,STR), NULL, SMP_T_UINT, SMP_USE_HRSHV },
{ "res.hdr_ip", smp_fetch_hdr_ip, ARG2(0,STR,SINT), val_hdr, SMP_T_IPV4, SMP_USE_HRSHV },
+ { "res.hdr_names", smp_fetch_hdr_names, ARG1(0,STR), NULL, SMP_T_STR, SMP_USE_HRSHV },
{ "res.hdr_val", smp_fetch_hdr_val, ARG2(0,STR,SINT), val_hdr, SMP_T_UINT, SMP_USE_HRSHV },
/* scook is valid only on the response and is used for ACL compatibility */