]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: Add binary encoding request header sample fetch
authorThierry FOURNIER <thierry.fournier@ozon.io>
Sun, 9 Apr 2017 03:38:19 +0000 (05:38 +0200)
committerWilly Tarreau <w@1wt.eu>
Thu, 27 Apr 2017 09:54:54 +0000 (11:54 +0200)
This sample fetch encodes the http request headers in binary
format. This sample-fetch is useful with SPOE.

doc/configuration.txt
src/proto_http.c

index f1afbc9a2b739b7f94da5bec767396749b90e574..1cb9b631e5adad5fc97be41e38c9d2a38ec962d6 100644 (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
index 6c940f1e3b943fc9c8ee10daecc8b7b129932069..2dd2ad4fb9fa1f5659a43f75768045af52629c87 100644 (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 },