1 | /* |
2 | * JSON streaming support |
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 | static void json_message_free_tokens(JSONMessageParser *parser) |
23 | { |
24 | JSONToken *token; |
25 | |
26 | while ((token = g_queue_pop_head(&parser->tokens))) { |
27 | g_free(token); |
28 | } |
29 | } |
30 | |
31 | void json_message_process_token(JSONLexer *lexer, GString *input, |
32 | JSONTokenType type, int x, int y) |
33 | { |
34 | JSONMessageParser *parser = container_of(lexer, JSONMessageParser, lexer); |
35 | QObject *json = NULL; |
36 | Error *err = NULL; |
37 | JSONToken *token; |
38 | |
39 | switch (type) { |
40 | case JSON_LCURLY: |
41 | parser->brace_count++; |
42 | break; |
43 | case JSON_RCURLY: |
44 | parser->brace_count--; |
45 | break; |
46 | case JSON_LSQUARE: |
47 | parser->bracket_count++; |
48 | break; |
49 | case JSON_RSQUARE: |
50 | parser->bracket_count--; |
51 | break; |
52 | case JSON_ERROR: |
53 | error_setg(&err, "JSON parse error, stray '%s'" , input->str); |
54 | goto out_emit; |
55 | case JSON_END_OF_INPUT: |
56 | if (g_queue_is_empty(&parser->tokens)) { |
57 | return; |
58 | } |
59 | json = json_parser_parse(&parser->tokens, parser->ap, &err); |
60 | goto out_emit; |
61 | default: |
62 | break; |
63 | } |
64 | |
65 | /* |
66 | * Security consideration, we limit total memory allocated per object |
67 | * and the maximum recursion depth that a message can force. |
68 | */ |
69 | if (parser->token_size + input->len + 1 > MAX_TOKEN_SIZE) { |
70 | error_setg(&err, "JSON token size limit exceeded" ); |
71 | goto out_emit; |
72 | } |
73 | if (g_queue_get_length(&parser->tokens) + 1 > MAX_TOKEN_COUNT) { |
74 | error_setg(&err, "JSON token count limit exceeded" ); |
75 | goto out_emit; |
76 | } |
77 | if (parser->bracket_count + parser->brace_count > MAX_NESTING) { |
78 | error_setg(&err, "JSON nesting depth limit exceeded" ); |
79 | goto out_emit; |
80 | } |
81 | |
82 | token = json_token(type, x, y, input); |
83 | parser->token_size += input->len; |
84 | |
85 | g_queue_push_tail(&parser->tokens, token); |
86 | |
87 | if ((parser->brace_count > 0 || parser->bracket_count > 0) |
88 | && parser->bracket_count >= 0 && parser->bracket_count >= 0) { |
89 | return; |
90 | } |
91 | |
92 | json = json_parser_parse(&parser->tokens, parser->ap, &err); |
93 | |
94 | out_emit: |
95 | parser->brace_count = 0; |
96 | parser->bracket_count = 0; |
97 | json_message_free_tokens(parser); |
98 | parser->token_size = 0; |
99 | parser->emit(parser->opaque, json, err); |
100 | } |
101 | |
102 | void json_message_parser_init(JSONMessageParser *parser, |
103 | void (*emit)(void *opaque, QObject *json, |
104 | Error *err), |
105 | void *opaque, va_list *ap) |
106 | { |
107 | parser->emit = emit; |
108 | parser->opaque = opaque; |
109 | parser->ap = ap; |
110 | parser->brace_count = 0; |
111 | parser->bracket_count = 0; |
112 | g_queue_init(&parser->tokens); |
113 | parser->token_size = 0; |
114 | |
115 | json_lexer_init(&parser->lexer, !!ap); |
116 | } |
117 | |
118 | void json_message_parser_feed(JSONMessageParser *parser, |
119 | const char *buffer, size_t size) |
120 | { |
121 | json_lexer_feed(&parser->lexer, buffer, size); |
122 | } |
123 | |
124 | void json_message_parser_flush(JSONMessageParser *parser) |
125 | { |
126 | json_lexer_flush(&parser->lexer); |
127 | assert(g_queue_is_empty(&parser->tokens)); |
128 | } |
129 | |
130 | void json_message_parser_destroy(JSONMessageParser *parser) |
131 | { |
132 | json_lexer_destroy(&parser->lexer); |
133 | json_message_free_tokens(parser); |
134 | } |
135 | |