]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: sample: Replace "req.ungrpc" smp fetch by a "ungrpc" converter.
authorFrédéric Lécaille <flecaille@haproxy.com>
Wed, 27 Feb 2019 13:34:51 +0000 (14:34 +0100)
committerWilly Tarreau <w@1wt.eu>
Mon, 4 Mar 2019 07:28:42 +0000 (08:28 +0100)
This patch simply extracts the code of smp_fetch_req_ungrpc() for "req.ungrpc"
from http_fetch.c to move it to sample.c with very few modifications.
Furthermore smp_fetch_body_buf() used to fetch the body contents is no more needed.

Update the documentation for gRPC.

doc/configuration.txt
src/http_fetch.c
src/sample.c

index 75383f8b3637fbe17384ea0ebce017ce2111590d..3ce29ca5d14cc4cef36199b59bbfbcf3fefc1d54 100644 (file)
@@ -13792,15 +13792,9 @@ sub(<value>)
   contain characters 'a-z', 'A-Z', '0-9', '.' and '_'.
 
 svarint
-  Converts a binary input sample of a protocol buffers signed "varints" ("sint32"
+  Converts a binary input sample of a protocol buffers signed "varint" ("sint32"
   and "sint64") to an integer.
-  More information may be found here about the protocol buffers message types:
-  https://developers.google.com/protocol-buffers/docs/encoding
-
-varint
-  Converts a binary input sample of a protocol buffers "varints", excepted
-  the signed ones "sint32" and "sint64", to an integer.
-  More information may be found here about the protocol buffers message types:
+  More information may be found here about the protocol buffers message field types:
   https://developers.google.com/protocol-buffers/docs/encoding
 
 table_bytes_in_rate(<table>)
@@ -13973,6 +13967,39 @@ url_dec
   Takes an url-encoded string provided as input and returns the decoded
   version as output. The input and the output are of type string.
 
+ungrpc(<field_number>) : binary
+  This extracts the protocol buffers message field in raw mode of an input binary
+  sample with <field_number> as field number (dotted notation).
+
+  Example:
+    // with such a protocol buffer .proto file content adapted from
+    // https://github.com/grpc/grpc/blob/master/examples/protos/route_guide.proto
+
+    message Point {
+      int32 latitude = 1;
+      int32 longitude = 2;
+    }
+
+    message PPoint {
+      Point point = 59;
+    }
+
+    message Rectangle {
+      // One corner of the rectangle.
+      PPoint lo = 48;
+      // The other corner of the rectangle.
+      PPoint hi = 49;
+    }
+
+    let's say a body request is made of a "Rectangle" object value (two PPoint
+    protocol buffers messages), the four protocol buffers fields could be
+    extracted with these "ungrpc" directives:
+
+    req.body,ungrpc(48.59.1) # "latitude" of "lo" first PPoint
+    req.body,ungrpc(48.59.2) # "longitude" of "lo" first PPoint
+    req.body,ungrpc(49.59.1) # "latidude" of "hi" second PPoint
+    req.body,ungrpc(49.59.2) # "longitude" of "hi" second PPoint
+
 unset-var(<var name>)
   Unsets a variable if the input content is defined. The name of the variable
   starts with an indication about its scope. The scopes allowed are:
@@ -13999,6 +14026,12 @@ utime(<format>[,<offset>])
       # e.g.  20140710162350 127.0.0.1:57325
       log-format %[date,utime(%Y%m%d%H%M%S)]\ %ci:%cp
 
+varint
+  Converts a binary input sample of a protocol buffers "varint", excepted
+  the signed ones "sint32" and "sint64", to an integer.
+  More information may be found here about the protocol buffers message field types:
+  https://developers.google.com/protocol-buffers/docs/encoding
+
 word(<index>,<delimiters>[,<count>])
   Extracts the nth word counting from the beginning (positive index) or from
   the end (negative index) considering given delimiters from an input string.
@@ -15976,38 +16009,6 @@ hdr_val([<name>[,<occ>]]) : integer (deprecated)
   the first one. Negative values indicate positions relative to the last one,
   with -1 being the last one. A typical use is with the X-Forwarded-For header.
 
