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