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 },