MINOR: sample: Extract some protocol buffers specific code.

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.
This commit is contained in:
Frdric Lcaille 2019-03-06 08:03:44 +01:00 committed by Willy Tarreau
parent 1aabc93978
commit 5f33f85ce8
2 changed files with 92 additions and 99 deletions

View 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 */
/*

View 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;
if (protobuf_field_lookup(arg_p, smp, &pos, &left))
return 1;
/* 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 (found) {
field++;
}
else if ((ssize_t)elen <= 0) {
field = 0;
}
}
grpc_left -= grpc_msg_len;
}