-req.ungrpc(<field_number>) : binary
-  This extracts the protocol buffers message in raw mode of a gRPC request body
-  with <field_number> as terminal field number (dotted notation).
-
-  Example:
-    // with such a protocol buffer .proto file content adapted from
-    // https://github.com/grpc/grpc/blob/master/examples/protos/route_guide.proto
-
-    message Point {
-      int32 latitude = 1;
-      int32 longitude = 2;
-    }
-
-    message PPoint {
-      Point point = 59;
-    }
-
-    message Rectangle {
-      // One corner of the rectangle.
-      PPoint lo = 48;
-      // The other corner of the rectangle.
-      PPoint hi = 49;
-    }
-
-  Let's say a body requests is made of a "Rectangle" object value (two PPoint
-  protocol buffers messages), the four protocol buffers messages could be fetched
-  with this "req.ungrpc" sample fetch directives:
-
-    req.ungrpc(48.59.1) # "latitude" of "lo" first PPoint
-    req.ungrpc(48.59.2) # "longitude" of "lo" first PPoint
-    req.ungrpc(49.59.1) # "latidude" of "hi" second PPoint
-    req.ungrpc(49.59.2) # "longitude" of "hi" second PPoint
 
 
 http_auth(<userlist>) : boolean
index 8f88646ea886aee17b6b1d4f102139fe16fc4438..51f2ef13f22333d35045c49e5d39912311ce1bfa 100644 (file)
@@ -39,7 +39,6 @@
 #include <proto/log.h>
 #include <proto/obj_type.h>
 #include <proto/proto_http.h>
-#include <proto/protocol_buffers.h>
 #include <proto/sample.h>
 #include <proto/stream.h>
 
@@ -1517,245 +1516,6 @@ static int smp_fetch_hdr_val(const struct arg *args, struct sample *smp, const c
        return ret;
 }
 
