Addressing comments.
diff --git a/Makefile b/Makefile
index 03e0058..77935bc 100644
--- a/Makefile
+++ b/Makefile
@@ -1406,7 +1406,9 @@
src/core/iomgr/tcp_server_posix.c \
src/core/iomgr/time_averaged_stats.c \
src/core/json/json.c \
- src/core/json/json-string.c \
+ src/core/json/json_reader.c \
+ src/core/json/json_string.c \
+ src/core/json/json_writer.c \
src/core/statistics/census_init.c \
src/core/statistics/census_log.c \
src/core/statistics/census_rpc_stats.c \
@@ -1526,7 +1528,9 @@
src/core/iomgr/tcp_server_posix.c: $(OPENSSL_DEP)
src/core/iomgr/time_averaged_stats.c: $(OPENSSL_DEP)
src/core/json/json.c: $(OPENSSL_DEP)
-src/core/json/json-string.c: $(OPENSSL_DEP)
+src/core/json/json_reader.c: $(OPENSSL_DEP)
+src/core/json/json_string.c: $(OPENSSL_DEP)
+src/core/json/json_writer.c: $(OPENSSL_DEP)
src/core/statistics/census_init.c: $(OPENSSL_DEP)
src/core/statistics/census_log.c: $(OPENSSL_DEP)
src/core/statistics/census_rpc_stats.c: $(OPENSSL_DEP)
@@ -1667,7 +1671,9 @@
objs/$(CONFIG)/src/core/iomgr/tcp_server_posix.o:
objs/$(CONFIG)/src/core/iomgr/time_averaged_stats.o:
objs/$(CONFIG)/src/core/json/json.o:
-objs/$(CONFIG)/src/core/json/json-string.o:
+objs/$(CONFIG)/src/core/json/json_reader.o:
+objs/$(CONFIG)/src/core/json/json_string.o:
+objs/$(CONFIG)/src/core/json/json_writer.o:
objs/$(CONFIG)/src/core/statistics/census_init.o:
objs/$(CONFIG)/src/core/statistics/census_log.o:
objs/$(CONFIG)/src/core/statistics/census_rpc_stats.o:
@@ -1828,7 +1834,9 @@
src/core/iomgr/tcp_server_posix.c \
src/core/iomgr/time_averaged_stats.c \
src/core/json/json.c \
- src/core/json/json-string.c \
+ src/core/json/json_reader.c \
+ src/core/json/json_string.c \
+ src/core/json/json_writer.c \
src/core/statistics/census_init.c \
src/core/statistics/census_log.c \
src/core/statistics/census_rpc_stats.c \
@@ -1952,7 +1960,9 @@
objs/$(CONFIG)/src/core/iomgr/tcp_server_posix.o:
objs/$(CONFIG)/src/core/iomgr/time_averaged_stats.o:
objs/$(CONFIG)/src/core/json/json.o:
-objs/$(CONFIG)/src/core/json/json-string.o:
+objs/$(CONFIG)/src/core/json/json_reader.o:
+objs/$(CONFIG)/src/core/json/json_string.o:
+objs/$(CONFIG)/src/core/json/json_writer.o:
objs/$(CONFIG)/src/core/statistics/census_init.o:
objs/$(CONFIG)/src/core/statistics/census_log.o:
objs/$(CONFIG)/src/core/statistics/census_rpc_stats.o:
diff --git a/build.json b/build.json
index 18c6b2e..c2f44ef 100644
--- a/build.json
+++ b/build.json
@@ -61,6 +61,10 @@
"src/core/iomgr/tcp_posix.h",
"src/core/iomgr/tcp_server.h",
"src/core/iomgr/time_averaged_stats.h",
+ "src/core/json/json.h",
+ "src/core/json/json_common.h",
+ "src/core/json/json_reader.h",
+ "src/core/json/json_writer.h",
"src/core/statistics/census_interface.h",
"src/core/statistics/census_log.h",
"src/core/statistics/census_rpc_stats.h",
@@ -139,7 +143,9 @@
"src/core/iomgr/tcp_server_posix.c",
"src/core/iomgr/time_averaged_stats.c",
"src/core/json/json.c",
- "src/core/json/json-string.c",
+ "src/core/json/json_reader.c",
+ "src/core/json/json_string.c",
+ "src/core/json/json_writer.c",
"src/core/statistics/census_init.c",
"src/core/statistics/census_log.c",
"src/core/statistics/census_rpc_stats.c",
diff --git a/src/core/json/json-reader-defs.h b/src/core/json/json-reader-defs.h
deleted file mode 100644
index 10c8473..0000000
--- a/src/core/json/json-reader-defs.h
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- *
- * Copyright 2014, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-/* the following need to be pre-defined:
- * grpc_json_reader_opaque_t // A type you can use to keep track of your
- * // own stuff.
- * grpc_json_wchar_t // A type that can hold a unicode character
- * // unsigned is good enough.
- * grpc_json_string_t // A type that can hold a growable string.
- */
-
-enum grpc_json_reader_state_t {
- GRPC_JSON_STATE_OBJECT_KEY_BEGIN,
- GRPC_JSON_STATE_OBJECT_KEY_STRING,
- GRPC_JSON_STATE_OBJECT_KEY_END,
- GRPC_JSON_STATE_VALUE_BEGIN,
- GRPC_JSON_STATE_VALUE_STRING,
- GRPC_JSON_STATE_STRING_ESCAPE,
- GRPC_JSON_STATE_STRING_ESCAPE_U1,
- GRPC_JSON_STATE_STRING_ESCAPE_U2,
- GRPC_JSON_STATE_STRING_ESCAPE_U3,
- GRPC_JSON_STATE_STRING_ESCAPE_U4,
- GRPC_JSON_STATE_VALUE_NUMBER,
- GRPC_JSON_STATE_VALUE_NUMBER_WITH_DECIMAL,
- GRPC_JSON_STATE_VALUE_NUMBER_ZERO,
- GRPC_JSON_STATE_VALUE_NUMBER_DOT,
- GRPC_JSON_STATE_VALUE_NUMBER_E,
- GRPC_JSON_STATE_VALUE_NUMBER_EPM,
- GRPC_JSON_STATE_VALUE_TRUE_R,
- GRPC_JSON_STATE_VALUE_TRUE_U,
- GRPC_JSON_STATE_VALUE_TRUE_E,
- GRPC_JSON_STATE_VALUE_FALSE_A,
- GRPC_JSON_STATE_VALUE_FALSE_L,
- GRPC_JSON_STATE_VALUE_FALSE_S,
- GRPC_JSON_STATE_VALUE_FALSE_E,
- GRPC_JSON_STATE_VALUE_NULL_U,
- GRPC_JSON_STATE_VALUE_NULL_L1,
- GRPC_JSON_STATE_VALUE_NULL_L2,
- GRPC_JSON_STATE_VALUE_END,
- GRPC_JSON_STATE_END
-};
-
-struct grpc_json_reader_t {
- /* You are responsible for the initialization of the following. */
- grpc_json_reader_opaque_t opaque;
-
- /* Everything down here is private,
- and initialized by grpc_json_reader_init. */
- int depth;
- int in_object;
- int in_array;
- int escaped_string_was_key;
- int container_just_begun;
- grpc_json_wchar_t unicode;
- enum grpc_json_reader_state_t state;
-};
-
-/* The return type of the parser. */
-typedef enum {
- GRPC_JSON_DONE, /* The parser finished successfully. */
- GRPC_JSON_EAGAIN, /* The parser yields to get more data. */
- GRPC_JSON_READ_ERROR, /* The parser passes through a read error. */
- GRPC_JSON_PARSE_ERROR, /* The parser found an error in the json stream. */
- GRPC_JSON_INTERNAL_ERROR /* The parser got an internal error. */
-} grpc_json_reader_ret_t;
diff --git a/src/core/json/json-string.c b/src/core/json/json-string.c
deleted file mode 100644
index 771c2cc..0000000
--- a/src/core/json/json-string.c
+++ /dev/null
@@ -1,378 +0,0 @@
-/*
- *
- * Copyright 2014, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include <string.h>
-
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-
-#include "src/core/json/json.h"
-
-/* This json-writer will put everything in a big string.
- * The point is that we allocate that string in chunks of 256 bytes.
- */
-typedef struct {
- char *output;
- size_t free_space, string_len, allocated;
-} grpc_json_writer_opaque_t;
-
-#include "src/core/json/json-writer-defs.h"
-
-/* The json-reader will construct a bunch of grpc_json objects and
- * link them all up together in a tree-like structure that will represent
- * the json data in memory.
- *
- * It also uses its own input as a scratchpad to store all of the decoded,
- * unescaped strings. So we need to keep track of all these pointers in
- * that opaque structure the reader will carry for us.
- *
- * Note that this works because the act of parsing json always reduces its
- * input size, and never expands it.
- */
-typedef struct {
- grpc_json *top;
- grpc_json *current_container;
- grpc_json *current_value;
- char *input;
- char *key;
- char *string;
- char *string_ptr;
- size_t remaining_input;
-} grpc_json_reader_opaque_t;
-
-typedef unsigned grpc_json_wchar_t;
-
-#include "src/core/json/json-reader-defs.h"
-
-/* Next up, the definitions needed for the implementation. */
-#define grpc_json_static_inline static
-#define grpc_json_eof -1
-#define grpc_json_eagain -2
-#define grpc_json_error -3
-
-/* This functions checks if there's enough space left in the output buffer,
- * and will enlarge it if necessary. We're only allocating chunks of 256
- * bytes at a time (or multiples thereof).
- */
-static void grpc_json_writer_output_check(struct grpc_json_writer_t *writer,
- size_t needed) {
- if (writer->opaque.free_space >= needed) return;
- needed = (needed - writer->opaque.free_space + 0xff) & ~0xff;
- writer->opaque.output = (char *)gpr_realloc(
- writer->opaque.output, writer->opaque.allocated + needed);
- writer->opaque.free_space += needed;
- writer->opaque.allocated += needed;
-}
-
-/* These are needed by the writer's implementation. */
-static void grpc_json_writer_output_char(struct grpc_json_writer_t *writer,
- char c) {
- grpc_json_writer_output_check(writer, 1);
- writer->opaque.output[writer->opaque.string_len++] = c;
- writer->opaque.free_space--;
-}
-
-static void grpc_json_writer_output_string_with_len(
- struct grpc_json_writer_t *writer, const char *str, size_t len) {
- grpc_json_writer_output_check(writer, len);
- memcpy(writer->opaque.output + writer->opaque.string_len, str, len);
- writer->opaque.string_len += len;
- writer->opaque.free_space -= len;
-}
-
-static void grpc_json_writer_output_string(struct grpc_json_writer_t *writer,
- const char *str) {
- size_t len = strlen(str);
- grpc_json_writer_output_string_with_len(writer, str, len);
-}
-
-#include "src/core/json/json-writer-impl.h"
-
-/* The reader asks us to clear our scratchpad. In our case, we'll simply mark
- * the end of the current string, and advance our output pointer.
- */
-static void grpc_json_reader_string_clear(struct grpc_json_reader_t *reader) {
- if (reader->opaque.string) {
- GPR_ASSERT(reader->opaque.string_ptr < reader->opaque.input);
- *reader->opaque.string_ptr++ = 0;
- }
- reader->opaque.string = reader->opaque.string_ptr;
-}
-
-static void grpc_json_reader_string_add_char(struct grpc_json_reader_t *reader,
- int c) {
- GPR_ASSERT(reader->opaque.string_ptr < reader->opaque.input);
- *reader->opaque.string_ptr++ = (char)c;
-}
-
-/* We are converting a unicode character into utf-8 here. */
-/* The unicode escape encoding of json can only hold 16-bits values.
- * So the the 4th case, as well as the last test aren't techically
- * necessary, but I wrote them anyway for completion.
- */
-static void grpc_json_reader_string_add_wchar(struct grpc_json_reader_t *reader,
- unsigned int c) {
- if (c <= 0x7f) {
- grpc_json_reader_string_add_char(reader, c);
- } else if (c <= 0x7ff) {
- int b1 = 0xc0 | ((c >> 6) & 0x1f);
- int b2 = 0x80 | (c & 0x3f);
- grpc_json_reader_string_add_char(reader, b1);
- grpc_json_reader_string_add_char(reader, b2);
- } else if (c <= 0xffff) {
- int b1 = 0xe0 | ((c >> 12) & 0x0f);
- int b2 = 0x80 | ((c >> 6) & 0x3f);
- int b3 = 0x80 | (c & 0x3f);
- grpc_json_reader_string_add_char(reader, b1);
- grpc_json_reader_string_add_char(reader, b2);
- grpc_json_reader_string_add_char(reader, b3);
- } else if (c <= 0x1fffff) {
- int b1 = 0xf0 | ((c >> 18) & 0x07);
- int b2 = 0x80 | ((c >> 12) & 0x3f);
- int b3 = 0x80 | ((c >> 6) & 0x3f);
- int b4 = 0x80 | (c & 0x3f);
- grpc_json_reader_string_add_char(reader, b1);
- grpc_json_reader_string_add_char(reader, b2);
- grpc_json_reader_string_add_char(reader, b3);
- grpc_json_reader_string_add_char(reader, b4);
- }
-}
-
-/* We consider that the input may be a zero-terminated string. So we
- * can end up hitting eof before the end of the alleged string length.
- */
-static int grpc_json_reader_read_char(struct grpc_json_reader_t *reader) {
- int r;
-
- if (reader->opaque.remaining_input == 0) {
- return grpc_json_eof;
- }
-
- r = *reader->opaque.input++;
- reader->opaque.remaining_input--;
-
- if (r == 0) {
- reader->opaque.remaining_input = 0;
- return grpc_json_eof;
- }
-
- return r;
-}
-
-/* Helper function to create a new grpc_json object and link it into
- * our tree-in-progress inside our opaque structure.
- */
-static grpc_json *grpc_json_new_and_link(struct grpc_json_reader_t *reader,
- enum grpc_json_type_t type) {
- grpc_json *json = grpc_json_new(type);
-
- json->parent = reader->opaque.current_container;
- json->prev = reader->opaque.current_value;
- reader->opaque.current_value = json;
-
- if (json->prev) {
- json->prev->next = json;
- }
- if (json->parent) {
- if (!json->parent->child) {
- json->parent->child = json;
- }
- if (json->parent->type == GRPC_JSON_OBJECT) {
- json->key = reader->opaque.key;
- }
- }
- if (!reader->opaque.top) {
- reader->opaque.top = json;
- }
-
- return json;
-}
-
-static void grpc_json_reader_container_begins(struct grpc_json_reader_t *reader,
- enum grpc_json_type_t type) {
- grpc_json *container;
-
- GPR_ASSERT(type == GRPC_JSON_ARRAY || type == GRPC_JSON_OBJECT);
-
- container = grpc_json_new_and_link(reader, type);
- reader->opaque.current_container = container;
- reader->opaque.current_value = NULL;
-}
-
-/* It's important to remember that the reader is mostly state-less, so it
- * isn't trying to remember what was the container prior the one that just
- * ends. Since we're keeping track of these for our own purpose, we are
- * able to return that information back, which is useful for it to validate
- * the input json stream.
- *
- * Also note that if we're at the top of the tree, and the last container
- * ends, we have to return GRPC_JSON_NONE.
- */
-static enum grpc_json_type_t grpc_json_reader_container_ends(
- struct grpc_json_reader_t *reader) {
- enum grpc_json_type_t container_type = GRPC_JSON_NONE;
-
- GPR_ASSERT(reader->opaque.current_container);
-
- reader->opaque.current_value = reader->opaque.current_container;
- reader->opaque.current_container = reader->opaque.current_container->parent;
-
- if (reader->opaque.current_container) {
- container_type = reader->opaque.current_container->type;
- }
-
- return container_type;
-}
-
-/* The next 3 functions basically are the reader asking us to use our string
- * scratchpad for one of these 3 purposes.
- *
- * Note that in the set_number case, we're not going to try interpreting it.
- * We'll keep it as a string, and leave it to the caller to evaluate it.
- */
-static void grpc_json_reader_object_set_key(struct grpc_json_reader_t *reader) {
- reader->opaque.key = reader->opaque.string;
-}
-
-static void grpc_json_reader_container_set_string(
- struct grpc_json_reader_t *reader) {
- grpc_json *json = grpc_json_new_and_link(reader, GRPC_JSON_STRING);
- json->value = reader->opaque.string;
-}
-
-static int grpc_json_reader_container_set_number(
- struct grpc_json_reader_t *reader) {
- grpc_json *json = grpc_json_new_and_link(reader, GRPC_JSON_NUMBER);
- json->value = reader->opaque.string;
- return 1;
-}
-
-/* The object types true, false and null are self-sufficient, and don't need
- * any more information beside their type.
- */
-static void grpc_json_reader_container_set_true(
- struct grpc_json_reader_t *reader) {
- grpc_json_new_and_link(reader, GRPC_JSON_TRUE);
-}
-
-static void grpc_json_reader_container_set_false(
- struct grpc_json_reader_t *reader) {
- grpc_json_new_and_link(reader, GRPC_JSON_FALSE);
-}
-
-static void grpc_json_reader_container_set_null(
- struct grpc_json_reader_t *reader) {
- grpc_json_new_and_link(reader, GRPC_JSON_NULL);
-}
-
-/* Now that we've defined all that's needed for the parser's implementation,
- * let's include its file. */
-#include "json-reader-impl.h"
-
-/* And finally, let's define our public API. */
-grpc_json *grpc_json_parse_string_with_len(char *input, size_t size) {
- struct grpc_json_reader_t reader;
- grpc_json *json = NULL;
- grpc_json_reader_ret_t status;
-
- if (!input) return NULL;
-
- reader.opaque.top = reader.opaque.current_container =
- reader.opaque.current_value = NULL;
- reader.opaque.string = reader.opaque.key = NULL;
- reader.opaque.string_ptr = reader.opaque.input = input;
- reader.opaque.remaining_input = size;
- grpc_json_reader_init(&reader);
-
- status = grpc_json_reader_run(&reader);
- json = reader.opaque.top;
-
- if ((status != GRPC_JSON_DONE) && json) {
- grpc_json_delete(json);
- json = NULL;
- }
-
- return json;
-}
-
-grpc_json *grpc_json_parse_string(char *input) {
- return grpc_json_parse_string_with_len(input, 0x7fffffff);
-}
-
-static void grpc_json_dump_recursive(struct grpc_json_writer_t *writer,
- grpc_json *json, int in_object) {
- while (json) {
- if (in_object) grpc_json_writer_object_key(writer, json->key);
-
- switch (json->type) {
- case GRPC_JSON_OBJECT:
- case GRPC_JSON_ARRAY:
- grpc_json_writer_container_begins(writer, json->type);
- if (json->child)
- grpc_json_dump_recursive(writer, json->child,
- json->type == GRPC_JSON_OBJECT);
- grpc_json_writer_container_ends(writer, json->type);
- break;
- case GRPC_JSON_STRING:
- grpc_json_writer_value_string(writer, json->value);
- break;
- case GRPC_JSON_NUMBER:
- grpc_json_writer_value_raw(writer, json->value);
- break;
- case GRPC_JSON_TRUE:
- grpc_json_writer_value_raw_with_len(writer, "true", 4);
- break;
- case GRPC_JSON_FALSE:
- grpc_json_writer_value_raw_with_len(writer, "false", 5);
- break;
- case GRPC_JSON_NULL:
- grpc_json_writer_value_raw_with_len(writer, "null", 4);
- break;
- default:
- abort();
- }
- json = json->next;
- }
-}
-
-char *grpc_json_dump_to_string(grpc_json *json, int indent) {
- struct grpc_json_writer_t writer;
- writer.opaque.output = NULL;
- writer.opaque.free_space = writer.opaque.string_len =
- writer.opaque.allocated = 0;
- grpc_json_writer_init(&writer, indent);
- grpc_json_dump_recursive(&writer, json, 0);
- grpc_json_writer_output_char(&writer, 0);
-
- return writer.opaque.output;
-}
diff --git a/src/core/json/json-writer-defs.h b/src/core/json/json-writer-defs.h
deleted file mode 100644
index f8ab988..0000000
--- a/src/core/json/json-writer-defs.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- *
- * Copyright 2014, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-/* the following need to be pre-defined:
- * grpc_json_writer_opaque_t // A type you can use to keep track of your
- * // own stuff.
- */
-
-struct grpc_json_writer_t {
- grpc_json_writer_opaque_t opaque;
-
- int indent;
- int depth;
- int container_empty;
- int got_key;
-};
diff --git a/src/core/json/json-writer-impl.h b/src/core/json/json-writer-impl.h
deleted file mode 100644
index f3ef968..0000000
--- a/src/core/json/json-writer-impl.h
+++ /dev/null
@@ -1,233 +0,0 @@
-/*
- *
- * Copyright 2014, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-
-/* The idea of the writer is basically symmetrical of the reader. While the
- * reader emits various calls to your code, the writer takes basically the
- * same calls and emit json out of it. It doesn't try to make any check on
- * the order of the calls you do on it.
- *
- * Also, unlike the reader, the writer expects UTF-8 encoded input strings.
- *
- * The following need to be defined:
- *
- * // Adds a character to the output stream.
- * void grpc_json_writer_output_char(struct grpc_json_writer_t *, char);
- * // Adds a zero-terminated string to the output stream.
- * void grpc_json_writer_output_string(
- * struct grpc_json_writer_t *writer, const char *str);
- * // Adds a fixed-length string to the output stream.
- * void grpc_json_writer_output_string_with_len(
- * struct grpc_json_writer_t *writer, const char *str, size_t len);
-
- */
-
-/* Call this function to initialize the writer structure. */
-grpc_json_static_inline void grpc_json_writer_init(
- struct grpc_json_writer_t* writer, int indent) {
- writer->depth = 0;
- writer->container_empty = 1;
- writer->got_key = 0;
- writer->indent = indent;
-}
-
-/* This function is fully private. */
-grpc_json_static_inline void grpc_json_writer_output_indent(
- struct grpc_json_writer_t* writer) {
- static const char spacesstr[] =
- " "
- " "
- " "
- " ";
-
- int spaces = writer->depth * writer->indent;
-
- if (writer->got_key) {
- grpc_json_writer_output_char(writer, ' ');
- return;
- }
-
- while (spaces >= (sizeof(spacesstr) - 1)) {
- grpc_json_writer_output_string_with_len(writer, spacesstr,
- sizeof(spacesstr) - 1);
- spaces -= (sizeof(spacesstr) - 1);
- }
-
- if (!spaces) return;
-
- grpc_json_writer_output_string_with_len(
- writer, spacesstr + sizeof(spacesstr) - 1 - spaces, spaces);
-}
-
-/* This function is fully private. */
-grpc_json_static_inline void grpc_json_writer_value_end(
- struct grpc_json_writer_t* writer) {
- if (writer->container_empty) {
- writer->container_empty = 0;
- if (!writer->indent || !writer->depth) return;
- grpc_json_writer_output_char(writer, '\n');
- } else {
- grpc_json_writer_output_char(writer, ',');
- if (!writer->indent) return;
- grpc_json_writer_output_char(writer, '\n');
- }
-}
-
-/* This function is fully private. */
-grpc_json_static_inline void grpc_json_writer_escape_string(
- struct grpc_json_writer_t* writer, const char* string) {
- static const char hex[] = "0123456789abcdef";
- grpc_json_writer_output_char(writer, '"');
-
- for (;;) {
- unsigned char c = (unsigned char)*string++;
- if (!c) {
- break;
- } else if ((c >= 32) && (c <= 127)) {
- if ((c == '\\') || (c == '"')) grpc_json_writer_output_char(writer, '\\');
- grpc_json_writer_output_char(writer, c);
- } else if (c < 32) {
- grpc_json_writer_output_char(writer, '\\');
- switch (c) {
- case '\b':
- grpc_json_writer_output_char(writer, 'b');
- break;
- case '\f':
- grpc_json_writer_output_char(writer, 'f');
- break;
- case '\n':
- grpc_json_writer_output_char(writer, 'n');
- break;
- case '\r':
- grpc_json_writer_output_char(writer, 'r');
- break;
- case '\t':
- grpc_json_writer_output_char(writer, 't');
- break;
- default:
- grpc_json_writer_output_string_with_len(writer, "u00", 3);
- grpc_json_writer_output_char(writer, c >= 16 ? '1' : '0');
- grpc_json_writer_output_char(writer, hex[c & 15]);
- break;
- }
- } else {
- unsigned unicode = 0;
- if ((c & 0xe0) == 0xc0) {
- unicode = c & 0x1f;
- unicode <<= 6;
- c = *string++;
- if ((c & 0xc0) != 0x80) break;
- unicode |= c & 0x3f;
- } else if ((c & 0xf0) == 0xe0) {
- unicode = c & 0x0f;
- unicode <<= 6;
- c = *string++;
- if ((c & 0xc0) != 0x80) break;
- unicode |= c & 0x3f;
- unicode <<= 6;
- c = *string++;
- if ((c & 0xc0) != 0x80) break;
- unicode |= c & 0x3f;
- } else {
- break;
- }
- grpc_json_writer_output_string_with_len(writer, "\\u", 2);
- grpc_json_writer_output_char(writer, hex[(unicode >> 12) & 0x0f]);
- grpc_json_writer_output_char(writer, hex[(unicode >> 8) & 0x0f]);
- grpc_json_writer_output_char(writer, hex[(unicode >> 4) & 0x0f]);
- grpc_json_writer_output_char(writer, hex[(unicode) & 0x0f]);
- }
- }
-
- grpc_json_writer_output_char(writer, '"');
-}
-
-/* Call that function to start a new json container. */
-grpc_json_static_inline void grpc_json_writer_container_begins(
- struct grpc_json_writer_t* writer, enum grpc_json_type_t type) {
- if (!writer->got_key) grpc_json_writer_value_end(writer);
- grpc_json_writer_output_indent(writer);
- grpc_json_writer_output_char(writer, type == GRPC_JSON_OBJECT ? '{' : '[');
- writer->container_empty = 1;
- writer->got_key = 0;
- writer->depth++;
-}
-
-/* Call that function to end the current json container. */
-grpc_json_static_inline void grpc_json_writer_container_ends(
- struct grpc_json_writer_t* writer, enum grpc_json_type_t type) {
- if (writer->indent && !writer->container_empty)
- grpc_json_writer_output_char(writer, '\n');
- writer->depth--;
- if (!writer->container_empty) grpc_json_writer_output_indent(writer);
- grpc_json_writer_output_char(writer, type == GRPC_JSON_OBJECT ? '}' : ']');
- writer->container_empty = 0;
- writer->got_key = 0;
-}
-
-/* If you are in a GRPC_JSON_OBJECT container, call this to set up a key. */
-grpc_json_static_inline void grpc_json_writer_object_key(
- struct grpc_json_writer_t* writer, const char* string) {
- grpc_json_writer_value_end(writer);
- grpc_json_writer_output_indent(writer);
- grpc_json_writer_escape_string(writer, string);
- grpc_json_writer_output_char(writer, ':');
- writer->got_key = 1;
-}
-
-/* Sets a raw value - use it for numbers. */
-grpc_json_static_inline void grpc_json_writer_value_raw(
- struct grpc_json_writer_t* writer, const char* string) {
- if (!writer->got_key) grpc_json_writer_value_end(writer);
- grpc_json_writer_output_indent(writer);
- grpc_json_writer_output_string(writer, string);
- writer->got_key = 0;
-}
-
-/* Sets a raw value with a known length - use it for true, false and null. */
-grpc_json_static_inline void grpc_json_writer_value_raw_with_len(
- struct grpc_json_writer_t* writer, const char* string, unsigned len) {
- if (!writer->got_key) grpc_json_writer_value_end(writer);
- grpc_json_writer_output_indent(writer);
- grpc_json_writer_output_string_with_len(writer, string, len);
- writer->got_key = 0;
-}
-
-/* Outputs a string value. This will add double quotes, and escape it. */
-grpc_json_static_inline void grpc_json_writer_value_string(
- struct grpc_json_writer_t* writer, const char* string) {
- if (!writer->got_key) grpc_json_writer_value_end(writer);
- grpc_json_writer_output_indent(writer);
- grpc_json_writer_escape_string(writer, string);
- writer->got_key = 0;
-}
diff --git a/src/core/json/json.c b/src/core/json/json.c
index 2905aba..e7fcec3 100644
--- a/src/core/json/json.c
+++ b/src/core/json/json.c
@@ -35,8 +35,8 @@
#include "src/core/json/json.h"
-grpc_json *grpc_json_new(enum grpc_json_type_t type) {
- grpc_json *json = (grpc_json *)gpr_malloc(sizeof(grpc_json));
+grpc_json *grpc_json_new(grpc_json_type type) {
+ grpc_json *json = gpr_malloc(sizeof(grpc_json));
json->parent = json->child = json->next = json->prev = NULL;
json->type = type;
diff --git a/src/core/json/json.h b/src/core/json/json.h
index a0bc4df..433ba22 100644
--- a/src/core/json/json.h
+++ b/src/core/json/json.h
@@ -36,12 +36,18 @@
#include <stdlib.h>
-#include "src/core/json/json-defs.h"
+#include "src/core/json/json_common.h"
-typedef struct grpc_json_t {
- struct grpc_json_t* next, *prev, *child, *parent;
- enum grpc_json_type_t type;
+/* A tree-like structure to hold json values. The key and value pointers
+ * are not owned by it.
+ */
+typedef struct grpc_json {
+ struct grpc_json* next;
+ struct grpc_json* prev;
+ struct grpc_json* child;
+ struct grpc_json* parent;
+ grpc_json_type type;
const char* key;
const char* value;
} grpc_json;
@@ -51,7 +57,11 @@
* all of the keys and values for the returned object tree.
*
* They assume UTF-8 input stream, and will output UTF-8 encoded
- * strings in the tree.
+ * strings in the tree. The input stream's UTF-8 isn't validated,
+ * as in, what you input is what you get as an output.
+ *
+ * All the keys and values in the grpc_json_t objects will be strings
+ * pointing at your input buffer.
*
* Delete the allocated tree afterward using grpc_json_delete().
*/
@@ -72,7 +82,7 @@
* Deletion is recursive. We will not attempt to free any of the strings
* in any of the objects of that tree.
*/
-grpc_json* grpc_json_new(enum grpc_json_type_t type);
+grpc_json* grpc_json_new(grpc_json_type type);
void grpc_json_delete(grpc_json* json);
#endif /* __GRPC_SRC_CORE_JSON_JSON_H__ */
diff --git a/src/core/json/json-defs.h b/src/core/json/json_common.h
similarity index 87%
rename from src/core/json/json-defs.h
rename to src/core/json/json_common.h
index decf35e..88a8155 100644
--- a/src/core/json/json-defs.h
+++ b/src/core/json/json_common.h
@@ -31,8 +31,11 @@
*
*/
-/* The various json types. "NONE" may only used on top-level. */
-enum grpc_json_type_t {
+#ifndef __GRPC_SRC_CORE_JSON_JSON_COMMON_H__
+#define __GRPC_SRC_CORE_JSON_JSON_COMMON_H__
+
+/* The various json types. */
+typedef enum {
GRPC_JSON_OBJECT,
GRPC_JSON_ARRAY,
GRPC_JSON_STRING,
@@ -40,5 +43,7 @@
GRPC_JSON_TRUE,
GRPC_JSON_FALSE,
GRPC_JSON_NULL,
- GRPC_JSON_NONE
-};
+ GRPC_JSON_TOP_LEVEL
+} grpc_json_type;
+
+#endif /* __GRPC_SRC_CORE_JSON_JSON_COMMON_H__ */
diff --git a/src/core/json/json-reader-impl.h b/src/core/json/json_reader.c
similarity index 75%
rename from src/core/json/json-reader-impl.h
rename to src/core/json/json_reader.c
index 2fe5695..c387796 100644
--- a/src/core/json/json-reader-impl.h
+++ b/src/core/json/json_reader.c
@@ -31,113 +31,93 @@
*
*/
-/* the following need to be pre-defined:
- * grpc_json_static_inline // A macro to declare a static inline
- * // function
- * grpc_json_eof // A macro that can be used in a switch
- * // statement, that grpc_json_read_char
- * // can return
- * grpc_json_eagain // A macro that can be used in a switch
- * // statement, that grpc_json_read_char
- * // can return
- * grpc_json_error // A macro that can be used in a switch
- * // statement, that grpc_json_read_char
- * // can return
- *
- * // A macro or a function that clears your internal scratchpad.
- * grpc_json_reader_string_clear(struct grpc_json_reader_t*);
- * // A macro or a function that adds a character to your internal
- * // scratchpad.
- * grpc_json_reader_string_add_char(struct grpc_json_reader_t*, int);
- * // A macro or a function that adds a unicode character to your internal
- * // scratchpad.
- * grpc_json_reader_string_add_wchar(struct grpc_json_reader_t*,
- * grpc_json_wchar_t);
- *
- * // A macro or a function that returns the next character from the input.
- * // It can return:
- * // . an actual character into an int - unicode, wchar_t, whatever, as
- * // long as it's going to work in a switch statement, and can be tested
- * // against typical json tokens, such as '{', '[', ',', '}', ']', digits
- * // and whitespaces.
- * // . grpc_json_eof, which means the end of the input has been reached.
- * // . grpc_json_eagain, which means the parser needs to yield before
- * // getting more input.
- * // . grpc_json_error, which means the parser needs to exit with an error.
- * int grpc_json_reader_read_char(struct grpc_json_reader_t*);
- *
- * // A macro or a function that will be called to signal the beginning of a
- * // container.
- * // The argument "type" can be either GRPC_JSON_OBJECT, or GRPC_JSON_ARRAY.
- * void grpc_json_reader_container_begins(struct grpc_json_reader_t*,
- * enum *grpc_json_type_t type)
- * // A macro or a function that will be called to signal the end of the
- * // current container. It must return GRPC_JSON_OBJECT or GRPC_JSON_ARRAY
- * // to signal what is the new current container, or GRPC_JSON_NONE if the
- * // stack of containers is now empty.
- * enum grpc_json_type_t
- * grpc_json_reader_container_ends(struct grpc_json_reader_t*);
- *
- * // A macro or a function that will be called to signal that json->string
- * // contains the string of a object's key that is being added.
- * void grpc_json_reader_object_set_key(struct grpc_json_reader_t*);
- *
- * // A set of macro or functions that will be called to signal that the
- * // current container is getting a new value. set_string and set_number
- * // are reading their value from your internal scratchpad. set_number
- * // must return a boolean to signal if the number parsing succeeded or
- * // not. There is little reason for it not to.
- * void grpc_json_reader_container_set_string(struct grpc_json_reader_t*);
- * int grpc_json_reader_container_set_number(struct grpc_json_reader_t*);
- * void grpc_json_reader_container_set_true(struct grpc_json_reader_t*);
- * void grpc_json_reader_container_set_false(struct grpc_json_reader_t*);
- * void grpc_json_reader_container_set_null(struct grpc_json_reader_t*);
- */
+#include <grpc/support/port_platform.h>
+#include "src/core/json/json_reader.h"
+
+static void grpc_json_reader_string_clear(grpc_json_reader* reader) {
+ reader->string_clear(reader);
+}
+
+static void grpc_json_reader_string_add_char(grpc_json_reader* reader,
+ gpr_uint32 c) {
+ reader->string_add_char(reader, c);
+}
+
+static void grpc_json_reader_string_add_utf32(grpc_json_reader* reader,
+ gpr_uint32 utf32) {
+ reader->string_add_utf32(reader, utf32);
+}
+
+static gpr_uint32
+ grpc_json_reader_read_char(grpc_json_reader* reader) {
+ return reader->read_char(reader);
+}
+
+static void grpc_json_reader_container_begins(grpc_json_reader* reader,
+ grpc_json_type type) {
+ reader->container_begins(reader, type);
+}
+
+static grpc_json_type
+ grpc_json_reader_container_ends(grpc_json_reader* reader) {
+ return reader->container_ends(reader);
+}
+
+static void grpc_json_reader_set_key(grpc_json_reader* reader) {
+ reader->set_key(reader);
+}
+
+static void grpc_json_reader_set_string(grpc_json_reader* reader) {
+ reader->set_string(reader);
+}
+
+static int grpc_json_reader_set_number(grpc_json_reader* reader) {
+ return reader->set_number(reader);
+}
+
+static void grpc_json_reader_set_true(grpc_json_reader* reader) {
+ reader->set_true(reader);
+}
+
+static void grpc_json_reader_set_false(grpc_json_reader* reader) {
+ reader->set_false(reader);
+}
+
+static void grpc_json_reader_set_null(grpc_json_reader* reader) {
+ reader->set_null(reader);
+}
/* Call this function to initialize the reader structure. */
-grpc_json_static_inline void grpc_json_reader_init(
- struct grpc_json_reader_t* reader) {
+void grpc_json_reader_init(grpc_json_reader* reader) {
reader->depth = 0;
reader->in_object = 0;
reader->in_array = 0;
+ reader->unicode_high_surrogate = 0;
grpc_json_reader_string_clear(reader);
reader->state = GRPC_JSON_STATE_VALUE_BEGIN;
}
-/* Call this function to start parsing the input. It will return the following:
- * . GRPC_JSON_DONE if the input got eof, and the parsing finished
- * successfully.
- * . GRPC_JSON_EAGAIN if the read_char function returned again. Call the
- * parser again as needed. It is okay to call the parser in polling mode,
- * although a bit dull.
- * . GRPC_JSON_READ_ERROR if the read_char function returned an error. The
- * state isn't broken however, and the function can be called again if the
- * error has been corrected. But please use the EAGAIN feature instead for
- * consistency.
- * . GRPC_JSON_PARSE_ERROR if the input was somehow invalid.
- * . GRPC_JSON_INTERNAL_ERROR if the parser somehow ended into an invalid
- * internal state.
- */
+int grpc_json_reader_is_complete(grpc_json_reader* reader) {
+ return ((reader->depth == 0) && ((reader->state == GRPC_JSON_STATE_END) ||
+ (reader->state == GRPC_JSON_STATE_VALUE_END)));
+}
-grpc_json_static_inline grpc_json_reader_ret_t
-grpc_json_reader_run(struct grpc_json_reader_t* reader) {
+grpc_json_reader_ret grpc_json_reader_run(grpc_json_reader* reader) {
int c, success;
- /* This state-machine is a strict implementation of http://json.org/ */
+ /* This state-machine is a strict implementation of ECMA-404 */
for (;;) {
c = grpc_json_reader_read_char(reader);
switch (c) {
/* Let's process the error cases first. */
- case grpc_json_error:
+ case GRPC_JSON_READ_CHAR_ERROR:
return GRPC_JSON_READ_ERROR;
- case grpc_json_eagain:
+ case GRPC_JSON_READ_CHAR_EAGAIN:
return GRPC_JSON_EAGAIN;
- case grpc_json_eof:
- if ((reader->depth == 0) &&
- ((reader->state == GRPC_JSON_STATE_END) ||
- (reader->state == GRPC_JSON_STATE_VALUE_END))) {
+ case GRPC_JSON_READ_CHAR_EOF:
+ if (grpc_json_reader_is_complete(reader)) {
return GRPC_JSON_DONE;
} else {
return GRPC_JSON_PARSE_ERROR;
@@ -159,6 +139,8 @@
case GRPC_JSON_STATE_OBJECT_KEY_STRING:
case GRPC_JSON_STATE_VALUE_STRING:
+ if (c != ' ') return GRPC_JSON_PARSE_ERROR;
+ if (reader->unicode_high_surrogate) return GRPC_JSON_PARSE_ERROR;
grpc_json_reader_string_add_char(reader, c);
break;
@@ -166,7 +148,7 @@
case GRPC_JSON_STATE_VALUE_NUMBER_WITH_DECIMAL:
case GRPC_JSON_STATE_VALUE_NUMBER_ZERO:
case GRPC_JSON_STATE_VALUE_NUMBER_EPM:
- success = grpc_json_reader_container_set_number(reader);
+ success = grpc_json_reader_set_number(reader);
if (!success) return GRPC_JSON_PARSE_ERROR;
grpc_json_reader_string_clear(reader);
reader->state = GRPC_JSON_STATE_VALUE_END;
@@ -184,6 +166,7 @@
switch (reader->state) {
case GRPC_JSON_STATE_OBJECT_KEY_STRING:
case GRPC_JSON_STATE_VALUE_STRING:
+ if (reader->unicode_high_surrogate) return GRPC_JSON_PARSE_ERROR;
grpc_json_reader_string_add_char(reader, c);
break;
@@ -191,7 +174,7 @@
case GRPC_JSON_STATE_VALUE_NUMBER_WITH_DECIMAL:
case GRPC_JSON_STATE_VALUE_NUMBER_ZERO:
case GRPC_JSON_STATE_VALUE_NUMBER_EPM:
- success = grpc_json_reader_container_set_number(reader);
+ success = grpc_json_reader_set_number(reader);
if (!success) return GRPC_JSON_PARSE_ERROR;
grpc_json_reader_string_clear(reader);
reader->state = GRPC_JSON_STATE_VALUE_END;
@@ -235,7 +218,7 @@
reader->in_object = 0;
reader->in_array = 1;
break;
- case GRPC_JSON_NONE:
+ case GRPC_JSON_TOP_LEVEL:
if (reader->depth != 0) return GRPC_JSON_INTERNAL_ERROR;
reader->in_object = 0;
reader->in_array = 0;
@@ -267,6 +250,7 @@
/* This is the \\ case. */
case GRPC_JSON_STATE_STRING_ESCAPE:
+ if (reader->unicode_high_surrogate) return GRPC_JSON_PARSE_ERROR;
grpc_json_reader_string_add_char(reader, '\\');
if (reader->escaped_string_was_key) {
reader->state = GRPC_JSON_STATE_OBJECT_KEY_STRING;
@@ -289,21 +273,25 @@
break;
case GRPC_JSON_STATE_OBJECT_KEY_STRING:
+ if (reader->unicode_high_surrogate) return GRPC_JSON_PARSE_ERROR;
if (c == '"') {
reader->state = GRPC_JSON_STATE_OBJECT_KEY_END;
- grpc_json_reader_object_set_key(reader);
+ grpc_json_reader_set_key(reader);
grpc_json_reader_string_clear(reader);
} else {
+ if (c < 32) return GRPC_JSON_PARSE_ERROR;
grpc_json_reader_string_add_char(reader, c);
}
break;
case GRPC_JSON_STATE_VALUE_STRING:
+ if (reader->unicode_high_surrogate) return GRPC_JSON_PARSE_ERROR;
if (c == '"') {
reader->state = GRPC_JSON_STATE_VALUE_END;
- grpc_json_reader_container_set_string(reader);
+ grpc_json_reader_set_string(reader);
grpc_json_reader_string_clear(reader);
} else {
+ if (c < 32) return GRPC_JSON_PARSE_ERROR;
grpc_json_reader_string_add_char(reader, c);
}
break;
@@ -374,6 +362,8 @@
} else {
reader->state = GRPC_JSON_STATE_VALUE_STRING;
}
+ if (reader->unicode_high_surrogate && c != 'u')
+ return GRPC_JSON_PARSE_ERROR;
switch (c) {
case '"':
case '/':
@@ -396,7 +386,7 @@
break;
case 'u':
reader->state = GRPC_JSON_STATE_STRING_ESCAPE_U1;
- reader->unicode = 0;
+ reader->unicode_char = 0;
break;
default:
return GRPC_JSON_PARSE_ERROR;
@@ -416,8 +406,8 @@
} else {
return GRPC_JSON_PARSE_ERROR;
}
- reader->unicode <<= 4;
- reader->unicode |= c;
+ reader->unicode_char <<= 4;
+ reader->unicode_char |= c;
switch (reader->state) {
case GRPC_JSON_STATE_STRING_ESCAPE_U1:
@@ -430,7 +420,27 @@
reader->state = GRPC_JSON_STATE_STRING_ESCAPE_U4;
break;
case GRPC_JSON_STATE_STRING_ESCAPE_U4:
- grpc_json_reader_string_add_wchar(reader, reader->unicode);
+ if ((reader->unicode_char & 0xfc00) == 0xd800) {
+ /* high surrogate utf-16 */
+ if (reader->unicode_high_surrogate)
+ return GRPC_JSON_PARSE_ERROR;
+ reader->unicode_high_surrogate = reader->unicode_char;
+ } else if ((reader->unicode_char & 0xfc00) == 0xdc00) {
+ /* low surrogate utf-16 */
+ gpr_uint32 utf32;
+ if (!reader->unicode_high_surrogate)
+ return GRPC_JSON_PARSE_ERROR;
+ utf32 = 0x10000;
+ utf32 += (reader->unicode_high_surrogate - 0xd800) * 0x400;
+ utf32 += reader->unicode_char - 0xdc00;
+ grpc_json_reader_string_add_utf32(reader, utf32);
+ reader->unicode_high_surrogate = 0;
+ } else {
+ /* anything else */
+ if (reader->unicode_high_surrogate)
+ return GRPC_JSON_PARSE_ERROR;
+ grpc_json_reader_string_add_utf32(reader, reader->unicode_char);
+ }
if (reader->escaped_string_was_key) {
reader->state = GRPC_JSON_STATE_OBJECT_KEY_STRING;
} else {
@@ -564,7 +574,7 @@
case GRPC_JSON_STATE_VALUE_TRUE_E:
if (c != 'e') return GRPC_JSON_PARSE_ERROR;
- grpc_json_reader_container_set_true(reader);
+ grpc_json_reader_set_true(reader);
reader->state = GRPC_JSON_STATE_VALUE_END;
break;
@@ -585,7 +595,7 @@
case GRPC_JSON_STATE_VALUE_FALSE_E:
if (c != 'e') return GRPC_JSON_PARSE_ERROR;
- grpc_json_reader_container_set_false(reader);
+ grpc_json_reader_set_false(reader);
reader->state = GRPC_JSON_STATE_VALUE_END;
break;
@@ -601,7 +611,7 @@
case GRPC_JSON_STATE_VALUE_NULL_L2:
if (c != 'l') return GRPC_JSON_PARSE_ERROR;
- grpc_json_reader_container_set_null(reader);
+ grpc_json_reader_set_null(reader);
reader->state = GRPC_JSON_STATE_VALUE_END;
break;
diff --git a/src/core/json/json_reader.h b/src/core/json/json_reader.h
new file mode 100644
index 0000000..d71f0b8
--- /dev/null
+++ b/src/core/json/json_reader.h
@@ -0,0 +1,158 @@
+/*
+ *
+ * Copyright 2014, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPC_SRC_CORE_JSON_JSON_READER_H__
+#define __GRPC_SRC_CORE_JSON_JSON_READER_H__
+
+#include <grpc/support/port_platform.h>
+#include "src/core/json/json_common.h"
+
+typedef enum {
+ GRPC_JSON_STATE_OBJECT_KEY_BEGIN,
+ GRPC_JSON_STATE_OBJECT_KEY_STRING,
+ GRPC_JSON_STATE_OBJECT_KEY_END,
+ GRPC_JSON_STATE_VALUE_BEGIN,
+ GRPC_JSON_STATE_VALUE_STRING,
+ GRPC_JSON_STATE_STRING_ESCAPE,
+ GRPC_JSON_STATE_STRING_ESCAPE_U1,
+ GRPC_JSON_STATE_STRING_ESCAPE_U2,
+ GRPC_JSON_STATE_STRING_ESCAPE_U3,
+ GRPC_JSON_STATE_STRING_ESCAPE_U4,
+ GRPC_JSON_STATE_VALUE_NUMBER,
+ GRPC_JSON_STATE_VALUE_NUMBER_WITH_DECIMAL,
+ GRPC_JSON_STATE_VALUE_NUMBER_ZERO,
+ GRPC_JSON_STATE_VALUE_NUMBER_DOT,
+ GRPC_JSON_STATE_VALUE_NUMBER_E,
+ GRPC_JSON_STATE_VALUE_NUMBER_EPM,
+ GRPC_JSON_STATE_VALUE_TRUE_R,
+ GRPC_JSON_STATE_VALUE_TRUE_U,
+ GRPC_JSON_STATE_VALUE_TRUE_E,
+ GRPC_JSON_STATE_VALUE_FALSE_A,
+ GRPC_JSON_STATE_VALUE_FALSE_L,
+ GRPC_JSON_STATE_VALUE_FALSE_S,
+ GRPC_JSON_STATE_VALUE_FALSE_E,
+ GRPC_JSON_STATE_VALUE_NULL_U,
+ GRPC_JSON_STATE_VALUE_NULL_L1,
+ GRPC_JSON_STATE_VALUE_NULL_L2,
+ GRPC_JSON_STATE_VALUE_END,
+ GRPC_JSON_STATE_END
+} grpc_json_reader_state;
+
+enum {
+ /* The first non-unicode value is 0x110000. But let's pick
+ * a value high enough to start our error codes from. These
+ * values are safe to return from the read_char function.
+ */
+ GRPC_JSON_READ_CHAR_EOF = 0x7ffffff0,
+ GRPC_JSON_READ_CHAR_EAGAIN,
+ GRPC_JSON_READ_CHAR_ERROR
+};
+
+typedef struct grpc_json_reader {
+ /* You are responsible for your own opaque userdata.
+ * Among other things, it needs to hold a string scratchpad.
+ */
+ void* userdata;
+
+ /* You also need to set up these callbacks. */
+
+ /* Clears your internal string scratchpad. */
+ void (*string_clear)(struct grpc_json_reader*);
+ /* Adds a char to the string scratchpad. */
+ void (*string_add_char)(struct grpc_json_reader*, gpr_uint32 c);
+ /* Adds a utf32 char to the string scratchpad. */
+ void (*string_add_utf32)(struct grpc_json_reader*, gpr_uint32 c);
+ /* Reads a character from your input. May be utf-8, 16 or 32. */
+ gpr_uint32 (*read_char)(struct grpc_json_reader*);
+ /* Starts a container of type GRPC_JSON_ARRAY or GRPC_JSON_OBJECT. */
+ void (*container_begins)(struct grpc_json_reader*, grpc_json_type type);
+ /* Ends the current container. Must return the type of its parent. */
+ grpc_json_type (*container_ends)(struct grpc_json_reader*);
+ /* Your internal string scratchpad is an object's key. */
+ void (*set_key)(struct grpc_json_reader*);
+ /* Your internal string scratchpad is a string value. */
+ void (*set_string)(struct grpc_json_reader*);
+ /* Your internal string scratchpad is a numerical value. Return 1 if valid. */
+ int (*set_number)(struct grpc_json_reader*);
+ /* Sets the values true, false or null. */
+ void (*set_true)(struct grpc_json_reader*);
+ void (*set_false)(struct grpc_json_reader*);
+ void (*set_null)(struct grpc_json_reader*);
+
+ /* Everything down here is private,
+ and initialized by grpc_json_reader_init. */
+ int depth;
+ int in_object;
+ int in_array;
+ int escaped_string_was_key;
+ int container_just_begun;
+ gpr_uint16 unicode_char, unicode_high_surrogate;
+ grpc_json_reader_state state;
+} grpc_json_reader;
+
+/* The return type of the parser. */
+typedef enum {
+ GRPC_JSON_DONE, /* The parser finished successfully. */
+ GRPC_JSON_EAGAIN, /* The parser yields to get more data. */
+ GRPC_JSON_READ_ERROR, /* The parser passes through a read error. */
+ GRPC_JSON_PARSE_ERROR, /* The parser found an error in the json stream. */
+ GRPC_JSON_INTERNAL_ERROR /* The parser got an internal error. */
+} grpc_json_reader_ret;
+
+/* Call this function to start parsing the input. It will return the following:
+ * . GRPC_JSON_DONE if the input got eof, and the parsing finished
+ * successfully.
+ * . GRPC_JSON_EAGAIN if the read_char function returned again. Call the
+ * parser again as needed. It is okay to call the parser in polling mode,
+ * although a bit dull.
+ * . GRPC_JSON_READ_ERROR if the read_char function returned an error. The
+ * state isn't broken however, and the function can be called again if the
+ * error has been corrected. But please use the EAGAIN feature instead for
+ * consistency.
+ * . GRPC_JSON_PARSE_ERROR if the input was somehow invalid.
+ * . GRPC_JSON_INTERNAL_ERROR if the parser somehow ended into an invalid
+ * internal state.
+ */
+grpc_json_reader_ret grpc_json_reader_run(grpc_json_reader* reader);
+
+/* Call this function to initialize the reader structure. */
+void grpc_json_reader_init(grpc_json_reader* reader);
+
+/* You may call this from the read_char callback if you don't know where is the
+ * end of your input stream, and you'd like the json reader to hint you that it
+ * has completed reading its input, so you can return an EOF to it. Note that
+ * there might still be trailing whitespaces after that point.
+ */
+int grpc_json_reader_is_complete(grpc_json_reader* reader);
+
+#endif /* __GRPC_SRC_CORE_JSON_JSON_READER_H__ */
diff --git a/src/core/json/json_string.c b/src/core/json/json_string.c
new file mode 100644
index 0000000..12309c4
--- /dev/null
+++ b/src/core/json/json_string.c
@@ -0,0 +1,391 @@
+/*
+ *
+ * Copyright 2014, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <string.h>
+#include <stdlib.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+
+#include "src/core/json/json.h"
+#include "src/core/json/json_reader.h"
+#include "src/core/json/json_writer.h"
+
+/* The json reader will construct a bunch of grpc_json objects and
+ * link them all up together in a tree-like structure that will represent
+ * the json data in memory.
+ *
+ * It also uses its own input as a scratchpad to store all of the decoded,
+ * unescaped strings. So we need to keep track of all these pointers in
+ * that opaque structure the reader will carry for us.
+ *
+ * Note that this works because the act of parsing json always reduces its
+ * input size, and never expands it.
+ */
+typedef struct {
+ grpc_json* top;
+ grpc_json* current_container;
+ grpc_json* current_value;
+ char* input;
+ char* key;
+ char* string;
+ char* string_ptr;
+ size_t remaining_input;
+} grpc_json_reader_opaque;
+
+/* This json writer will put everything in a big string.
+ * The point is that we allocate that string in chunks of 256 bytes.
+ */
+typedef struct {
+ char* output;
+ size_t free_space, string_len, allocated;
+} grpc_json_writer_opaque;
+
+
+/* This function checks if there's enough space left in the output buffer,
+ * and will enlarge it if necessary. We're only allocating chunks of 256
+ * bytes at a time (or multiples thereof).
+ */
+static void grpc_json_writer_output_check(grpc_json_writer* writer,
+ size_t needed) {
+ grpc_json_writer_opaque* state = writer->userdata;
+ if (state->free_space >= needed) return;
+ needed -= state->free_space;
+ /* Round up by 256 bytes. */
+ needed = (needed + 0xff) & ~0xff;
+ state->output = gpr_realloc(state->output, state->allocated + needed);
+ state->free_space += needed;
+ state->allocated += needed;
+}
+
+/* These are needed by the writer's implementation. */
+static void grpc_json_writer_output_char(grpc_json_writer* writer,
+ char c) {
+ grpc_json_writer_opaque* state = writer->userdata;
+ grpc_json_writer_output_check(writer, 1);
+ state->output[state->string_len++] = c;
+ state->free_space--;
+}
+
+static void grpc_json_writer_output_string_with_len(
+ grpc_json_writer* writer, const char* str, size_t len) {
+ grpc_json_writer_opaque* state = writer->userdata;
+ grpc_json_writer_output_check(writer, len);
+ memcpy(state->output + state->string_len, str, len);
+ state->string_len += len;
+ state->free_space -= len;
+}
+
+static void grpc_json_writer_output_string(grpc_json_writer* writer,
+ const char* str) {
+ size_t len = strlen(str);
+ grpc_json_writer_output_string_with_len(writer, str, len);
+}
+
+/* The reader asks us to clear our scratchpad. In our case, we'll simply mark
+ * the end of the current string, and advance our output pointer.
+ */
+static void grpc_json_reader_string_clear(grpc_json_reader* reader) {
+ grpc_json_reader_opaque* state = reader->userdata;
+ if (state->string) {
+ GPR_ASSERT(state->string_ptr < state->input);
+ *state->string_ptr++ = 0;
+ }
+ state->string = state->string_ptr;
+}
+
+static void grpc_json_reader_string_add_char(grpc_json_reader* reader, gpr_uint32 c) {
+ grpc_json_reader_opaque* state = reader->userdata;
+ GPR_ASSERT(state->string_ptr < state->input);
+ GPR_ASSERT(c <= 0xff);
+ *state->string_ptr++ = (char)c;
+}
+
+/* We are converting a UTF-32 character into UTF-8 here. */
+static void grpc_json_reader_string_add_utf32(grpc_json_reader* reader, gpr_uint32 c) {
+ if (c <= 0x7f) {
+ grpc_json_reader_string_add_char(reader, c);
+ } else if (c <= 0x7ff) {
+ int b1 = 0xc0 | ((c >> 6) & 0x1f);
+ int b2 = 0x80 | (c & 0x3f);
+ grpc_json_reader_string_add_char(reader, b1);
+ grpc_json_reader_string_add_char(reader, b2);
+ } else if (c <= 0xffff) {
+ int b1 = 0xe0 | ((c >> 12) & 0x0f);
+ int b2 = 0x80 | ((c >> 6) & 0x3f);
+ int b3 = 0x80 | (c & 0x3f);
+ grpc_json_reader_string_add_char(reader, b1);
+ grpc_json_reader_string_add_char(reader, b2);
+ grpc_json_reader_string_add_char(reader, b3);
+ } else if (c <= 0x1fffff) {
+ int b1 = 0xf0 | ((c >> 18) & 0x07);
+ int b2 = 0x80 | ((c >> 12) & 0x3f);
+ int b3 = 0x80 | ((c >> 6) & 0x3f);
+ int b4 = 0x80 | (c & 0x3f);
+ grpc_json_reader_string_add_char(reader, b1);
+ grpc_json_reader_string_add_char(reader, b2);
+ grpc_json_reader_string_add_char(reader, b3);
+ grpc_json_reader_string_add_char(reader, b4);
+ }
+}
+
+/* We consider that the input may be a zero-terminated string. So we
+ * can end up hitting eof before the end of the alleged string length.
+ */
+static gpr_uint32 grpc_json_reader_read_char(grpc_json_reader* reader) {
+ gpr_uint32 r;
+ grpc_json_reader_opaque* state = reader->userdata;
+
+ if (state->remaining_input == 0) return GRPC_JSON_READ_CHAR_EOF;
+
+ r = *state->input++;
+ state->remaining_input--;
+
+ if (r == 0) {
+ state->remaining_input = 0;
+ return GRPC_JSON_READ_CHAR_EOF;
+ }
+
+ return r;
+}
+
+/* Helper function to create a new grpc_json object and link it into
+ * our tree-in-progress inside our opaque structure.
+ */
+static grpc_json* grpc_json_new_and_link(grpc_json_reader* reader,
+ grpc_json_type type) {
+ grpc_json_reader_opaque* state = reader->userdata;
+ grpc_json* json = grpc_json_new(type);
+
+ json->parent = state->current_container;
+ json->prev = state->current_value;
+ state->current_value = json;
+
+ if (json->prev) {
+ json->prev->next = json;
+ }
+ if (json->parent) {
+ if (!json->parent->child) {
+ json->parent->child = json;
+ }
+ if (json->parent->type == GRPC_JSON_OBJECT) {
+ json->key = state->key;
+ }
+ }
+ if (!state->top) {
+ state->top = json;
+ }
+
+ return json;
+}
+
+static void grpc_json_reader_container_begins(grpc_json_reader* reader,
+ grpc_json_type type) {
+ grpc_json_reader_opaque* state = reader->userdata;
+ grpc_json* container;
+
+ GPR_ASSERT(type == GRPC_JSON_ARRAY || type == GRPC_JSON_OBJECT);
+
+ container = grpc_json_new_and_link(reader, type);
+ state->current_container = container;
+ state->current_value = NULL;
+}
+
+/* It's important to remember that the reader is mostly stateless, so it
+ * isn't trying to remember what the container was prior the one that just
+ * ends. Since we're keeping track of these for our own purpose, we are
+ * able to return that information back, which is useful for it to validate
+ * the input json stream.
+ *
+ * Also note that if we're at the top of the tree, and the last container
+ * ends, we have to return GRPC_JSON_TOP_LEVEL.
+ */
+static grpc_json_type grpc_json_reader_container_ends(
+ grpc_json_reader* reader) {
+ grpc_json_type container_type = GRPC_JSON_TOP_LEVEL;
+ grpc_json_reader_opaque* state = reader->userdata;
+
+ GPR_ASSERT(state->current_container);
+
+ state->current_value = state->current_container;
+ state->current_container = state->current_container->parent;
+
+ if (state->current_container) {
+ container_type = state->current_container->type;
+ }
+
+ return container_type;
+}
+
+/* The next 3 functions basically are the reader asking us to use our string
+ * scratchpad for one of these 3 purposes.
+ *
+ * Note that in the set_number case, we're not going to try interpreting it.
+ * We'll keep it as a string, and leave it to the caller to evaluate it.
+ */
+static void grpc_json_reader_set_key(grpc_json_reader* reader) {
+ grpc_json_reader_opaque* state = reader->userdata;
+ state->key = state->string;
+}
+
+static void grpc_json_reader_set_string(
+ grpc_json_reader* reader) {
+ grpc_json_reader_opaque* state = reader->userdata;
+ grpc_json* json = grpc_json_new_and_link(reader, GRPC_JSON_STRING);
+ json->value = state->string;
+}
+
+static int grpc_json_reader_set_number(
+ grpc_json_reader* reader) {
+ grpc_json_reader_opaque* state = reader->userdata;
+ grpc_json* json = grpc_json_new_and_link(reader, GRPC_JSON_NUMBER);
+ json->value = state->string;
+ return 1;
+}
+
+/* The object types true, false and null are self-sufficient, and don't need
+ * any more information beside their type.
+ */
+static void grpc_json_reader_set_true(
+ grpc_json_reader *reader) {
+ grpc_json_new_and_link(reader, GRPC_JSON_TRUE);
+}
+
+static void grpc_json_reader_set_false(
+ grpc_json_reader *reader) {
+ grpc_json_new_and_link(reader, GRPC_JSON_FALSE);
+}
+
+static void grpc_json_reader_set_null(
+ grpc_json_reader *reader) {
+ grpc_json_new_and_link(reader, GRPC_JSON_NULL);
+}
+
+/* And finally, let's define our public API. */
+grpc_json* grpc_json_parse_string_with_len(char* input, size_t size) {
+ grpc_json_reader reader;
+ grpc_json_reader_opaque state;
+ grpc_json *json = NULL;
+ grpc_json_reader_ret status;
+
+ if (!input) return NULL;
+
+ state.top = state.current_container = state.current_value = NULL;
+ state.string = state.key = NULL;
+ state.string_ptr = state.input = input;
+ state.remaining_input = size;
+ reader.userdata = &state;
+ reader.string_clear = grpc_json_reader_string_clear;
+ reader.string_add_char = grpc_json_reader_string_add_char;
+ reader.string_add_utf32 = grpc_json_reader_string_add_utf32;
+ reader.read_char = grpc_json_reader_read_char;
+ reader.container_begins = grpc_json_reader_container_begins;
+ reader.container_ends = grpc_json_reader_container_ends;
+ reader.set_key = grpc_json_reader_set_key;
+ reader.set_string = grpc_json_reader_set_string;
+ reader.set_number = grpc_json_reader_set_number;
+ reader.set_true = grpc_json_reader_set_true;
+ reader.set_false = grpc_json_reader_set_false;
+ reader.set_null = grpc_json_reader_set_null;
+ grpc_json_reader_init(&reader);
+
+ status = grpc_json_reader_run(&reader);
+ json = state.top;
+
+ if ((status != GRPC_JSON_DONE) && json) {
+ grpc_json_delete(json);
+ json = NULL;
+ }
+
+ return json;
+}
+
+#define UNBOUND_JSON_STRING_LENGTH 0x7fffffff
+
+grpc_json* grpc_json_parse_string(char* input) {
+ return grpc_json_parse_string_with_len(input, UNBOUND_JSON_STRING_LENGTH);
+}
+
+static void grpc_json_dump_recursive(grpc_json_writer* writer,
+ grpc_json* json, int in_object) {
+ while (json) {
+ if (in_object) grpc_json_writer_object_key(writer, json->key);
+
+ switch (json->type) {
+ case GRPC_JSON_OBJECT:
+ case GRPC_JSON_ARRAY:
+ grpc_json_writer_container_begins(writer, json->type);
+ if (json->child)
+ grpc_json_dump_recursive(writer, json->child,
+ json->type == GRPC_JSON_OBJECT);
+ grpc_json_writer_container_ends(writer, json->type);
+ break;
+ case GRPC_JSON_STRING:
+ grpc_json_writer_value_string(writer, json->value);
+ break;
+ case GRPC_JSON_NUMBER:
+ grpc_json_writer_value_raw(writer, json->value);
+ break;
+ case GRPC_JSON_TRUE:
+ grpc_json_writer_value_raw_with_len(writer, "true", 4);
+ break;
+ case GRPC_JSON_FALSE:
+ grpc_json_writer_value_raw_with_len(writer, "false", 5);
+ break;
+ case GRPC_JSON_NULL:
+ grpc_json_writer_value_raw_with_len(writer, "null", 4);
+ break;
+ default:
+ abort();
+ }
+ json = json->next;
+ }
+}
+
+char* grpc_json_dump_to_string(grpc_json* json, int indent) {
+ grpc_json_writer writer;
+ grpc_json_writer_opaque state;
+ state.output = NULL;
+ state.free_space = state.string_len = state.allocated = 0;
+ writer.userdata = &state;
+ writer.output_char = grpc_json_writer_output_char;
+ writer.output_string = grpc_json_writer_output_string;
+ writer.output_string_with_len = grpc_json_writer_output_string_with_len;
+ grpc_json_writer_init(&writer, indent);
+
+ grpc_json_dump_recursive(&writer, json, 0);
+
+ grpc_json_writer_output_char(&writer, 0);
+
+ return state.output;
+}
diff --git a/src/core/json/json_writer.c b/src/core/json/json_writer.c
new file mode 100644
index 0000000..9fc65aa
--- /dev/null
+++ b/src/core/json/json_writer.c
@@ -0,0 +1,248 @@
+/*
+ *
+ * Copyright 2014, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/support/port_platform.h>
+#include "src/core/json/json_writer.h"
+
+static void grpc_json_writer_output_char(grpc_json_writer* writer, char c) {
+ writer->output_char(writer, c);
+}
+
+static void grpc_json_writer_output_string(grpc_json_writer* writer, const char* str) {
+ writer->output_string(writer, str);
+}
+
+static void grpc_json_writer_output_string_with_len(grpc_json_writer* writer, const char* str, size_t len) {
+ writer->output_string_with_len(writer, str, len);
+}
+
+/* Call this function to initialize the writer structure. */
+void grpc_json_writer_init(grpc_json_writer* writer, int indent) {
+ writer->depth = 0;
+ writer->container_empty = 1;
+ writer->got_key = 0;
+ writer->indent = indent;
+}
+
+static void grpc_json_writer_output_indent(
+ grpc_json_writer* writer) {
+ static const char spacesstr[] =
+ " "
+ " "
+ " "
+ " ";
+
+ int spaces = writer->depth * writer->indent;
+
+ if (writer->got_key) {
+ grpc_json_writer_output_char(writer, ' ');
+ return;
+ }
+
+ while (spaces >= (sizeof(spacesstr) - 1)) {
+ grpc_json_writer_output_string_with_len(writer, spacesstr,
+ sizeof(spacesstr) - 1);
+ spaces -= (sizeof(spacesstr) - 1);
+ }
+
+ if (!spaces) return;
+
+ grpc_json_writer_output_string_with_len(
+ writer, spacesstr + sizeof(spacesstr) - 1 - spaces, spaces);
+}
+
+static void grpc_json_writer_value_end(
+ grpc_json_writer* writer) {
+ if (writer->container_empty) {
+ writer->container_empty = 0;
+ if (!writer->indent || !writer->depth) return;
+ grpc_json_writer_output_char(writer, '\n');
+ } else {
+ grpc_json_writer_output_char(writer, ',');
+ if (!writer->indent) return;
+ grpc_json_writer_output_char(writer, '\n');
+ }
+}
+
+static void grpc_json_writer_escape_utf16(grpc_json_writer* writer, gpr_uint16 utf16) {
+ static const char hex[] = "0123456789abcdef";
+
+ grpc_json_writer_output_string_with_len(writer, "\\u", 2);
+ grpc_json_writer_output_char(writer, hex[(utf16 >> 12) & 0x0f]);
+ grpc_json_writer_output_char(writer, hex[(utf16 >> 8) & 0x0f]);
+ grpc_json_writer_output_char(writer, hex[(utf16 >> 4) & 0x0f]);
+ grpc_json_writer_output_char(writer, hex[(utf16) & 0x0f]);
+}
+
+static void grpc_json_writer_escape_string(
+ grpc_json_writer* writer, const char* string) {
+ grpc_json_writer_output_char(writer, '"');
+
+ for (;;) {
+ unsigned char c = (unsigned char)*string++;
+ if (!c) {
+ break;
+ } else if ((c >= 32) && (c <= 127)) {
+ if ((c == '\\') || (c == '"')) grpc_json_writer_output_char(writer, '\\');
+ grpc_json_writer_output_char(writer, c);
+ } else if (c < 32) {
+ grpc_json_writer_output_char(writer, '\\');
+ switch (c) {
+ case '\b':
+ grpc_json_writer_output_char(writer, 'b');
+ break;
+ case '\f':
+ grpc_json_writer_output_char(writer, 'f');
+ break;
+ case '\n':
+ grpc_json_writer_output_char(writer, 'n');
+ break;
+ case '\r':
+ grpc_json_writer_output_char(writer, 'r');
+ break;
+ case '\t':
+ grpc_json_writer_output_char(writer, 't');
+ break;
+ default:
+ grpc_json_writer_escape_utf16(writer, c);
+ break;
+ }
+ } else {
+ gpr_uint32 utf32 = 0;
+ int extra = 0;
+ int i;
+ int valid = 1;
+ if ((c & 0xe0) == 0xc0) {
+ utf32 = c & 0x1f;
+ extra = 1;
+ } else if ((c & 0xf0) == 0xe0) {
+ utf32 = c & 0x0f;
+ extra = 2;
+ } else if ((c & 0xf8) == 0xf0) {
+ utf32 = c & 0x07;
+ extra = 3;
+ } else {
+ break;
+ }
+ for (i = 0; i < extra; i++) {
+ utf32 <<= 6;
+ c = *string++;
+ if ((c & 0xc0) != 0x80) {
+ valid = 0;
+ break;
+ }
+ utf32 |= c & 0x3f;
+ }
+ if (!valid) break;
+ /* The range 0xd800 - 0xdfff is reserved by the surrogates ad vitam.
+ * Any other range is technically reserved for future usage, so if we
+ * don't want the software to break in the future, we have to allow
+ * anything else. The first non-unicode character is 0x110000. */
+ if (((utf32 >= 0xd800) && (utf32 <= 0xdfff)) ||
+ (utf32 >= 0x110000)) break;
+ if (utf32 >= 0x10000) {
+ /* If utf32 contains a character that is above 0xffff, it needs to be
+ * broken down into a utf-16 surrogate pair. A surrogate pair is first
+ * a high surrogate, followed by a low surrogate. Each surrogate holds
+ * 10 bits of usable data, thus allowing a total of 20 bits of data.
+ * The high surrogate marker is 0xd800, while the low surrogate marker
+ * is 0xdc00. The low 10 bits of each will be the usable data.
+ *
+ * After re-combining the 20 bits of data, one has to add 0x10000 to
+ * the resulting value, in order to obtain the original character.
+ * This is obviously because the range 0x0000 - 0xffff can be written
+ * without any special trick.
+ *
+ * Since 0x10ffff is the highest allowed character, we're working in
+ * the range 0x00000 - 0xfffff after we decrement it by 0x10000.
+ * That range is exactly 20 bits.
+ */
+ utf32 -= 0x10000;
+ grpc_json_writer_escape_utf16(writer, 0xd800 | (utf32 >> 10));
+ grpc_json_writer_escape_utf16(writer, 0xdc00 | (utf32 && 0x3ff));
+ } else {
+ grpc_json_writer_escape_utf16(writer, utf32);
+ }
+ }
+ }
+
+ grpc_json_writer_output_char(writer, '"');
+}
+
+void grpc_json_writer_container_begins(grpc_json_writer* writer, grpc_json_type type) {
+ if (!writer->got_key) grpc_json_writer_value_end(writer);
+ grpc_json_writer_output_indent(writer);
+ grpc_json_writer_output_char(writer, type == GRPC_JSON_OBJECT ? '{' : '[');
+ writer->container_empty = 1;
+ writer->got_key = 0;
+ writer->depth++;
+}
+
+void grpc_json_writer_container_ends(grpc_json_writer* writer, grpc_json_type type) {
+ if (writer->indent && !writer->container_empty)
+ grpc_json_writer_output_char(writer, '\n');
+ writer->depth--;
+ if (!writer->container_empty) grpc_json_writer_output_indent(writer);
+ grpc_json_writer_output_char(writer, type == GRPC_JSON_OBJECT ? '}' : ']');
+ writer->container_empty = 0;
+ writer->got_key = 0;
+}
+
+void grpc_json_writer_object_key(grpc_json_writer* writer, const char* string) {
+ grpc_json_writer_value_end(writer);
+ grpc_json_writer_output_indent(writer);
+ grpc_json_writer_escape_string(writer, string);
+ grpc_json_writer_output_char(writer, ':');
+ writer->got_key = 1;
+}
+
+void grpc_json_writer_value_raw(grpc_json_writer* writer, const char* string) {
+ if (!writer->got_key) grpc_json_writer_value_end(writer);
+ grpc_json_writer_output_indent(writer);
+ grpc_json_writer_output_string(writer, string);
+ writer->got_key = 0;
+}
+
+void grpc_json_writer_value_raw_with_len(grpc_json_writer* writer, const char* string, size_t len) {
+ if (!writer->got_key) grpc_json_writer_value_end(writer);
+ grpc_json_writer_output_indent(writer);
+ grpc_json_writer_output_string_with_len(writer, string, len);
+ writer->got_key = 0;
+}
+
+void grpc_json_writer_value_string(grpc_json_writer* writer, const char* string) {
+ if (!writer->got_key) grpc_json_writer_value_end(writer);
+ grpc_json_writer_output_indent(writer);
+ grpc_json_writer_escape_string(writer, string);
+ writer->got_key = 0;
+}
diff --git a/src/core/json/json_writer.h b/src/core/json/json_writer.h
new file mode 100644
index 0000000..f0baa1e
--- /dev/null
+++ b/src/core/json/json_writer.h
@@ -0,0 +1,92 @@
+/*
+ *
+ * Copyright 2014, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/* The idea of the writer is basically symmetrical of the reader. While the
+ * reader emits various calls to your code, the writer takes basically the
+ * same calls and emit json out of it. It doesn't try to make any check on
+ * the order of the calls you do on it. Meaning you can theorically force
+ * it to generate invalid json.
+ *
+ * Also, unlike the reader, the writer expects UTF-8 encoded input strings.
+ * These strings will be UTF-8 validated, and any invalid character will
+ * cut the conversion short, before any invalid UTF-8 sequence, thus forming
+ * a valid UTF-8 string overall.
+ */
+
+#ifndef __GRPC_SRC_CORE_JSON_JSON_WRITER_H__
+#define __GRPC_SRC_CORE_JSON_JSON_WRITER_H__
+
+#include <stdlib.h>
+
+#include "src/core/json/json_common.h"
+
+typedef struct grpc_json_writer {
+ /* You are responsible for your own opaque userdata. */
+ void* userdata;
+
+ /* The rest are your own callbacks. Define them. */
+
+ /* Adds a character to the output stream. */
+ void (*output_char)(struct grpc_json_writer*, char);
+ /* Adds a zero-terminated string to the output stream. */
+ void (*output_string)(struct grpc_json_writer*, const char* str);
+ /* Adds a fixed-length string to the output stream. */
+ void (*output_string_with_len)(struct grpc_json_writer*, const char* str, size_t len);
+
+ int indent;
+ int depth;
+ int container_empty;
+ int got_key;
+} grpc_json_writer;
+
+/* Call this to initialize your writer structure. The indent parameter is
+ * specifying the number of spaces to use for indenting the output. If you
+ * use indent=0, then the output will not have any newlines either, thus
+ * emitting a condensed json output.
+ */
+void grpc_json_writer_init(grpc_json_writer* writer, int indent);
+
+/* Signals the beginning of a container. */
+void grpc_json_writer_container_begins(grpc_json_writer* writer, grpc_json_type type);
+/* Signals the end of a container. */
+void grpc_json_writer_container_ends(grpc_json_writer* writer, grpc_json_type type);
+/* Writes down an object key for the next value. */
+void grpc_json_writer_object_key(grpc_json_writer* writer, const char* string);
+/* Sets a raw value. Useful for numbers. */
+void grpc_json_writer_value_raw(grpc_json_writer* writer, const char* string);
+/* Sets a raw value with its length. Useful for values like true or false. */
+void grpc_json_writer_value_raw_with_len(grpc_json_writer* writer, const char* string, size_t len);
+/* Sets a string value. It'll be escaped, and utf-8 validated. */
+void grpc_json_writer_value_string(grpc_json_writer* writer, const char* string);
+
+#endif /* __GRPC_SRC_CORE_JSON_JSON_WRITER_H__ */
diff --git a/src/core/security/credentials.c b/src/core/security/credentials.c
index 78937c1..28adf1e 100644
--- a/src/core/security/credentials.c
+++ b/src/core/security/credentials.c
@@ -392,7 +392,7 @@
}
gpr_asprintf(&new_access_token, "%s %s", token_type->value,
access_token->value);
- token_lifetime->tv_sec = expires_in->valueint;
+ token_lifetime->tv_sec = strtol(expires_in->value, NULL, 10);
token_lifetime->tv_nsec = 0;
if (*token_elem != NULL) grpc_mdelem_unref(*token_elem);
*token_elem = grpc_mdelem_from_strings(ctx, GRPC_AUTHORIZATION_METADATA_KEY,
diff --git a/src/core/security/json_token.c b/src/core/security/json_token.c
index 2da30f4..9aeeb89 100644
--- a/src/core/security/json_token.c
+++ b/src/core/security/json_token.c
@@ -169,26 +169,26 @@
/* --- jwt encoding and signature. --- */
-static void create_child(grpc_json **brother, grpc_json *parent,
+static grpc_json *create_child(grpc_json *brother, grpc_json *parent,
const char *key, const char *value,
- enum grpc_json_type_t type) {
+ grpc_json_type type) {
grpc_json *child = grpc_json_new(type);
- if (*brother) (*brother)->next = child;
+ if (brother) (brother)->next = child;
if (!parent->child) parent->child = child;
child->parent = parent;
child->value = value;
child->key = key;
- *brother = child;
+ return child;
}
static char *encoded_jwt_header(const char *algorithm) {
grpc_json *json = grpc_json_new(GRPC_JSON_OBJECT);
- grpc_json *brother = NULL;
+ grpc_json *child = NULL;
char *json_str = NULL;
char *result = NULL;
- create_child(&brother, json, "alg", algorithm, GRPC_JSON_STRING);
- create_child(&brother, json, "typ", GRPC_JWT_TYPE, GRPC_JSON_STRING);
+ child = create_child(NULL, json, "alg", algorithm, GRPC_JSON_STRING);
+ create_child(child, json, "typ", GRPC_JWT_TYPE, GRPC_JSON_STRING);
json_str = grpc_json_dump_to_string(json, 0);
result = grpc_base64_encode(json_str, strlen(json_str), 1, 0);
@@ -200,7 +200,7 @@
static char *encoded_jwt_claim(const grpc_auth_json_key *json_key,
const char *scope, gpr_timespec token_lifetime) {
grpc_json *json = grpc_json_new(GRPC_JSON_OBJECT);
- grpc_json *brother = NULL;
+ grpc_json *child = NULL;
char *json_str = NULL;
char *result = NULL;
gpr_timespec now = gpr_now();
@@ -215,11 +215,12 @@
sprintf(now_str, "%ld", now.tv_sec);
sprintf(expiration_str, "%ld", expiration.tv_sec);
- create_child(&brother, json, "iss", json_key->client_email, GRPC_JSON_STRING);
- create_child(&brother, json, "scope", scope, GRPC_JSON_STRING);
- create_child(&brother, json, "aud", GRPC_JWT_AUDIENCE, GRPC_JSON_STRING);
- create_child(&brother, json, "iat", now_str, GRPC_JSON_NUMBER);
- create_child(&brother, json, "exp", expiration_str, GRPC_JSON_NUMBER);
+ child = create_child(NULL, json, "iss", json_key->client_email,
+ GRPC_JSON_STRING);
+ child = create_child(child, json, "scope", scope, GRPC_JSON_STRING);
+ child = create_child(child, json, "aud", GRPC_JWT_AUDIENCE, GRPC_JSON_STRING);
+ child = create_child(child, json, "iat", now_str, GRPC_JSON_NUMBER);
+ create_child(child, json, "exp", expiration_str, GRPC_JSON_NUMBER);
json_str = grpc_json_dump_to_string(json, 0);
result = grpc_base64_encode(json_str, strlen(json_str), 1, 0);
diff --git a/test/core/security/credentials_test.c b/test/core/security/credentials_test.c
index ec21e0d..fbad52d 100644
--- a/test/core/security/credentials_test.c
+++ b/test/core/security/credentials_test.c
@@ -55,23 +55,23 @@
Maximum size for a string literal is 509 chars in C89, yay! */
static const char test_json_key_str_part1[] =
"{ \"private_key\": \"-----BEGIN PRIVATE KEY-----"
- "\nMIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBAOEvJsnoHnyHkXcp\n7mJEqg"
- "WGjiw71NfXByguekSKho65FxaGbsnSM9SMQAqVk7Q2rG+I0OpsT0LrWQtZ\nyjSeg/"
+ "\\nMIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBAOEvJsnoHnyHkXcp\\n7mJEqg"
+ "WGjiw71NfXByguekSKho65FxaGbsnSM9SMQAqVk7Q2rG+I0OpsT0LrWQtZ\\nyjSeg/"
"rWBQvS4hle4LfijkP3J5BG+"
- "IXDMP8RfziNRQsenAXDNPkY4kJCvKux2xdD\nOnVF6N7dL3nTYZg+"
- "uQrNsMTz9UxVAgMBAAECgYEAzbLewe1xe9vy+2GoSsfib+28\nDZgSE6Bu/"
- "zuFoPrRc6qL9p2SsnV7txrunTyJkkOnPLND9ABAXybRTlcVKP/sGgza\n/"
+ "IXDMP8RfziNRQsenAXDNPkY4kJCvKux2xdD\\nOnVF6N7dL3nTYZg+"
+ "uQrNsMTz9UxVAgMBAAECgYEAzbLewe1xe9vy+2GoSsfib+28\\nDZgSE6Bu/"
+ "zuFoPrRc6qL9p2SsnV7txrunTyJkkOnPLND9ABAXybRTlcVKP/sGgza\\n/"
"8HpCqFYM9V8f34SBWfD4fRFT+n/"
- "73cfRUtGXdXpseva2lh8RilIQfPhNZAncenU\ngqXjDvpkypEusgXAykECQQD+";
+ "73cfRUtGXdXpseva2lh8RilIQfPhNZAncenU\\ngqXjDvpkypEusgXAykECQQD+";
static const char test_json_key_str_part2[] =
- "53XxNVnxBHsYb+AYEfklR96yVi8HywjVHP34+OQZ\nCslxoHQM8s+"
- "dBnjfScLu22JqkPv04xyxmt0QAKm9+vTdAkEA4ib7YvEAn2jXzcCI\nEkoy2L/"
- "XydR1GCHoacdfdAwiL2npOdnbvi4ZmdYRPY1LSTO058tQHKVXV7NLeCa3\nAARh2QJBAMKeDAG"
- "W303SQv2cZTdbeaLKJbB5drz3eo3j7dDKjrTD9JupixFbzcGw\n8FZi5c8idxiwC36kbAL6HzA"
- "ZoX+ofI0CQE6KCzPJTtYNqyShgKAZdJ8hwOcvCZtf\n6z8RJm0+"
+ "53XxNVnxBHsYb+AYEfklR96yVi8HywjVHP34+OQZ\\nCslxoHQM8s+"
+ "dBnjfScLu22JqkPv04xyxmt0QAKm9+vTdAkEA4ib7YvEAn2jXzcCI\\nEkoy2L/"
+ "XydR1GCHoacdfdAwiL2npOdnbvi4ZmdYRPY1LSTO058tQHKVXV7NLeCa3\\nAARh2QJBAMKeDAG"
+ "W303SQv2cZTdbeaLKJbB5drz3eo3j7dDKjrTD9JupixFbzcGw\\n8FZi5c8idxiwC36kbAL6HzA"
+ "ZoX+ofI0CQE6KCzPJTtYNqyShgKAZdJ8hwOcvCZtf\\n6z8RJm0+"
"6YBd38lfh5j8mZd7aHFf6I17j5AQY7oPEc47TjJj/"
- "5nZ68ECQQDvYuI3\nLyK5fS8g0SYbmPOL9TlcHDOqwG0mrX9qpg5DC2fniXNSrrZ64GTDKdzZY"
- "Ap6LI9W\nIqv4vr6y38N79TTC\n-----END PRIVATE KEY-----\n\", ";
+ "5nZ68ECQQDvYuI3\\nLyK5fS8g0SYbmPOL9TlcHDOqwG0mrX9qpg5DC2fniXNSrrZ64GTDKdzZY"
+ "Ap6LI9W\\nIqv4vr6y38N79TTC\\n-----END PRIVATE KEY-----\\n\", ";
static const char test_json_key_str_part3[] =
"\"private_key_id\": \"e6b5137873db8d2ef81e06a47289e6434ec8a165\", "
"\"client_email\": "
diff --git a/test/core/security/json_token_test.c b/test/core/security/json_token_test.c
index 2f9f6dd..1eddfc1 100644
--- a/test/core/security/json_token_test.c
+++ b/test/core/security/json_token_test.c
@@ -49,23 +49,23 @@
Maximum size for a string literal is 509 chars in C89, yay! */
static const char test_json_key_str_part1[] =
"{ \"private_key\": \"-----BEGIN PRIVATE KEY-----"
- "\nMIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBAOEvJsnoHnyHkXcp\n7mJEqg"
- "WGjiw71NfXByguekSKho65FxaGbsnSM9SMQAqVk7Q2rG+I0OpsT0LrWQtZ\nyjSeg/"
+ "\\nMIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBAOEvJsnoHnyHkXcp\\n7mJEqg"
+ "WGjiw71NfXByguekSKho65FxaGbsnSM9SMQAqVk7Q2rG+I0OpsT0LrWQtZ\\nyjSeg/"
"rWBQvS4hle4LfijkP3J5BG+"
- "IXDMP8RfziNRQsenAXDNPkY4kJCvKux2xdD\nOnVF6N7dL3nTYZg+"
- "uQrNsMTz9UxVAgMBAAECgYEAzbLewe1xe9vy+2GoSsfib+28\nDZgSE6Bu/"
- "zuFoPrRc6qL9p2SsnV7txrunTyJkkOnPLND9ABAXybRTlcVKP/sGgza\n/"
+ "IXDMP8RfziNRQsenAXDNPkY4kJCvKux2xdD\\nOnVF6N7dL3nTYZg+"
+ "uQrNsMTz9UxVAgMBAAECgYEAzbLewe1xe9vy+2GoSsfib+28\\nDZgSE6Bu/"
+ "zuFoPrRc6qL9p2SsnV7txrunTyJkkOnPLND9ABAXybRTlcVKP/sGgza\\n/"
"8HpCqFYM9V8f34SBWfD4fRFT+n/"
- "73cfRUtGXdXpseva2lh8RilIQfPhNZAncenU\ngqXjDvpkypEusgXAykECQQD+";
+ "73cfRUtGXdXpseva2lh8RilIQfPhNZAncenU\\ngqXjDvpkypEusgXAykECQQD+";
static const char test_json_key_str_part2[] =
- "53XxNVnxBHsYb+AYEfklR96yVi8HywjVHP34+OQZ\nCslxoHQM8s+"
- "dBnjfScLu22JqkPv04xyxmt0QAKm9+vTdAkEA4ib7YvEAn2jXzcCI\nEkoy2L/"
- "XydR1GCHoacdfdAwiL2npOdnbvi4ZmdYRPY1LSTO058tQHKVXV7NLeCa3\nAARh2QJBAMKeDAG"
- "W303SQv2cZTdbeaLKJbB5drz3eo3j7dDKjrTD9JupixFbzcGw\n8FZi5c8idxiwC36kbAL6HzA"
- "ZoX+ofI0CQE6KCzPJTtYNqyShgKAZdJ8hwOcvCZtf\n6z8RJm0+"
+ "53XxNVnxBHsYb+AYEfklR96yVi8HywjVHP34+OQZ\\nCslxoHQM8s+"
+ "dBnjfScLu22JqkPv04xyxmt0QAKm9+vTdAkEA4ib7YvEAn2jXzcCI\\nEkoy2L/"
+ "XydR1GCHoacdfdAwiL2npOdnbvi4ZmdYRPY1LSTO058tQHKVXV7NLeCa3\\nAARh2QJBAMKeDAG"
+ "W303SQv2cZTdbeaLKJbB5drz3eo3j7dDKjrTD9JupixFbzcGw\\n8FZi5c8idxiwC36kbAL6HzA"
+ "ZoX+ofI0CQE6KCzPJTtYNqyShgKAZdJ8hwOcvCZtf\\n6z8RJm0+"
"6YBd38lfh5j8mZd7aHFf6I17j5AQY7oPEc47TjJj/"
- "5nZ68ECQQDvYuI3\nLyK5fS8g0SYbmPOL9TlcHDOqwG0mrX9qpg5DC2fniXNSrrZ64GTDKdzZY"
- "Ap6LI9W\nIqv4vr6y38N79TTC\n-----END PRIVATE KEY-----\n\", ";
+ "5nZ68ECQQDvYuI3\\nLyK5fS8g0SYbmPOL9TlcHDOqwG0mrX9qpg5DC2fniXNSrrZ64GTDKdzZY"
+ "Ap6LI9W\\nIqv4vr6y38N79TTC\\n-----END PRIVATE KEY-----\\n\", ";
static const char test_json_key_str_part3[] =
"\"private_key_id\": \"e6b5137873db8d2ef81e06a47289e6434ec8a165\", "
"\"client_email\": "
diff --git a/vsprojects/vs2013/grpc.vcxproj b/vsprojects/vs2013/grpc.vcxproj
index 28ea603..d325121 100644
--- a/vsprojects/vs2013/grpc.vcxproj
+++ b/vsprojects/vs2013/grpc.vcxproj
@@ -134,6 +134,10 @@
<ClInclude Include="..\..\src\core\iomgr\tcp_posix.h" />
<ClInclude Include="..\..\src\core\iomgr\tcp_server.h" />
<ClInclude Include="..\..\src\core\iomgr\time_averaged_stats.h" />
+ <ClInclude Include="..\..\src\core\json\json.h" />
+ <ClInclude Include="..\..\src\core\json\json_common.h" />
+ <ClInclude Include="..\..\src\core\json\json_reader.h" />
+ <ClInclude Include="..\..\src\core\json\json_writer.h" />
<ClInclude Include="..\..\src\core\statistics\census_interface.h" />
<ClInclude Include="..\..\src\core\statistics\census_log.h" />
<ClInclude Include="..\..\src\core\statistics\census_rpc_stats.h" />
@@ -278,7 +282,11 @@
</ClCompile>
<ClCompile Include="..\..\src\core\json\json.c">
</ClCompile>
- <ClCompile Include="..\..\src\core\json\json-string.c">
+ <ClCompile Include="..\..\src\core\json\json_reader.c">
+ </ClCompile>
+ <ClCompile Include="..\..\src\core\json\json_string.c">
+ </ClCompile>
+ <ClCompile Include="..\..\src\core\json\json_writer.c">
</ClCompile>
<ClCompile Include="..\..\src\core\statistics\census_init.c">
</ClCompile>
diff --git a/vsprojects/vs2013/grpc.vcxproj.filters b/vsprojects/vs2013/grpc.vcxproj.filters
index 4f03c14..6b7e63e 100644
--- a/vsprojects/vs2013/grpc.vcxproj.filters
+++ b/vsprojects/vs2013/grpc.vcxproj.filters
@@ -157,6 +157,18 @@
<ClCompile Include="..\..\src\core\iomgr\time_averaged_stats.c">
<Filter>src\core\iomgr</Filter>
</ClCompile>
+ <ClCompile Include="..\..\src\core\json\json.c">
+ <Filter>src\core\json</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\src\core\json\json_reader.c">
+ <Filter>src\core\json</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\src\core\json\json_string.c">
+ <Filter>src\core\json</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\src\core\json\json_writer.c">
+ <Filter>src\core\json</Filter>
+ </ClCompile>
<ClCompile Include="..\..\src\core\statistics\census_init.c">
<Filter>src\core\statistics</Filter>
</ClCompile>
@@ -280,9 +292,6 @@
<ClCompile Include="..\..\src\core\transport\transport.c">
<Filter>src\core\transport</Filter>
</ClCompile>
- <ClCompile Include="..\..\third_party\cJSON\cJSON.c">
- <Filter>third_party\cJSON</Filter>
- </ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\include\grpc\grpc_security.h">
@@ -464,6 +473,18 @@
<ClInclude Include="..\..\src\core\iomgr\time_averaged_stats.h">
<Filter>src\core\iomgr</Filter>
</ClInclude>
+ <ClInclude Include="..\..\src\core\json\json.h">
+ <Filter>src\core\json</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\src\core\json\json_common.h">
+ <Filter>src\core\json</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\src\core\json\json_reader.h">
+ <Filter>src\core\json</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\src\core\json\json_writer.h">
+ <Filter>src\core\json</Filter>
+ </ClInclude>
<ClInclude Include="..\..\src\core\statistics\census_interface.h">
<Filter>src\core\statistics</Filter>
</ClInclude>
@@ -599,6 +620,9 @@
<Filter Include="src\core\iomgr">
<UniqueIdentifier>{1baf3894-af37-e647-bdbc-95dc17ed0073}</UniqueIdentifier>
</Filter>
+ <Filter Include="src\core\json">
+ <UniqueIdentifier>{e665cc0e-b994-d7c5-cc18-2007392019f0}</UniqueIdentifier>
+ </Filter>
<Filter Include="src\core\security">
<UniqueIdentifier>{1d850ac6-e639-4eab-5338-4ba40272fcc9}</UniqueIdentifier>
</Filter>
@@ -617,12 +641,6 @@
<Filter Include="src\core\tsi">
<UniqueIdentifier>{0b0f9ab1-efa4-7f03-e446-6fb9b5227e84}</UniqueIdentifier>
</Filter>
- <Filter Include="third_party">
- <UniqueIdentifier>{aaab30a4-2a15-732e-c141-3fbc0f0f5a7a}</UniqueIdentifier>
- </Filter>
- <Filter Include="third_party\cJSON">
- <UniqueIdentifier>{332d0840-2c7a-bb09-8e58-585a6fb3959f}</UniqueIdentifier>
- </Filter>
</ItemGroup>
</Project>
diff --git a/vsprojects/vs2013/grpc_unsecure.vcxproj b/vsprojects/vs2013/grpc_unsecure.vcxproj
index 28ea603..d325121 100644
--- a/vsprojects/vs2013/grpc_unsecure.vcxproj
+++ b/vsprojects/vs2013/grpc_unsecure.vcxproj
@@ -134,6 +134,10 @@
<ClInclude Include="..\..\src\core\iomgr\tcp_posix.h" />
<ClInclude Include="..\..\src\core\iomgr\tcp_server.h" />
<ClInclude Include="..\..\src\core\iomgr\time_averaged_stats.h" />
+ <ClInclude Include="..\..\src\core\json\json.h" />
+ <ClInclude Include="..\..\src\core\json\json_common.h" />
+ <ClInclude Include="..\..\src\core\json\json_reader.h" />
+ <ClInclude Include="..\..\src\core\json\json_writer.h" />
<ClInclude Include="..\..\src\core\statistics\census_interface.h" />
<ClInclude Include="..\..\src\core\statistics\census_log.h" />
<ClInclude Include="..\..\src\core\statistics\census_rpc_stats.h" />
@@ -278,7 +282,11 @@
</ClCompile>
<ClCompile Include="..\..\src\core\json\json.c">
</ClCompile>
- <ClCompile Include="..\..\src\core\json\json-string.c">
+ <ClCompile Include="..\..\src\core\json\json_reader.c">
+ </ClCompile>
+ <ClCompile Include="..\..\src\core\json\json_string.c">
+ </ClCompile>
+ <ClCompile Include="..\..\src\core\json\json_writer.c">
</ClCompile>
<ClCompile Include="..\..\src\core\statistics\census_init.c">
</ClCompile>
diff --git a/vsprojects/vs2013/grpc_unsecure.vcxproj.filters b/vsprojects/vs2013/grpc_unsecure.vcxproj.filters
index a7ba173..b9f6525 100644
--- a/vsprojects/vs2013/grpc_unsecure.vcxproj.filters
+++ b/vsprojects/vs2013/grpc_unsecure.vcxproj.filters
@@ -118,6 +118,18 @@
<ClCompile Include="..\..\src\core\iomgr\time_averaged_stats.c">
<Filter>src\core\iomgr</Filter>
</ClCompile>
+ <ClCompile Include="..\..\src\core\json\json.c">
+ <Filter>src\core\json</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\src\core\json\json_reader.c">
+ <Filter>src\core\json</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\src\core\json\json_string.c">
+ <Filter>src\core\json</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\src\core\json\json_writer.c">
+ <Filter>src\core\json</Filter>
+ </ClCompile>
<ClCompile Include="..\..\src\core\statistics\census_init.c">
<Filter>src\core\statistics</Filter>
</ClCompile>
@@ -241,9 +253,6 @@
<ClCompile Include="..\..\src\core\transport\transport.c">
<Filter>src\core\transport</Filter>
</ClCompile>
- <ClCompile Include="..\..\third_party\cJSON\cJSON.c">
- <Filter>third_party\cJSON</Filter>
- </ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\include\grpc\byte_buffer.h">
@@ -389,6 +398,18 @@
<ClInclude Include="..\..\src\core\iomgr\time_averaged_stats.h">
<Filter>src\core\iomgr</Filter>
</ClInclude>
+ <ClInclude Include="..\..\src\core\json\json.h">
+ <Filter>src\core\json</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\src\core\json\json_common.h">
+ <Filter>src\core\json</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\src\core\json\json_reader.h">
+ <Filter>src\core\json</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\src\core\json\json_writer.h">
+ <Filter>src\core\json</Filter>
+ </ClInclude>
<ClInclude Include="..\..\src\core\statistics\census_interface.h">
<Filter>src\core\statistics</Filter>
</ClInclude>
@@ -524,6 +545,9 @@
<Filter Include="src\core\iomgr">
<UniqueIdentifier>{a9df8b24-ecea-ff6d-8999-d8fa54cd70bf}</UniqueIdentifier>
</Filter>
+ <Filter Include="src\core\json">
+ <UniqueIdentifier>{443ffc61-1bea-2477-6e54-1ddf8c139264}</UniqueIdentifier>
+ </Filter>
<Filter Include="src\core\statistics">
<UniqueIdentifier>{e084164c-a069-00e3-db35-4e0b1cd6f0b7}</UniqueIdentifier>
</Filter>
@@ -536,12 +560,6 @@
<Filter Include="src\core\transport\chttp2">
<UniqueIdentifier>{5fcd6206-f774-9ae6-4b85-305d6a723843}</UniqueIdentifier>
</Filter>
- <Filter Include="third_party">
- <UniqueIdentifier>{025c051e-8eba-125b-67f9-173f95176eb2}</UniqueIdentifier>
- </Filter>
- <Filter Include="third_party\cJSON">
- <UniqueIdentifier>{7d75397e-988a-baac-897e-2ea7b43d5dd9}</UniqueIdentifier>
- </Filter>
</ItemGroup>
</Project>