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.
This commit is contained in:
Thierry FOURNIER 2017-04-09 05:38:19 +02:00 committed by Willy Tarreau
parent 6ab2bae084
commit 5617dce27d
2 changed files with 125 additions and 0 deletions

View File

@ -14167,6 +14167,19 @@ payload_lv(<offset1>,<length>[,<offset2>]) : binary (deprecated)
(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

View File

@ -10437,6 +10437,116 @@ smp_fetch_uniqueid(const struct arg *args, struct sample *smp, const char *kw, v
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 @@ static struct sample_fetch_kw_list sample_fetch_keywords = {ILH, {
{ "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 },