-static inline struct buffer *
-smp_fetch_body_buf(const struct arg *args, struct sample *smp)
-{
-       struct buffer *buf;
-
-       if (IS_HTX_SMP(smp) || (smp->px->mode == PR_MODE_TCP)) {
-               /* HTX version */
-               struct htx *htx = smp_prefetch_htx(smp, args);
-               int32_t pos;
-
-               if (!htx)
-                       return NULL;
-
-               buf = get_trash_chunk();
-               for (pos = htx_get_head(htx); pos != -1; pos = htx_get_next(htx, pos)) {
-                       struct htx_blk *blk = htx_get_blk(htx, pos);
-                       enum htx_blk_type type = htx_get_blk_type(blk);
-
-                       if (type == HTX_BLK_EOM || type == HTX_BLK_EOD)
-                               break;
-                       if (type == HTX_BLK_DATA) {
-                               if (!htx_data_to_h1(htx_get_blk_value(htx, blk), buf, 0))
-                                       return NULL;
-                       }
-               }
-       }
-       else {
-               /* LEGACY version */
-               struct http_msg *msg;
-               unsigned long len;
-               unsigned long block1;
-               char *body;
-
-               if (smp_prefetch_http(smp->px, smp->strm, smp->opt, args, smp, 1) <= 0)
-                       return NULL;
-
-               if ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_REQ)
-                       msg = &smp->strm->txn->req;
-               else
-                       msg = &smp->strm->txn->rsp;
-
-               len  = http_body_bytes(msg);
-               body = c_ptr(msg->chn, -http_data_rewind(msg));
-
-               block1 = len;
-               if (block1 > b_wrap(&msg->chn->buf) - body)
-                       block1 = b_wrap(&msg->chn->buf) - body;
-
-               buf = get_trash_chunk();
-               if (block1 == len) {
-                       /* buffer is not wrapped (or empty) */
-                       memcpy(buf->area, body, len);
-               }
-               else {
-                       /* buffer is wrapped, we need to defragment it */
-                       memcpy(buf->area, body, block1);
-                       memcpy(buf->area + block1, b_orig(&msg->chn->buf),
-                              len - block1);
-               }
-               buf->data = len;
-       }
-
-       return buf;
-}
-
-#define GRPC_MSG_COMPRESS_FLAG_SZ 1 /* 1 byte */
-#define GRPC_MSG_LENGTH_SZ        4 /* 4 bytes */
-#define GRPC_MSG_HEADER_SZ        (GRPC_MSG_COMPRESS_FLAG_SZ + GRPC_MSG_LENGTH_SZ)
-
-/*
- * Fetch a gRPC field value. Takes a mandatory argument: the field identifier
- * (dotted notation) internally represented as an array of unsigned integers
- * and its size.
- * Return 1 if the field was found, 0 if not.
- */
-static int smp_fetch_req_ungrpc(const struct arg *args, struct sample *smp, const char *kw, void *private)
-{
-       struct buffer *body;
-       unsigned char *pos;
-       size_t grpc_left;
-       unsigned int *fid;
-       size_t fid_sz;
-
-       if (!smp->strm)
-               return 0;
-
-       fid = args[0].data.fid.ids;
-       fid_sz = args[0].data.fid.sz;
-
-       body = smp_fetch_body_buf(args, smp);
-       if (!body)
-               return 0;
-
-       pos = (unsigned char *)body->area;
-       /* Remaining bytes in the body to be parsed. */
-       grpc_left = body->data;
-
-       while (grpc_left > GRPC_MSG_COMPRESS_FLAG_SZ + GRPC_MSG_LENGTH_SZ) {
-               int next_field, found;
-               size_t grpc_msg_len, left;
-               unsigned int wire_type, field_number;
-               uint64_t key, elen;
-
-               grpc_msg_len = left = ntohl(*(uint32_t *)(pos + GRPC_MSG_COMPRESS_FLAG_SZ));
-
-               pos += GRPC_MSG_HEADER_SZ;
-               grpc_left -= GRPC_MSG_HEADER_SZ;
-
-               if (grpc_left < left)
-                       return 0;
-
-               found = 1;
-               /* Length of the length-delimited messages if any. */
-               elen = 0;
-
-               /* Message decoding: there may be serveral key+value protobuf pairs by
-                * gRPC message.
-                */
-               next_field = 0;
-               while (next_field < fid_sz) {
-                       uint64_t sleft;
-
-                       if ((ssize_t)left <= 0)
-                               return 0;
-
-                       /* Remaining bytes saving. */
-                       sleft = left;
-
-                       /* Key decoding */
-                       if (!protobuf_decode_varint(&key, &pos, &left))
-                               return 0;
-
-                       wire_type = key & 0x7;
-                       field_number = key >> 3;
-                       found = field_number == fid[next_field];
-
-                       if (found && field_number != fid[next_field])
-                               found = 0;
-
-                       switch (wire_type) {
-                       case PBUF_TYPE_VARINT:
-                       {
-                               if (!found) {
-                                       protobuf_skip_varint(&pos, &left);
-                               } else if (next_field == fid_sz - 1) {
-                                       int varint_len;
-                                       unsigned char *spos = pos;
-
-                                       varint_len = protobuf_varint_getlen(&pos, &left);
-                                       if (varint_len == -1)
-                                               return 0;
-
-                                       smp->data.type = SMP_T_BIN;
-                                       smp->data.u.str.area = (char *)spos;
-                                       smp->data.u.str.data = varint_len;
-                                       smp->flags = SMP_F_VOL_TEST;
-                                       return 1;
-                               }
-                               break;
-                       }
-
-                       case PBUF_TYPE_64BIT:
-                       {
-                               if (!found) {
-                                       pos += sizeof(uint64_t);
-                                       left -= sizeof(uint64_t);
-                               } else if (next_field == fid_sz - 1) {
-                                       smp->data.type = SMP_T_BIN;
-                                       smp->data.u.str.area = (char *)pos;
-                                       smp->data.u.str.data = sizeof(uint64_t);
-                                       smp->flags = SMP_F_VOL_TEST;
-                                       return 1;
-                               }
-                               break;
-                       }
-
-                       case PBUF_TYPE_LENGTH_DELIMITED:
-                       {
-                               /* Decode the length of this length-delimited field. */
-                               if (!protobuf_decode_varint(&elen, &pos, &left))
-                                       return 0;
-
-                               if (elen > left)
-                                       return 0;
-
-                               /* The size of the current field is computed from here do skip
-                                * the bytes to encode the previous lenght.*
-                                */
-                               sleft = left;
-                               if (!found) {
-                                       /* Skip the current length-delimited field. */
-                                       pos += elen;
-                                       left -= elen;
-                                       break;
-                               } else if (next_field == fid_sz - 1) {
-                                       smp->data.type = SMP_T_BIN;
-                                       smp->data.u.str.area = (char *)pos;
-                                       smp->data.u.str.data = elen;
-                                       smp->flags = SMP_F_VOL_TEST;
-                                       return 1;
-                               }
-                               break;
-                       }
-
-                       case PBUF_TYPE_32BIT:
-                       {
-                               if (!found) {
-                                       pos += sizeof(uint32_t);
-                                       left -= sizeof(uint32_t);
-                               } else if (next_field == fid_sz - 1) {
-                                       smp->data.type = SMP_T_BIN;
-                                       smp->data.u.str.area = (char *)pos;
-                                       smp->data.u.str.data = sizeof(uint32_t);
-                                       smp->flags = SMP_F_VOL_TEST;
-                                       return 1;
-                               }
-                               break;
-                       }
-
-                       default:
-                               return 0;
-                       }
-
-                       if ((ssize_t)(elen) > 0)
-                               elen -= sleft - left;
-
-                       if (found) {
-                               next_field++;
-                       }
-                       else if ((ssize_t)elen <= 0) {
-                               next_field = 0;
-                       }
-               }
-               grpc_left -= grpc_msg_len;
-       }
-
-       return 0;
-}
-
 /* Fetch an HTTP header's IP value. takes a mandatory argument of type string
  * and an optional one of type int to designate a specific occurrence.
  * It returns an IPv4 or IPv6 address.
@@ -3122,7 +2882,6 @@ static struct sample_fetch_kw_list sample_fetch_keywords = {ILH, {
        { "req.hdr_ip",         smp_fetch_hdr_ip,             ARG2(0,STR,SINT), val_hdr, SMP_T_IPV4, SMP_USE_HRQHV },
        { "req.hdr_names",      smp_fetch_hdr_names,          ARG1(0,STR),      NULL,    SMP_T_STR,  SMP_USE_HRQHV },
        { "req.hdr_val",        smp_fetch_hdr_val,            ARG2(0,STR,SINT), val_hdr, SMP_T_SINT, SMP_USE_HRQHV },
-       { "req.ungrpc",         smp_fetch_req_ungrpc,         ARG1(1, PBUF_FNUM), NULL,  SMP_T_BIN,  SMP_USE_HRQHV },
 
        /* explicit req.{cook,hdr} are used to force the fetch direction to be response-only */
        { "res.cook",           smp_fetch_cookie,             ARG1(0,STR),      NULL,    SMP_T_STR,  SMP_USE_HRSHV },
