MINOR: Add binary encoding request header sample fetch
This sample fetch encodes the http request headers in binary
format. This sample-fetch is useful with SPOE.
diff --git a/doc/configuration.txt b/doc/configuration.txt
index f1afbc9..1cb9b63 100644
--- a/doc/configuration.txt
+++ b/doc/configuration.txt
@@ -14167,6 +14167,19 @@
(eg: "stick on", "stick match"), and for "res.payload_lv" when used in the
context of a response such as in "stick store response".
+req.hdrs_bin : binary
+ Returns the current request headers contained in preparsed binary form. This
+ is useful for offloading some processing with SPOE. Each string is described
+ by a length followed by the number of bytes indicated in the length. The
+ length is represented using the variable integer encoding detailed in the
+ SPOE documentation. The end of the list is marked by a couple of empty header
+ names and values (length of 0 for both).
+
+ *(<str:header-name><str:header-value>)<empty string><empty string>
+
+ int: refer to the SPOE documentation for the encoding
+ str: <int:length><bytes>
+
req.len : integer
req_len : integer (deprecated)
Returns an integer value corresponding to the number of bytes present in the
diff --git a/src/proto_http.c b/src/proto_http.c
index 6c940f1..2dd2ad4 100644
--- a/src/proto_http.c
+++ b/src/proto_http.c
@@ -10437,6 +10437,116 @@
return 1;
}
+/* Returns the header request in a length/value encoded format.
+ * This is useful for exchanges with the SPOE.
+ *
+ * A "length value" is a multibyte code encoding numbers. It uses the
+ * SPOE format. The encoding is the following:
+ *
+ * Each couple "header name" / "header value" is composed
+ * like this:
+ * "length value" "header name bytes"
+ * "length value" "header value bytes"
+ * When the last header is reached, the header name and the header
+ * value are empty. Their length are 0
+ */
+static int
+smp_fetch_hdrs_bin(const struct arg *args, struct sample *smp, const char *kw, void *private)
+{
+ struct http_msg *msg;
+ struct chunk *temp;
+ struct hdr_idx *idx;
+ const char *cur_ptr, *cur_next, *p;
+ int old_idx, cur_idx;
+ struct hdr_idx_elem *cur_hdr;
+ const char *hn, *hv;
+ int hnl, hvl;
+ int ret;
+ struct http_txn *txn;
+ char *buf;
+ char *end;
+
+ CHECK_HTTP_MESSAGE_FIRST();
+
+ temp = get_trash_chunk();
+ buf = temp->str;
+ end = temp->str + temp->size;
+
+ txn = smp->strm->txn;
+ idx = &txn->hdr_idx;
+ msg = &txn->req;
+
+ /* Build array of headers. */
+ old_idx = 0;
+ cur_next = msg->chn->buf->p + hdr_idx_first_pos(idx);
+ while (1) {
+ cur_idx = idx->v[old_idx].next;
+ if (!cur_idx)
+ break;
+ old_idx = cur_idx;
+
+ cur_hdr = &idx->v[cur_idx];
+ cur_ptr = cur_next;
+ cur_next = cur_ptr + cur_hdr->len + cur_hdr->cr + 1;
+
+ /* Now we have one full header at cur_ptr of len cur_hdr->len,
+ * and the next header starts at cur_next. We'll check
+ * this header in the list as well as against the default
+ * rule.
+ */
+
+ /* look for ': *'. */
+ hn = cur_ptr;
+ for (p = cur_ptr; p < cur_ptr + cur_hdr->len && *p != ':'; p++);
+ if (p >= cur_ptr+cur_hdr->len)
+ continue;
+ hnl = p - hn;
+ p++;
+ while (p < cur_ptr + cur_hdr->len && (*p == ' ' || *p == '\t'))
+ p++;
+ if (p >= cur_ptr + cur_hdr->len)
+ continue;
+ hv = p;
+ hvl = cur_ptr + cur_hdr->len-p;
+
+ /* encode the header name. */
+ ret = encode_varint(hnl, &buf, end);
+ if (ret == -1)
+ return 0;
+ if (buf + hnl > end)
+ return 0;
+ memcpy(buf, hn, hnl);
+ buf += hnl;
+
+ /* encode and copy the value. */
+ ret = encode_varint(hvl, &buf, end);
+ if (ret == -1)
+ return 0;
+ if (buf + hvl > end)
+ return 0;
+ memcpy(buf, hv, hvl);
+ buf += hvl;
+ }
+
+ /* encode the end of the header list with empty
+ * header name and header value.
+ */
+ ret = encode_varint(0, &buf, end);
+ if (ret == -1)
+ return 0;
+ ret = encode_varint(0, &buf, end);
+ if (ret == -1)
+ return 0;
+
+ /* Initialise sample data which will be filled. */
+ smp->data.type = SMP_T_BIN;
+ smp->data.u.str.str = temp->str;
+ smp->data.u.str.len = buf - temp->str;
+ smp->data.u.str.size = temp->size;
+
+ return 1;
+}
+
/* returns the longest available part of the body. This requires that the body
* has been waited for using http-buffer-request.
*/
@@ -13347,6 +13457,8 @@
{ "req.body_size", smp_fetch_body_size, 0, NULL, SMP_T_SINT, SMP_USE_HRQHV },
{ "req.body_param", smp_fetch_body_param, ARG1(0,STR), NULL, SMP_T_BIN, SMP_USE_HRQHV },
+ { "req.hdrs_bin", smp_fetch_hdrs_bin, 0, NULL, SMP_T_BIN, SMP_USE_HRQHV },
+
/* HTTP version on the response path */
{ "res.ver", smp_fetch_stver, 0, NULL, SMP_T_STR, SMP_USE_HRSHV },
{ "resp_ver", smp_fetch_stver, 0, NULL, SMP_T_STR, SMP_USE_HRSHV },