master
c 143 lines 4.18 KB
Raw
1 /*
2 * JSON parser - callback interface and error recovery
3 *
4 * Copyright IBM, Corp. 2009
5 *
6 * Authors:
7 * Anthony Liguori <aliguori@us.ibm.com>
8 *
9 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
10 * See the COPYING.LIB file in the top-level directory.
11 *
12 */
13
14 #include "qemu/osdep.h"
15 #include "qapi/error.h"
16 #include "json-parser-int.h"
17
18 #define MAX_TOKEN_SIZE (64ULL << 20)
19 #define MAX_TOKEN_COUNT (2ULL << 20)
20 #define MAX_NESTING (1 << 10)
21
22 void json_message_process_token(JSONLexer *lexer, GString *input,
23 JSONTokenType type, int x, int y)
24 {
25 JSONMessageParser *parser = container_of(lexer, JSONMessageParser, lexer);
26 Error *err = NULL;
27
28 parser->token_size += input->len;
29 parser->token_count++;
30
31 /* Detect message boundaries for error recovery purposes. */
32 switch (type) {
33 case JSON_LCURLY:
34 parser->brace_count++;
35 break;
36 case JSON_RCURLY:
37 if (!parser->brace_count) {
38 goto end_error_recovery;
39 }
40 parser->brace_count--;
41 break;
42 case JSON_LSQUARE:
43 parser->bracket_count++;
44 break;
45 case JSON_RSQUARE:
46 if (!parser->bracket_count) {
47 goto end_error_recovery;
48 }
49 parser->bracket_count--;
50 break;
51 case JSON_ERROR:
52 end_error_recovery:
53 /*
54 * We come here due to receiving either JSON_ERROR or a
55 * JSON_R{CURLY,SQUARE}) that is known to be unbalanced.
56 * If in error recovery, end it immediately. If not in
57 * error recovery, json_parser_feed() will raise an error
58 * but error recovery won't be entered at all.
59 */
60 parser->brace_count = 0;
61 parser->bracket_count = 0;
62 break;
63 default:
64 break;
65 }
66
67 if (parser->error) {
68 /* error recovery, eat tokens until parentheses balance */
69 } else {
70 /*
71 * Safety consideration, we limit total memory allocated per object
72 * and the maximum nesting depth that a message can force.
73 */
74 if (parser->token_size >= MAX_TOKEN_SIZE) {
75 error_setg(&err, "JSON token size limit exceeded");
76 } else if (parser->token_count > MAX_TOKEN_COUNT) {
77 error_setg(&err, "JSON token count limit exceeded");
78 } else if (parser->bracket_count + parser->brace_count > MAX_NESTING) {
79 error_setg(&err, "JSON nesting depth limit exceeded");
80 } else {
81 JSONToken token = (JSONToken) {
82 .type = type,
83 .x = x,
84 .y = y,
85 .str = input->str
86 };
87 QObject *json = json_parser_feed(&parser->parser, &token, &err);
88 if (json) {
89 parser->emit(parser->opaque, json, NULL);
90 }
91 }
92
93 if (err) {
94 parser->emit(parser->opaque, NULL, err);
95 /* start recovery */
96 parser->error = true;
97 }
98 }
99
100 if ((parser->brace_count == 0 && parser->bracket_count == 0)
101 || type == JSON_END_OF_INPUT) {
102 json_parser_reset(&parser->parser);
103 parser->error = false;
104 parser->brace_count = 0;
105 parser->bracket_count = 0;
106 parser->token_count = 0;
107 parser->token_size = 0;
108 }
109 }
110
111 void json_message_parser_init(JSONMessageParser *parser,
112 void (*emit)(void *opaque, QObject *json,
113 Error *err),
114 void *opaque, va_list *ap)
115 {
116 parser->emit = emit;
117 parser->opaque = opaque;
118 parser->error = false;
119 parser->brace_count = 0;
120 parser->bracket_count = 0;
121 parser->token_count = 0;
122 parser->token_size = 0;
123
124 json_parser_init(&parser->parser, ap);
125 json_lexer_init(&parser->lexer, !!ap);
126 }
127
128 void json_message_parser_feed(JSONMessageParser *parser,
129 const char *buffer, size_t size)
130 {
131 json_lexer_feed(&parser->lexer, buffer, size);
132 }
133
134 void json_message_parser_flush(JSONMessageParser *parser)
135 {
136 json_lexer_flush(&parser->lexer);
137 }
138
139 void json_message_parser_destroy(JSONMessageParser *parser)
140 {
141 json_lexer_destroy(&parser->lexer);
142 json_parser_destroy(&parser->parser);
143 }