diff --git a/doc/configuration.txt b/doc/configuration.txt index f1afbc9a2..1cb9b631e 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -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 diff --git a/src/proto_http.c b/src/proto_http.c index 6c940f1e3..2dd2ad4fb 100644 --- a/src/proto_http.c +++ b/src/proto_http.c @@ -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 },