static void test_json_parser_skip_array(void) { static const char *test_input = "[ 1, {\"foo\": 1 }, 2, \"bar\", 3, 1.234, 4, [], 5, [[]], 6, true ]"; struct json_parser *parser; struct istream *input; enum json_type type; const char *value, *error; int i; test_begin("json parser skip array"); input = test_istream_create_data(test_input, strlen(test_input)); parser = json_parser_init_flags(input, JSON_PARSER_NO_ROOT_OBJECT); test_assert(json_parse_next(parser, &type, &value) > 0 && type == JSON_TYPE_ARRAY); for (i = 1; i <= 6; i++) { test_assert(json_parse_next(parser, &type, &value) > 0 && type == JSON_TYPE_NUMBER && atoi(value) == i); json_parse_skip_next(parser); } test_assert(json_parse_next(parser, &type, &value) > 0 && type == JSON_TYPE_ARRAY_END); test_assert(json_parser_deinit(&parser, &error) == 0); i_stream_unref(&input); test_end(); }
static void test_json_parser_success(bool full_size) { struct json_parser *parser; struct istream *input, *jsoninput = NULL; enum json_type type; const char *value, *error; unsigned int i, pos, json_input_len = strlen(json_input); int ret = 0; test_begin(full_size ? "json parser" : "json parser (nonblocking)"); input = test_istream_create_data(json_input, json_input_len); test_istream_set_allow_eof(input, FALSE); parser = json_parser_init(input); i = full_size ? json_input_len : 0; for (pos = 0; i <= json_input_len; i++) { test_istream_set_size(input, i); for (;;) { value = NULL; if (pos < N_ELEMENTS(json_output) && json_output[pos].type == (enum json_type)TYPE_SKIP) { json_parse_skip_next(parser); pos++; continue; } else if (pos == N_ELEMENTS(json_output) || json_output[pos].type != (enum json_type)TYPE_STREAM) { ret = json_parse_next(parser, &type, &value); } else { ret = jsoninput != NULL ? 1 : json_parse_next_stream(parser, &jsoninput); if (jsoninput != NULL) ret = stream_read_value(&jsoninput, &value); type = TYPE_STREAM; } if (ret <= 0) break; i_assert(pos < N_ELEMENTS(json_output)); test_assert(json_output[pos].type == type); test_assert(null_strcmp(json_output[pos].value, value) == 0); pos++; } test_assert(ret == 0); } test_assert(pos == N_ELEMENTS(json_output)); test_istream_set_allow_eof(input, TRUE); test_assert(json_parse_next(parser, &type, &value) == -1); i_stream_unref(&input); test_assert(json_parser_deinit(&parser, &error) == 0); test_end(); }
void oauth2_parse_json(struct oauth2_request *req) { bool success; enum json_type type; const char *token, *error; int ret; req->field_name = NULL; while((ret = json_parse_next(req->parser, &type, &token)) > 0) { if (req->field_name == NULL) { if (type != JSON_TYPE_OBJECT_KEY) break; /* cannot use t_strdup because we might have to read more */ req->field_name = p_strdup(req->pool, token); } else if (type < JSON_TYPE_STRING) { /* this should be last allocation */ p_free(req->pool, req->field_name); json_parse_skip_next(req->parser); } else { if (!array_is_created(&req->fields)) p_array_init(&req->fields, req->pool, 4); struct oauth2_field *field = array_append_space(&req->fields); field->name = req->field_name; req->field_name = NULL; field->value = p_strdup(req->pool, token); } } /* read more */ if (ret == 0) return; io_remove(&req->io); if (ret > 0) { (void)json_parser_deinit(&req->parser, &error); error = "Invalid response data"; success = FALSE; } else if (i_stream_read_eof(req->is) && req->is->v_offset == 0 && req->is->stream_errno == 0) { /* discard error, empty response is OK. */ (void)json_parser_deinit(&req->parser, &error); error = NULL; success = TRUE; } else { ret = json_parser_deinit(&req->parser, &error); success = (ret == 0); } i_stream_unref(&req->is); req->json_parsed_cb(req, success, error); }
static int test_json_parse_input(const char *test_input, enum json_parser_flags flags) { 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_flags(input, flags); while (json_parse_next(parser, &type, &value) > 0) ret++; if (json_parser_deinit(&parser, &error) < 0) ret = -1; i_stream_unref(&input); return ret; }