diff --git a/src/lib/json-parser.c b/src/lib/json-parser.c index cf0eeaa119..45f888dfef 100644 --- a/src/lib/json-parser.c +++ b/src/lib/json-parser.c @@ -335,21 +335,16 @@ static int json_parse_denest(struct json_parser *parser) json_parser_update_input_pos(parser); nested_states = array_get(&parser->nesting, &count); - if (count == 0) { + i_assert(count > 0); + if (count == 1) { /* closing root */ parser->state = JSON_STATE_DONE; return 0; } /* closing a nested object */ - if (count == 1) { - /* we're back to root */ - parser->state = JSON_STATE_OBJECT_NEXT; - } else { - /* back to previous nested object */ - parser->state = nested_states[count-2] == JSON_STATE_OBJECT_OPEN ? - JSON_STATE_OBJECT_NEXT : JSON_STATE_ARRAY_NEXT; - } + parser->state = nested_states[count-2] == JSON_STATE_OBJECT_OPEN ? + JSON_STATE_OBJECT_NEXT : JSON_STATE_ARRAY_NEXT; array_delete(&parser->nesting, count-1, 1); if (parser->nested_skip_count > 0) { @@ -377,6 +372,14 @@ json_parse_close_array(struct json_parser *parser, enum json_type *type_r) return 1; } +static void json_parser_object_open(struct json_parser *parser) +{ + parser->data++; + parser->state = JSON_STATE_OBJECT_OPEN; + array_append(&parser->nesting, &parser->state, 1); + json_parser_update_input_pos(parser); +} + static int json_try_parse_next(struct json_parser *parser, enum json_type *type_r, const char **value_r) @@ -393,17 +396,12 @@ json_try_parse_next(struct json_parser *parser, enum json_type *type_r, parser->error = "Object doesn't begin with '{'"; return -1; } - parser->data++; - parser->state = JSON_STATE_OBJECT_OPEN; - json_parser_update_input_pos(parser); + json_parser_object_open(parser); return 0; case JSON_STATE_OBJECT_VALUE: case JSON_STATE_ARRAY_VALUE: if (*parser->data == '{') { - parser->data++; - parser->state = JSON_STATE_OBJECT_OPEN; - array_append(&parser->nesting, &parser->state, 1); - json_parser_update_input_pos(parser); + json_parser_object_open(parser); if (parser->skipping) { parser->nested_skip_count++; diff --git a/src/lib/test-json-parser.c b/src/lib/test-json-parser.c index d2b78ec377..da24f0fcbb 100644 --- a/src/lib/test-json-parser.c +++ b/src/lib/test-json-parser.c @@ -163,6 +163,46 @@ static void test_json_parser_success(bool full_size) test_end(); } +static int test_json_parse_input(const char *test_input) +{ + struct json_parser *parser; + struct istream *input; + enum json_type type; + const char *value, *error; + int ret = 0; + + input = test_istream_create_data(test_input, strlen(test_input)); + parser = json_parser_init(input); + while (json_parse_next(parser, &type, &value) > 0) + ret++; + if (json_parser_deinit(&parser, &error) < 0) + ret = -1; + i_stream_unref(&input); + return ret; +} + +static void test_json_parser_errors(void) +{ + static const char *test_inputs[] = { + "{", + "{:}", + "{\"foo\":}", + "{\"foo\" []}", + "{\"foo\": [1}", + "{\"foo\": [1,]}", + "{\"foo\": [1,]}", + "{\"foo\": 1,}", + "{\"foo\": 1.}}", + "{\"foo\": 1},{}" + }; + unsigned int i; + + test_begin("json parser error handling"); + for (i = 0; i < N_ELEMENTS(test_inputs); i++) + test_assert_idx(test_json_parse_input(test_inputs[i]) < 0, i); + test_end(); +} + static void test_json_append_escaped(void) { string_t *str = t_str_new(32); @@ -189,6 +229,7 @@ void test_json_parser(void) { test_json_parser_success(TRUE); test_json_parser_success(FALSE); + test_json_parser_errors(); test_json_append_escaped(); test_json_append_escaped_data(); }