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