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