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_free_tokens(JSONMessageParser *parser) 26 { 27 if (parser->tokens) { 28 g_queue_free(parser->tokens); 29 parser->tokens = NULL; 30 } 31 } 32 33 static void json_message_process_token(JSONLexer *lexer, GString *input, 34 JSONTokenType type, int x, int y) 35 { 36 JSONMessageParser *parser = container_of(lexer, JSONMessageParser, lexer); 37 QDict *dict; 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 default: 53 break; 54 } 55 56 dict = qdict_new(); 57 qdict_put(dict, "type", qint_from_int(type)); 58 qdict_put(dict, "token", qstring_from_str(input->str)); 59 qdict_put(dict, "x", qint_from_int(x)); 60 qdict_put(dict, "y", qint_from_int(y)); 61 62 parser->token_size += input->len; 63 64 g_queue_push_tail(parser->tokens, dict); 65 66 if (type == JSON_ERROR) { 67 goto out_emit_bad; 68 } else if (parser->brace_count < 0 || 69 parser->bracket_count < 0 || 70 (parser->brace_count == 0 && 71 parser->bracket_count == 0)) { 72 goto out_emit; 73 } else if (parser->token_size > MAX_TOKEN_SIZE || 74 parser->bracket_count + parser->brace_count > MAX_NESTING) { 75 /* Security consideration, we limit total memory allocated per object 76 * and the maximum recursion depth that a message can force. 77 */ 78 goto out_emit_bad; 79 } 80 81 return; 82 83 out_emit_bad: 84 /* 85 * Clear out token list and tell the parser to emit an error 86 * indication by passing it a NULL list 87 */ 88 json_message_free_tokens(parser); 89 out_emit: 90 /* send current list of tokens to parser and reset tokenizer */ 91 parser->brace_count = 0; 92 parser->bracket_count = 0; 93 /* parser->emit takes ownership of parser->tokens. */ 94 parser->emit(parser, parser->tokens); 95 parser->tokens = g_queue_new(); 96 parser->token_size = 0; 97 } 98 99 void json_message_parser_init(JSONMessageParser *parser, 100 void (*func)(JSONMessageParser *, GQueue *)) 101 { 102 parser->emit = func; 103 parser->brace_count = 0; 104 parser->bracket_count = 0; 105 parser->tokens = g_queue_new(); 106 parser->token_size = 0; 107 108 json_lexer_init(&parser->lexer, json_message_process_token); 109 } 110 111 int json_message_parser_feed(JSONMessageParser *parser, 112 const char *buffer, size_t size) 113 { 114 return json_lexer_feed(&parser->lexer, buffer, size); 115 } 116 117 int json_message_parser_flush(JSONMessageParser *parser) 118 { 119 return json_lexer_flush(&parser->lexer); 120 } 121 122 void json_message_parser_destroy(JSONMessageParser *parser) 123 { 124 json_lexer_destroy(&parser->lexer); 125 json_message_free_tokens(parser); 126 } 127