xref: /openbmc/qemu/qobject/json-streamer.c (revision 1fd6bb44)
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 "qapi/qmp/qlist.h"
15 #include "qapi/qmp/qint.h"
16 #include "qapi/qmp/qdict.h"
17 #include "qemu-common.h"
18 #include "qapi/qmp/json-lexer.h"
19 #include "qapi/qmp/json-streamer.h"
20 
21 #define MAX_TOKEN_SIZE (64ULL << 20)
22 #define MAX_NESTING (1ULL << 10)
23 
24 static void json_message_process_token(JSONLexer *lexer, QString *token, JSONTokenType type, int x, int y)
25 {
26     JSONMessageParser *parser = container_of(lexer, JSONMessageParser, lexer);
27     QDict *dict;
28 
29     if (type == JSON_OPERATOR) {
30         switch (qstring_get_str(token)[0]) {
31         case '{':
32             parser->brace_count++;
33             break;
34         case '}':
35             parser->brace_count--;
36             break;
37         case '[':
38             parser->bracket_count++;
39             break;
40         case ']':
41             parser->bracket_count--;
42             break;
43         default:
44             break;
45         }
46     }
47 
48     dict = qdict_new();
49     qdict_put(dict, "type", qint_from_int(type));
50     QINCREF(token);
51     qdict_put(dict, "token", token);
52     qdict_put(dict, "x", qint_from_int(x));
53     qdict_put(dict, "y", qint_from_int(y));
54 
55     parser->token_size += token->length;
56 
57     qlist_append(parser->tokens, dict);
58 
59     if (type == JSON_ERROR) {
60         goto out_emit_bad;
61     } else if (parser->brace_count < 0 ||
62         parser->bracket_count < 0 ||
63         (parser->brace_count == 0 &&
64          parser->bracket_count == 0)) {
65         goto out_emit;
66     } else if (parser->token_size > MAX_TOKEN_SIZE ||
67                parser->bracket_count > MAX_NESTING ||
68                parser->brace_count > MAX_NESTING) {
69         /* Security consideration, we limit total memory allocated per object
70          * and the maximum recursion depth that a message can force.
71          */
72         goto out_emit;
73     }
74 
75     return;
76 
77 out_emit_bad:
78     /* clear out token list and tell the parser to emit and error
79      * indication by passing it a NULL list
80      */
81     QDECREF(parser->tokens);
82     parser->tokens = NULL;
83 out_emit:
84     /* send current list of tokens to parser and reset tokenizer */
85     parser->brace_count = 0;
86     parser->bracket_count = 0;
87     parser->emit(parser, parser->tokens);
88     if (parser->tokens) {
89         QDECREF(parser->tokens);
90     }
91     parser->tokens = qlist_new();
92     parser->token_size = 0;
93 }
94 
95 void json_message_parser_init(JSONMessageParser *parser,
96                               void (*func)(JSONMessageParser *, QList *))
97 {
98     parser->emit = func;
99     parser->brace_count = 0;
100     parser->bracket_count = 0;
101     parser->tokens = qlist_new();
102     parser->token_size = 0;
103 
104     json_lexer_init(&parser->lexer, json_message_process_token);
105 }
106 
107 int json_message_parser_feed(JSONMessageParser *parser,
108                              const char *buffer, size_t size)
109 {
110     return json_lexer_feed(&parser->lexer, buffer, size);
111 }
112 
113 int json_message_parser_flush(JSONMessageParser *parser)
114 {
115     return json_lexer_flush(&parser->lexer);
116 }
117 
118 void json_message_parser_destroy(JSONMessageParser *parser)
119 {
120     json_lexer_destroy(&parser->lexer);
121     QDECREF(parser->tokens);
122 }
123