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