Skip to content

Commit 1d14886

Browse files
committed
pack: on JSON formatting, remove duplicated keys (#1835 #1051)
Our internal serialization format allows to have several keys with the same name in a map. When converting to JSON the case is quite dangerous, despite the JSON spec is not mandatory about having unique keys at the same level in a map, we got tons of reports that backend services that receives JSON payload raises exception due to duplicated keys. On this patch now the JSON formatter will check for duplicated keys, if found, it preserves the latest one found. Signed-off-by: Eduardo Silva <eduardo@treasure-data.com>
1 parent 00e0742 commit 1d14886

File tree

1 file changed

+60
-9
lines changed

1 file changed

+60
-9
lines changed

src/flb_pack.c

Lines changed: 60 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -441,12 +441,46 @@ static inline int try_to_write(char *buf, int *off, size_t left,
441441
return FLB_TRUE;
442442
}
443443

444+
445+
/*
446+
* Check if a key exists in the map using the 'offset' as an index to define
447+
* which element needs to start looking from
448+
*/
449+
static inline int key_exists_in_map(msgpack_object key, msgpack_object map, int offset)
450+
{
451+
int i;
452+
msgpack_object p;
453+
454+
if (key.type != MSGPACK_OBJECT_STR) {
455+
return FLB_FALSE;
456+
}
457+
458+
for (i = offset; i < map.via.map.size; i++) {
459+
p = map.via.map.ptr[i].key;
460+
if (p.type != MSGPACK_OBJECT_STR) {
461+
continue;
462+
}
463+
464+
if (key.via.str.size != p.via.str.size) {
465+
continue;
466+
}
467+
468+
if (memcmp(key.via.str.ptr, p.via.str.ptr, p.via.str.size) == 0) {
469+
return FLB_TRUE;
470+
}
471+
}
472+
473+
return FLB_FALSE;
474+
}
475+
444476
static int msgpack2json(char *buf, int *off, size_t left,
445477
const msgpack_object *o)
446478
{
447-
int ret = FLB_FALSE;
448479
int i;
480+
int dup;
481+
int ret = FLB_FALSE;
449482
int loop;
483+
int packed;
450484

451485
switch(o->type) {
452486
case MSGPACK_OBJECT_NIL:
@@ -558,21 +592,33 @@ static int msgpack2json(char *buf, int *off, size_t left,
558592
goto msg2json_end;
559593
}
560594
if (loop != 0) {
595+
msgpack_object k;
561596
msgpack_object_kv *p = o->via.map.ptr;
562-
if (!msgpack2json(buf, off, left, &p->key) ||
563-
!try_to_write(buf, off, left, ":", 1) ||
564-
!msgpack2json(buf, off, left, &p->val)) {
565-
goto msg2json_end;
566-
}
567-
for (i = 1; i < loop; i++) {
597+
598+
packed = 0;
599+
dup = FLB_FALSE;
600+
601+
k = o->via.map.ptr[0].key;
602+
for (i = 0; i < loop; i++) {
603+
k = o->via.map.ptr[i].key;
604+
dup = key_exists_in_map(k, *o, i + 1);
605+
if (dup == FLB_TRUE) {
606+
continue;
607+
}
608+
609+
if (packed > 0) {
610+
if (!try_to_write(buf, off, left, ",", 1)) {
611+
goto msg2json_end;
612+
}
613+
}
614+
568615
if (
569-
!try_to_write(buf, off, left, ",", 1) ||
570616
!msgpack2json(buf, off, left, &(p+i)->key) ||
571617
!try_to_write(buf, off, left, ":", 1) ||
572618
!msgpack2json(buf, off, left, &(p+i)->val) ) {
573619
goto msg2json_end;
574-
575620
}
621+
packed++;
576622
}
577623
}
578624

@@ -907,6 +953,11 @@ flb_sds_t flb_pack_msgpack_to_json_format(const char *data, uint64_t bytes,
907953
msgpack_sbuffer_destroy(&tmp_sbuf);
908954
}
909955

956+
if (out_buf && flb_sds_len(out_buf) == 0) {
957+
flb_sds_destroy(out_buf);
958+
return NULL;
959+
}
960+
910961
return out_buf;
911962
}
912963

0 commit comments

Comments
 (0)