index 1f323bdc7828850206089d3331965c7cd9fae3d5..9c20469c5aa53a624786f08c37932dbca85ccb87 100644 (file)
@@ -2776,6 +2776,175 @@ static int sample_conv_strcmp(const struct arg *arg_p, struct sample *smp, void
        return 1;
 }
 
+#define GRPC_MSG_COMPRESS_FLAG_SZ 1 /* 1 byte */
+#define GRPC_MSG_LENGTH_SZ        4 /* 4 bytes */
+#define GRPC_MSG_HEADER_SZ        (GRPC_MSG_COMPRESS_FLAG_SZ + GRPC_MSG_LENGTH_SZ)
+
+/*
+ * Extract the field value of an input binary sample. Takes a mandatory argument:
+ * the protocol buffers field identifier (dotted notation) internally represented
+ * as an array of unsigned integers and its size.
+ * Return 1 if the field was found, 0 if not.
+ */
+static int sample_conv_ungrpc(const struct arg *arg_p, struct sample *smp, void *private)
+{
+       unsigned char *pos;
+       size_t grpc_left;
+       unsigned int *fid;
+       size_t fid_sz;
+
+       if (!smp->strm)
+               return 0;
+
+       fid = arg_p[0].data.fid.ids;
+       fid_sz = arg_p[0].data.fid.sz;
+
+       pos = (unsigned char *)smp->data.u.str.area;
+       /* Remaining bytes in the body to be parsed. */
+       grpc_left = smp->data.u.str.data;
+
+       while (grpc_left > GRPC_MSG_COMPRESS_FLAG_SZ + GRPC_MSG_LENGTH_SZ) {
+               int next_field, found;
+               size_t grpc_msg_len, left;
+               unsigned int wire_type, field_number;
+               uint64_t key, elen;
+
+               grpc_msg_len = left = ntohl(*(uint32_t *)(pos + GRPC_MSG_COMPRESS_FLAG_SZ));
+
+               pos += GRPC_MSG_HEADER_SZ;
+               grpc_left -= GRPC_MSG_HEADER_SZ;
+
+               if (grpc_left < left)
+                       return 0;
+
+               found = 1;
+               /* Length of the length-delimited messages if any. */
+               elen = 0;
+
+               /* Message decoding: there may be serveral key+value protobuf pairs by
+                * gRPC message.
+                */
+               next_field = 0;
+               while (next_field < fid_sz) {
+                       uint64_t sleft;
+
+                       if ((ssize_t)left <= 0)
+                               return 0;
+
+                       /* Remaining bytes saving. */
+                       sleft = left;
+
+                       /* Key decoding */
+                       if (!protobuf_decode_varint(&key, &pos, &left))
+                               return 0;
+
+                       wire_type = key & 0x7;
+                       field_number = key >> 3;
+                       found = field_number == fid[next_field];
+
+                       if (found && field_number != fid[next_field])
+                               found = 0;
+
+                       switch (wire_type) {
+                       case PBUF_TYPE_VARINT:
+                       {
+                               if (!found) {
+                                       protobuf_skip_varint(&pos, &left);
+                               } else if (next_field == fid_sz - 1) {
+                                       int varint_len;
+                                       unsigned char *spos = pos;
+
+                                       varint_len = protobuf_varint_getlen(&pos, &left);
+                                       if (varint_len == -1)
+                                               return 0;
+
+                                       smp->data.type = SMP_T_BIN;
+                                       smp->data.u.str.area = (char *)spos;
+                                       smp->data.u.str.data = varint_len;
+                                       smp->flags = SMP_F_VOL_TEST;
+                                       return 1;
+                               }
+                               break;
+                       }
+
+                       case PBUF_TYPE_64BIT:
+                       {
+                               if (!found) {
+                                       pos += sizeof(uint64_t);
+                                       left -= sizeof(uint64_t);
+                               } else if (next_field == fid_sz - 1) {
+                                       smp->data.type = SMP_T_BIN;
+                                       smp->data.u.str.area = (char *)pos;
+                                       smp->data.u.str.data = sizeof(uint64_t);
+                                       smp->flags = SMP_F_VOL_TEST;
+                                       return 1;
+                               }
+                               break;
+                       }
+
+                       case PBUF_TYPE_LENGTH_DELIMITED:
+                       {
+                               /* Decode the length of this length-delimited field. */
+                               if (!protobuf_decode_varint(&elen, &pos, &left))
+                                       return 0;
+
+                               if (elen > left)
+                                       return 0;
+
+                               /* The size of the current field is computed from here do skip
+                                * the bytes to encode the previous lenght.*
+                                */
+                               sleft = left;
+                               if (!found) {
+                                       /* Skip the current length-delimited field. */
+                                       pos += elen;
+                                       left -= elen;
+                                       break;
+                               } else if (next_field == fid_sz - 1) {
+                                       smp->data.type = SMP_T_BIN;
+                                       smp->data.u.str.area = (char *)pos;
+                                       smp->data.u.str.data = elen;
+                                       smp->flags = SMP_F_VOL_TEST;
+                                       return 1;
+                               }
+                               break;
+                       }
+
+                       case PBUF_TYPE_32BIT:
+                       {
+                               if (!found) {
+                                       pos += sizeof(uint32_t);
+                                       left -= sizeof(uint32_t);
+                               } else if (next_field == fid_sz - 1) {
+                                       smp->data.type = SMP_T_BIN;
+                                       smp->data.u.str.area = (char *)pos;
+                                       smp->data.u.str.data = sizeof(uint32_t);
+                                       smp->flags = SMP_F_VOL_TEST;
+                                       return 1;
+                               }
+                               break;
+                       }
+
+                       default:
+                               return 0;
+                       }
+
+                       if ((ssize_t)(elen) > 0)
+                               elen -= sleft - left;
+
+                       if (found) {
+                               next_field++;
+                       }
+                       else if ((ssize_t)elen <= 0) {
+                               next_field = 0;
+                       }
+               }
+               grpc_left -= grpc_msg_len;
+       }
+
+       return 0;
+}
+
 /* This function checks the "strcmp" converter's arguments and extracts the
  * variable name and its scope.
  */
@@ -3161,6 +3330,9 @@ static struct sample_conv_kw_list sample_conv_kws = {ILH, {
        { "sha1",   sample_conv_sha1,      0,            NULL, SMP_T_BIN,  SMP_T_BIN  },
        { "concat", sample_conv_concat,    ARG3(1,STR,STR,STR), smp_check_concat, SMP_T_STR,  SMP_T_STR },
        { "strcmp", sample_conv_strcmp,    ARG1(1,STR), smp_check_strcmp, SMP_T_STR,  SMP_T_SINT },
+
+       /* gRPC converters. */
+       { "ungrpc", sample_conv_ungrpc,    ARG1(1,PBUF_FNUM), NULL, SMP_T_BIN, SMP_T_BIN  },
        { "varint", sample_conv_varint,    0,            NULL, SMP_T_BIN,  SMP_T_SINT  },
        { "svarint", sample_conv_svarint,  0,            NULL, SMP_T_BIN,  SMP_T_SINT  },