summaryrefslogtreecommitdiff
path: root/upb/json/parser.rl
diff options
context:
space:
mode:
authorPaul Yang <TeBoring@users.noreply.github.com>2018-10-05 11:12:23 -0700
committerGitHub <noreply@github.com>2018-10-05 11:12:23 -0700
commit3c742bfdc8f63e1cfed63a93571bb4e72e5f49c4 (patch)
tree4f28741369e02a07b74aeaa9f4a51001f458f6d5 /upb/json/parser.rl
parentb258ae323503d93997b661df1309ff339bd8341d (diff)
Fix json ignore unknown (#128)
* Fix json ignore unknown Previously, there were several problems with ignoring unknown in json. 1) After finding a field is unknown, the parser's state is not changed. Thus, there is no way to distinguish whether the parser is dealing with an unknown field or it's just a top level message. 2) Several method didn't respect unknown field, e.g., start_object, end_bool, start_array. * Update json parser size * Update json parser size
Diffstat (limited to 'upb/json/parser.rl')
-rw-r--r--upb/json/parser.rl44
1 files changed, 39 insertions, 5 deletions
diff --git a/upb/json/parser.rl b/upb/json/parser.rl
index 8e6caa9..29efd09 100644
--- a/upb/json/parser.rl
+++ b/upb/json/parser.rl
@@ -111,6 +111,9 @@ typedef struct {
* because |f| is the field in the *current* message (i.e., the map-entry
* message itself), not the parent's field that leads to this map. */
const upb_fielddef *mapfield;
+
+ /* True if the field to be parsed is unknown. */
+ bool is_unknown_field;
} upb_jsonparser_frame;
struct upb_json_parser {
@@ -916,6 +919,10 @@ static bool end_bool(upb_json_parser *p, bool val) {
start_value_object(p, VALUE_BOOLVALUE);
}
+ if (p->top->is_unknown_field) {
+ return true;
+ }
+
if (!parser_putbool(p, val)) {
return false;
}
@@ -1022,6 +1029,7 @@ static bool start_stringval(upb_json_parser *p) {
inner->name_table = NULL;
inner->is_map = false;
inner->is_mapentry = false;
+ inner->is_unknown_field = false;
p->top = inner;
if (upb_fielddef_type(p->top->f) == UPB_TYPE_STRING) {
@@ -1513,6 +1521,7 @@ static bool handle_mapentry(upb_json_parser *p) {
inner->name_table = NULL;
inner->mapfield = mapfield;
inner->is_map = false;
+ inner->is_unknown_field = false;
/* Don't set this to true *yet* -- we reuse parsing handlers below to push
* the key field value to the sink, and these handlers will pop the frame
@@ -1543,6 +1552,8 @@ static bool end_membername(upb_json_parser *p) {
UPB_ASSERT(!p->top->f);
if (!p->top->m) {
+ p->top->is_unknown_field = true;
+ multipart_end(p);
return true;
}
@@ -1559,6 +1570,7 @@ static bool end_membername(upb_json_parser *p) {
return true;
} else if (p->ignore_json_unknown) {
+ p->top->is_unknown_field = true;
multipart_end(p);
return true;
} else {
@@ -1590,10 +1602,11 @@ static void end_member(upb_json_parser *p) {
}
p->top->f = NULL;
+ p->top->is_unknown_field = false;
}
static bool start_subobject(upb_json_parser *p) {
- if (p->top->f == NULL) {
+ if (p->top->is_unknown_field) {
upb_jsonparser_frame *inner;
if (!check_stack(p)) return false;
@@ -1602,6 +1615,7 @@ static bool start_subobject(upb_json_parser *p) {
inner->f = NULL;
inner->is_map = false;
inner->is_mapentry = false;
+ inner->is_unknown_field = false;
p->top = inner;
return true;
}
@@ -1623,6 +1637,7 @@ static bool start_subobject(upb_json_parser *p) {
inner->f = NULL;
inner->is_map = true;
inner->is_mapentry = false;
+ inner->is_unknown_field = false;
p->top = inner;
return true;
@@ -1643,6 +1658,7 @@ static bool start_subobject(upb_json_parser *p) {
inner->f = NULL;
inner->is_map = false;
inner->is_mapentry = false;
+ inner->is_unknown_field = false;
p->top = inner;
return true;
@@ -1742,7 +1758,18 @@ static bool start_array(upb_json_parser *p) {
start_listvalue_object(p);
}
- UPB_ASSERT(p->top->f);
+ if (p->top->is_unknown_field) {
+ inner = p->top + 1;
+ inner->m = NULL;
+ inner->name_table = NULL;
+ inner->f = NULL;
+ inner->is_map = false;
+ inner->is_mapentry = false;
+ inner->is_unknown_field = true;
+ p->top = inner;
+
+ return true;
+ }
if (!upb_fielddef_isseq(p->top->f)) {
upb_status_seterrf(&p->status,
@@ -1762,6 +1789,7 @@ static bool start_array(upb_json_parser *p) {
inner->f = p->top->f;
inner->is_map = false;
inner->is_mapentry = false;
+ inner->is_unknown_field = false;
p->top = inner;
return true;
@@ -1773,6 +1801,11 @@ static void end_array(upb_json_parser *p) {
UPB_ASSERT(p->top > p->stack);
p->top--;
+
+ if (p->top->is_unknown_field) {
+ return;
+ }
+
sel = getsel_for_handlertype(p, UPB_HANDLER_ENDSEQ);
upb_sink_endseq(&p->top->sink, sel);
@@ -1792,13 +1825,13 @@ static void end_array(upb_json_parser *p) {
}
static void start_object(upb_json_parser *p) {
- if (!p->top->is_map) {
+ if (!p->top->is_map && p->top->m != NULL) {
upb_sink_startmsg(&p->top->sink);
}
}
static void end_object(upb_json_parser *p) {
- if (!p->top->is_map) {
+ if (!p->top->is_map && p->top->m != NULL) {
upb_status status;
upb_status_clear(&status);
upb_sink_endmsg(&p->top->sink, &status);
@@ -1910,7 +1943,7 @@ static void end_structvalue_object(upb_json_parser *p) {
}
static bool is_top_level(upb_json_parser *p) {
- return p->top == p->stack && p->top->f == NULL;
+ return p->top == p->stack && p->top->f == NULL && !p->top->is_unknown_field;
}
static bool is_wellknown_msg(upb_json_parser *p, upb_wellknowntype_t type) {
@@ -2177,6 +2210,7 @@ static void json_parser_reset(upb_json_parser *p) {
p->top->f = NULL;
p->top->is_map = false;
p->top->is_mapentry = false;
+ p->top->is_unknown_field = false;
/* Emit Ragel initialization of the parser. */
%% write init;
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback