]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: sample: Extract some protocol buffers specific code.
authorFrédéric Lécaille <flecaille@haproxy.com>
Wed, 6 Mar 2019 07:03:44 +0000 (08:03 +0100)
committerWilly Tarreau <w@1wt.eu>
Wed, 6 Mar 2019 14:36:02 +0000 (15:36 +0100)
We move the code responsible of parsing protocol buffers messages
inside gRPC messages from sample.c to include/proto/protocol_buffers.h
so that to reuse it to cascade "ungrpc" converter.

include/proto/protocol_buffers.h
src/sample.c

index 97f9bf55a976bf96522a31e04fd0d37d38ca1029..a9deab129017582d65f45e929af66cbcf304f7ab 100644 (file)
@@ -23,6 +23,7 @@
 #define _PROTO_PROTOCOL_BUFFERS_H
 
 #include <stdint.h>
+#include <types/arg.h>
 #include <types/protocol_buffers.h>
 #include <proto/sample.h>
 
@@ -477,6 +478,95 @@ int protobuf_smp_store_32bit(struct sample *smp, int type,
        return 1;
 }
 
+/*
+ * Lookup for a protocol buffers field whose parameters are provided by <arg_p>
+ * first argument in the buffer with <pos> as address and <len> as length address.
+ * If found, store its value depending on the type of storage to use provided by <arg_p>
+ * second argument and return 1, 0 if not.
+ */
+static inline int protobuf_field_lookup(const struct arg *arg_p, struct sample *smp,
+                                        unsigned char **pos, size_t *len)
+{
+       unsigned int *fid;
+       size_t fid_sz;
+       int type;
+       uint64_t elen;
+       int field;
+
+       fid = arg_p[0].data.fid.ids;
+       fid_sz = arg_p[0].data.fid.sz;
+       type = arg_p[1].data.sint;
+
+       /* Length of the length-delimited messages if any. */
+       elen = 0;
+       field = 0;
+
+       while (field < fid_sz) {
+               int found;
+               uint64_t key, sleft;
+               struct protobuf_parser_def *pbuf_parser = NULL;
+               unsigned int wire_type, field_number;
+
+               if ((ssize_t)*len <= 0)
+                       return 0;
+
+               /* Remaining bytes saving. */
+               sleft = *len;
+
+               /* Key decoding */
+               if (!protobuf_decode_varint(&key, pos, len))
+                       return 0;
+
+               wire_type = key & 0x7;
+               field_number = key >> 3;
+               found = field_number == fid[field];
+
+               /* Skip the data if the current field does not match. */
+               switch (wire_type) {
+               case PBUF_TYPE_VARINT:
+               case PBUF_TYPE_32BIT:
+               case PBUF_TYPE_64BIT:
+                       pbuf_parser = &protobuf_parser_defs[wire_type];
+                       if (!found && !pbuf_parser->skip(pos, len, 0))
+                               return 0;
+                       break;
+
+               case PBUF_TYPE_LENGTH_DELIMITED:
+                       /* Decode the length of this length-delimited field. */
+                       if (!protobuf_decode_varint(&elen, pos, len) || elen > *len)
+                               return 0;
+
+                       /* The size of the current field is computed from here to skip
+                        * the bytes used to encode the previous length.*
+                        */
+                       sleft = *len;
+                       pbuf_parser = &protobuf_parser_defs[wire_type];
+                       if (!found && !pbuf_parser->skip(pos, len, elen))
+                               return 0;
+                       break;
+
+               default:
+                       return 0;
+               }
+
+               /* Store the data if found. Note that <pbuf_parser> is not NULL */
+               if (found && field == fid_sz - 1)
+                       return pbuf_parser->smp_store(smp, type, *pos, *len, elen);
+
+               if ((ssize_t)(elen) > 0)
+                       elen -= sleft - *len;
+
+               if (found) {
+                       field++;
+               }
+               else if ((ssize_t)elen <= 0) {
+                       field = 0;
+               }
+       }
+
+       return 0;
+}
+
 #endif /* _PROTO_PROTOCOL_BUFFERS_H */
 
 /*
index 5b0ccc9537d975c879f2f88ae33fad859f1e0d3c..e95c57c10f08597a0fcdaa388ae33888bee80313 100644 (file)
@@ -2763,26 +2763,12 @@ static int sample_conv_ungrpc(const struct arg *arg_p, struct sample *smp, void
 {
        unsigned char *pos;
        size_t grpc_left;
-       unsigned int *fid;
-       size_t fid_sz;
-       int type;
-
-       if (!smp->strm)
-               return 0;
-
-       fid = arg_p[0].data.fid.ids;
-       fid_sz = arg_p[0].data.fid.sz;
-       type = arg_p[1].data.sint;
 
        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_HEADER_SZ) {
-               int 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));
 
@@ -2792,92 +2778,9 @@ static int sample_conv_ungrpc(const struct arg *arg_p, struct sample *smp, void
                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.
-                */
-               field = 0;
-               while (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[field];
-
-                       switch (wire_type) {
-                       case PBUF_TYPE_VARINT:
-                       case PBUF_TYPE_32BIT:
-                       case PBUF_TYPE_64BIT:
-                       {
-                               struct protobuf_parser_def *pbuf_parser;
-
-                               pbuf_parser = &protobuf_parser_defs[wire_type];
-                               if (!found) {
-                                       /* Skip the data. */
-                                       if (!pbuf_parser->skip(&pos, &left, 0))
-                                               return 0;
-                               }
-                               else if (field == fid_sz - 1) {
-                                       return pbuf_parser->smp_store(smp, type, pos, left, 0);
-                               }
-
-                               break;
-                       }
-
-                       case PBUF_TYPE_LENGTH_DELIMITED:
-                       {
-                               struct protobuf_parser_def *pbuf_parser;
-
-                               /* 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;
-                               pbuf_parser = &protobuf_parser_defs[wire_type];
-                               if (!found) {
-                                       /* Skip the data. */
-                                       if (!pbuf_parser->skip(&pos, &left, elen))
-                                               return 0;
-                               } else if (field == fid_sz - 1) {
-                                       return pbuf_parser->smp_store(smp, type, pos, left, elen);
-                               }
-
-                               break;
-                       }
-
-                       default:
-                               return 0;
-                       }
-
-                       if ((ssize_t)(elen) > 0)
-                               elen -= sleft - left;
+               if (protobuf_field_lookup(arg_p, smp, &pos, &left))
+                       return 1;
 
-                       if (found) {
-                               field++;
-                       }
-                       else if ((ssize_t)elen <= 0) {
-                               field = 0;
-                       }
-               }
                grpc_left -= grpc_msg_len;
        }