Merge pull request #21392 from markdroth/json_new_api_only

New JSON API
pull/21256/head
Mark D. Roth 5 years ago committed by GitHub
commit 3003fc0b21
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      BUILD
  2. 2
      BUILD.gn
  3. 49
      CMakeLists.txt
  4. 60
      Makefile
  5. 13
      build.yaml
  6. 2
      config.m4
  7. 2
      config.w32
  8. 2
      gRPC-Core.podspec
  9. 2
      grpc.gemspec
  10. 10
      grpc.gyp
  11. 2
      package.xml
  12. 213
      src/core/lib/json/json.h
  13. 808
      src/core/lib/json/json_reader_new.cc
  14. 336
      src/core/lib/json/json_writer_new.cc
  15. 2
      src/python/grpcio/grpc_core_dependencies.py
  16. 15
      test/core/json/BUILD
  17. 295
      test/core/json/json_test_new.cc
  18. 2
      tools/doxygen/Doxyfile.core.internal
  19. 24
      tools/run_tests/generated/tests.json

@ -806,7 +806,9 @@ grpc_cc_library(
"src/core/lib/iomgr/wakeup_fd_posix.cc", "src/core/lib/iomgr/wakeup_fd_posix.cc",
"src/core/lib/json/json.cc", "src/core/lib/json/json.cc",
"src/core/lib/json/json_reader.cc", "src/core/lib/json/json_reader.cc",
"src/core/lib/json/json_reader_new.cc",
"src/core/lib/json/json_writer.cc", "src/core/lib/json/json_writer.cc",
"src/core/lib/json/json_writer_new.cc",
"src/core/lib/slice/b64.cc", "src/core/lib/slice/b64.cc",
"src/core/lib/slice/percent_encoding.cc", "src/core/lib/slice/percent_encoding.cc",
"src/core/lib/slice/slice.cc", "src/core/lib/slice/slice.cc",

@ -718,7 +718,9 @@ config("grpc_config") {
"src/core/lib/json/json.cc", "src/core/lib/json/json.cc",
"src/core/lib/json/json.h", "src/core/lib/json/json.h",
"src/core/lib/json/json_reader.cc", "src/core/lib/json/json_reader.cc",
"src/core/lib/json/json_reader_new.cc",
"src/core/lib/json/json_writer.cc", "src/core/lib/json/json_writer.cc",
"src/core/lib/json/json_writer_new.cc",
"src/core/lib/security/context/security_context.cc", "src/core/lib/security/context/security_context.cc",
"src/core/lib/security/context/security_context.h", "src/core/lib/security/context/security_context.h",
"src/core/lib/security/credentials/alts/alts_credentials.cc", "src/core/lib/security/credentials/alts/alts_credentials.cc",

@ -826,6 +826,7 @@ if(gRPC_BUILD_TESTS)
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX) if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
add_dependencies(buildtests_cxx json_run_localhost) add_dependencies(buildtests_cxx json_run_localhost)
endif() endif()
add_dependencies(buildtests_cxx json_test_new)
add_dependencies(buildtests_cxx logical_thread_test) add_dependencies(buildtests_cxx logical_thread_test)
add_dependencies(buildtests_cxx message_allocator_end2end_test) add_dependencies(buildtests_cxx message_allocator_end2end_test)
add_dependencies(buildtests_cxx metrics_client) add_dependencies(buildtests_cxx metrics_client)
@ -1125,7 +1126,9 @@ add_library(alts_test_util
src/core/lib/iomgr/wakeup_fd_posix.cc src/core/lib/iomgr/wakeup_fd_posix.cc
src/core/lib/json/json.cc src/core/lib/json/json.cc
src/core/lib/json/json_reader.cc src/core/lib/json/json_reader.cc
src/core/lib/json/json_reader_new.cc
src/core/lib/json/json_writer.cc src/core/lib/json/json_writer.cc
src/core/lib/json/json_writer_new.cc
src/core/lib/slice/b64.cc src/core/lib/slice/b64.cc
src/core/lib/slice/percent_encoding.cc src/core/lib/slice/percent_encoding.cc
src/core/lib/slice/slice.cc src/core/lib/slice/slice.cc
@ -1613,7 +1616,9 @@ add_library(grpc
src/core/lib/iomgr/wakeup_fd_posix.cc src/core/lib/iomgr/wakeup_fd_posix.cc
src/core/lib/json/json.cc src/core/lib/json/json.cc
src/core/lib/json/json_reader.cc src/core/lib/json/json_reader.cc
src/core/lib/json/json_reader_new.cc
src/core/lib/json/json_writer.cc src/core/lib/json/json_writer.cc
src/core/lib/json/json_writer_new.cc
src/core/lib/slice/b64.cc src/core/lib/slice/b64.cc
src/core/lib/slice/percent_encoding.cc src/core/lib/slice/percent_encoding.cc
src/core/lib/slice/slice.cc src/core/lib/slice/slice.cc
@ -2097,7 +2102,9 @@ add_library(grpc_cronet
src/core/lib/iomgr/wakeup_fd_posix.cc src/core/lib/iomgr/wakeup_fd_posix.cc
src/core/lib/json/json.cc src/core/lib/json/json.cc
src/core/lib/json/json_reader.cc src/core/lib/json/json_reader.cc
src/core/lib/json/json_reader_new.cc
src/core/lib/json/json_writer.cc src/core/lib/json/json_writer.cc
src/core/lib/json/json_writer_new.cc
src/core/lib/slice/b64.cc src/core/lib/slice/b64.cc
src/core/lib/slice/percent_encoding.cc src/core/lib/slice/percent_encoding.cc
src/core/lib/slice/slice.cc src/core/lib/slice/slice.cc
@ -2526,7 +2533,9 @@ add_library(grpc_test_util
src/core/lib/iomgr/wakeup_fd_posix.cc src/core/lib/iomgr/wakeup_fd_posix.cc
src/core/lib/json/json.cc src/core/lib/json/json.cc
src/core/lib/json/json_reader.cc src/core/lib/json/json_reader.cc
src/core/lib/json/json_reader_new.cc
src/core/lib/json/json_writer.cc src/core/lib/json/json_writer.cc
src/core/lib/json/json_writer_new.cc
src/core/lib/slice/b64.cc src/core/lib/slice/b64.cc
src/core/lib/slice/percent_encoding.cc src/core/lib/slice/percent_encoding.cc
src/core/lib/slice/slice.cc src/core/lib/slice/slice.cc
@ -2869,7 +2878,9 @@ add_library(grpc_test_util_unsecure
src/core/lib/iomgr/wakeup_fd_posix.cc src/core/lib/iomgr/wakeup_fd_posix.cc
src/core/lib/json/json.cc src/core/lib/json/json.cc
src/core/lib/json/json_reader.cc src/core/lib/json/json_reader.cc
src/core/lib/json/json_reader_new.cc
src/core/lib/json/json_writer.cc src/core/lib/json/json_writer.cc
src/core/lib/json/json_writer_new.cc
src/core/lib/slice/b64.cc src/core/lib/slice/b64.cc
src/core/lib/slice/percent_encoding.cc src/core/lib/slice/percent_encoding.cc
src/core/lib/slice/slice.cc src/core/lib/slice/slice.cc
@ -3188,7 +3199,9 @@ add_library(grpc_unsecure
src/core/lib/iomgr/wakeup_fd_posix.cc src/core/lib/iomgr/wakeup_fd_posix.cc
src/core/lib/json/json.cc src/core/lib/json/json.cc
src/core/lib/json/json_reader.cc src/core/lib/json/json_reader.cc
src/core/lib/json/json_reader_new.cc
src/core/lib/json/json_writer.cc src/core/lib/json/json_writer.cc
src/core/lib/json/json_writer_new.cc
src/core/lib/slice/b64.cc src/core/lib/slice/b64.cc
src/core/lib/slice/percent_encoding.cc src/core/lib/slice/percent_encoding.cc
src/core/lib/slice/slice.cc src/core/lib/slice/slice.cc
@ -14004,6 +14017,42 @@ endif()
endif() endif()
if(gRPC_BUILD_TESTS) if(gRPC_BUILD_TESTS)
add_executable(json_test_new
test/core/json/json_test_new.cc
third_party/googletest/googletest/src/gtest-all.cc
third_party/googletest/googlemock/src/gmock-all.cc
)
target_include_directories(json_test_new
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/include
${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
${_gRPC_SSL_INCLUDE_DIR}
${_gRPC_UPB_GENERATED_DIR}
${_gRPC_UPB_GRPC_GENERATED_DIR}
${_gRPC_UPB_INCLUDE_DIR}
${_gRPC_ZLIB_INCLUDE_DIR}
third_party/googletest/googletest/include
third_party/googletest/googletest
third_party/googletest/googlemock/include
third_party/googletest/googlemock
${_gRPC_PROTO_GENS_DIR}
)
target_link_libraries(json_test_new
${_gRPC_PROTOBUF_LIBRARIES}
${_gRPC_ALLTARGETS_LIBRARIES}
grpc_test_util
grpc
gpr
${_gRPC_GFLAGS_LIBRARIES}
)
endif()
if(gRPC_BUILD_TESTS)
add_executable(logical_thread_test add_executable(logical_thread_test
test/core/iomgr/logical_thread_test.cc test/core/iomgr/logical_thread_test.cc
third_party/googletest/googletest/src/gtest-all.cc third_party/googletest/googletest/src/gtest-all.cc

@ -1256,6 +1256,7 @@ interop_client: $(BINDIR)/$(CONFIG)/interop_client
interop_server: $(BINDIR)/$(CONFIG)/interop_server interop_server: $(BINDIR)/$(CONFIG)/interop_server
interop_test: $(BINDIR)/$(CONFIG)/interop_test interop_test: $(BINDIR)/$(CONFIG)/interop_test
json_run_localhost: $(BINDIR)/$(CONFIG)/json_run_localhost json_run_localhost: $(BINDIR)/$(CONFIG)/json_run_localhost
json_test_new: $(BINDIR)/$(CONFIG)/json_test_new
logical_thread_test: $(BINDIR)/$(CONFIG)/logical_thread_test logical_thread_test: $(BINDIR)/$(CONFIG)/logical_thread_test
message_allocator_end2end_test: $(BINDIR)/$(CONFIG)/message_allocator_end2end_test message_allocator_end2end_test: $(BINDIR)/$(CONFIG)/message_allocator_end2end_test
metrics_client: $(BINDIR)/$(CONFIG)/metrics_client metrics_client: $(BINDIR)/$(CONFIG)/metrics_client
@ -1726,6 +1727,7 @@ buildtests_cxx: privatelibs_cxx \
$(BINDIR)/$(CONFIG)/interop_server \ $(BINDIR)/$(CONFIG)/interop_server \
$(BINDIR)/$(CONFIG)/interop_test \ $(BINDIR)/$(CONFIG)/interop_test \
$(BINDIR)/$(CONFIG)/json_run_localhost \ $(BINDIR)/$(CONFIG)/json_run_localhost \
$(BINDIR)/$(CONFIG)/json_test_new \
$(BINDIR)/$(CONFIG)/logical_thread_test \ $(BINDIR)/$(CONFIG)/logical_thread_test \
$(BINDIR)/$(CONFIG)/message_allocator_end2end_test \ $(BINDIR)/$(CONFIG)/message_allocator_end2end_test \
$(BINDIR)/$(CONFIG)/metrics_client \ $(BINDIR)/$(CONFIG)/metrics_client \
@ -1901,6 +1903,7 @@ buildtests_cxx: privatelibs_cxx \
$(BINDIR)/$(CONFIG)/interop_server \ $(BINDIR)/$(CONFIG)/interop_server \
$(BINDIR)/$(CONFIG)/interop_test \ $(BINDIR)/$(CONFIG)/interop_test \
$(BINDIR)/$(CONFIG)/json_run_localhost \ $(BINDIR)/$(CONFIG)/json_run_localhost \
$(BINDIR)/$(CONFIG)/json_test_new \
$(BINDIR)/$(CONFIG)/logical_thread_test \ $(BINDIR)/$(CONFIG)/logical_thread_test \
$(BINDIR)/$(CONFIG)/message_allocator_end2end_test \ $(BINDIR)/$(CONFIG)/message_allocator_end2end_test \
$(BINDIR)/$(CONFIG)/metrics_client \ $(BINDIR)/$(CONFIG)/metrics_client \
@ -2414,6 +2417,8 @@ test_cxx: buildtests_cxx
$(Q) $(BINDIR)/$(CONFIG)/inproc_sync_unary_ping_pong_test || ( echo test inproc_sync_unary_ping_pong_test failed ; exit 1 ) $(Q) $(BINDIR)/$(CONFIG)/inproc_sync_unary_ping_pong_test || ( echo test inproc_sync_unary_ping_pong_test failed ; exit 1 )
$(E) "[RUN] Testing interop_test" $(E) "[RUN] Testing interop_test"
$(Q) $(BINDIR)/$(CONFIG)/interop_test || ( echo test interop_test failed ; exit 1 ) $(Q) $(BINDIR)/$(CONFIG)/interop_test || ( echo test interop_test failed ; exit 1 )
$(E) "[RUN] Testing json_test_new"
$(Q) $(BINDIR)/$(CONFIG)/json_test_new || ( echo test json_test_new failed ; exit 1 )
$(E) "[RUN] Testing logical_thread_test" $(E) "[RUN] Testing logical_thread_test"
$(Q) $(BINDIR)/$(CONFIG)/logical_thread_test || ( echo test logical_thread_test failed ; exit 1 ) $(Q) $(BINDIR)/$(CONFIG)/logical_thread_test || ( echo test logical_thread_test failed ; exit 1 )
$(E) "[RUN] Testing message_allocator_end2end_test" $(E) "[RUN] Testing message_allocator_end2end_test"
@ -3635,7 +3640,9 @@ LIBALTS_TEST_UTIL_SRC = \
src/core/lib/iomgr/wakeup_fd_posix.cc \ src/core/lib/iomgr/wakeup_fd_posix.cc \
src/core/lib/json/json.cc \ src/core/lib/json/json.cc \
src/core/lib/json/json_reader.cc \ src/core/lib/json/json_reader.cc \
src/core/lib/json/json_reader_new.cc \
src/core/lib/json/json_writer.cc \ src/core/lib/json/json_writer.cc \
src/core/lib/json/json_writer_new.cc \
src/core/lib/slice/b64.cc \ src/core/lib/slice/b64.cc \
src/core/lib/slice/percent_encoding.cc \ src/core/lib/slice/percent_encoding.cc \
src/core/lib/slice/slice.cc \ src/core/lib/slice/slice.cc \
@ -4091,7 +4098,9 @@ LIBGRPC_SRC = \
src/core/lib/iomgr/wakeup_fd_posix.cc \ src/core/lib/iomgr/wakeup_fd_posix.cc \
src/core/lib/json/json.cc \ src/core/lib/json/json.cc \
src/core/lib/json/json_reader.cc \ src/core/lib/json/json_reader.cc \
src/core/lib/json/json_reader_new.cc \
src/core/lib/json/json_writer.cc \ src/core/lib/json/json_writer.cc \
src/core/lib/json/json_writer_new.cc \
src/core/lib/slice/b64.cc \ src/core/lib/slice/b64.cc \
src/core/lib/slice/percent_encoding.cc \ src/core/lib/slice/percent_encoding.cc \
src/core/lib/slice/slice.cc \ src/core/lib/slice/slice.cc \
@ -4567,7 +4576,9 @@ LIBGRPC_CRONET_SRC = \
src/core/lib/iomgr/wakeup_fd_posix.cc \ src/core/lib/iomgr/wakeup_fd_posix.cc \
src/core/lib/json/json.cc \ src/core/lib/json/json.cc \
src/core/lib/json/json_reader.cc \ src/core/lib/json/json_reader.cc \
src/core/lib/json/json_reader_new.cc \
src/core/lib/json/json_writer.cc \ src/core/lib/json/json_writer.cc \
src/core/lib/json/json_writer_new.cc \
src/core/lib/slice/b64.cc \ src/core/lib/slice/b64.cc \
src/core/lib/slice/percent_encoding.cc \ src/core/lib/slice/percent_encoding.cc \
src/core/lib/slice/slice.cc \ src/core/lib/slice/slice.cc \
@ -4987,7 +4998,9 @@ LIBGRPC_TEST_UTIL_SRC = \
src/core/lib/iomgr/wakeup_fd_posix.cc \ src/core/lib/iomgr/wakeup_fd_posix.cc \
src/core/lib/json/json.cc \ src/core/lib/json/json.cc \
src/core/lib/json/json_reader.cc \ src/core/lib/json/json_reader.cc \
src/core/lib/json/json_reader_new.cc \
src/core/lib/json/json_writer.cc \ src/core/lib/json/json_writer.cc \
src/core/lib/json/json_writer_new.cc \
src/core/lib/slice/b64.cc \ src/core/lib/slice/b64.cc \
src/core/lib/slice/percent_encoding.cc \ src/core/lib/slice/percent_encoding.cc \
src/core/lib/slice/slice.cc \ src/core/lib/slice/slice.cc \
@ -5316,7 +5329,9 @@ LIBGRPC_TEST_UTIL_UNSECURE_SRC = \
src/core/lib/iomgr/wakeup_fd_posix.cc \ src/core/lib/iomgr/wakeup_fd_posix.cc \
src/core/lib/json/json.cc \ src/core/lib/json/json.cc \
src/core/lib/json/json_reader.cc \ src/core/lib/json/json_reader.cc \
src/core/lib/json/json_reader_new.cc \
src/core/lib/json/json_writer.cc \ src/core/lib/json/json_writer.cc \
src/core/lib/json/json_writer_new.cc \
src/core/lib/slice/b64.cc \ src/core/lib/slice/b64.cc \
src/core/lib/slice/percent_encoding.cc \ src/core/lib/slice/percent_encoding.cc \
src/core/lib/slice/slice.cc \ src/core/lib/slice/slice.cc \
@ -5608,7 +5623,9 @@ LIBGRPC_UNSECURE_SRC = \
src/core/lib/iomgr/wakeup_fd_posix.cc \ src/core/lib/iomgr/wakeup_fd_posix.cc \
src/core/lib/json/json.cc \ src/core/lib/json/json.cc \
src/core/lib/json/json_reader.cc \ src/core/lib/json/json_reader.cc \
src/core/lib/json/json_reader_new.cc \
src/core/lib/json/json_writer.cc \ src/core/lib/json/json_writer.cc \
src/core/lib/json/json_writer_new.cc \
src/core/lib/slice/b64.cc \ src/core/lib/slice/b64.cc \
src/core/lib/slice/percent_encoding.cc \ src/core/lib/slice/percent_encoding.cc \
src/core/lib/slice/slice.cc \ src/core/lib/slice/slice.cc \
@ -18350,6 +18367,49 @@ endif
endif endif
JSON_TEST_NEW_SRC = \
test/core/json/json_test_new.cc \
JSON_TEST_NEW_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(JSON_TEST_NEW_SRC))))
ifeq ($(NO_SECURE),true)
# You can't build secure targets if you don't have OpenSSL.
$(BINDIR)/$(CONFIG)/json_test_new: openssl_dep_error
else
ifeq ($(NO_PROTOBUF),true)
# You can't build the protoc plugins or protobuf-enabled targets if you don't have protobuf 3.5.0+.
$(BINDIR)/$(CONFIG)/json_test_new: protobuf_dep_error
else
$(BINDIR)/$(CONFIG)/json_test_new: $(PROTOBUF_DEP) $(JSON_TEST_NEW_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a
$(E) "[LD] Linking $@"
$(Q) mkdir -p `dirname $@`
$(Q) $(LDXX) $(LDFLAGS) $(JSON_TEST_NEW_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/json_test_new
endif
endif
$(OBJDIR)/$(CONFIG)/test/core/json/json_test_new.o: $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a
deps_json_test_new: $(JSON_TEST_NEW_OBJS:.o=.dep)
ifneq ($(NO_SECURE),true)
ifneq ($(NO_DEPS),true)
-include $(JSON_TEST_NEW_OBJS:.o=.dep)
endif
endif
LOGICAL_THREAD_TEST_SRC = \ LOGICAL_THREAD_TEST_SRC = \
test/core/iomgr/logical_thread_test.cc \ test/core/iomgr/logical_thread_test.cc \

@ -772,7 +772,9 @@ filegroups:
- src/core/lib/iomgr/wakeup_fd_posix.cc - src/core/lib/iomgr/wakeup_fd_posix.cc
- src/core/lib/json/json.cc - src/core/lib/json/json.cc
- src/core/lib/json/json_reader.cc - src/core/lib/json/json_reader.cc
- src/core/lib/json/json_reader_new.cc
- src/core/lib/json/json_writer.cc - src/core/lib/json/json_writer.cc
- src/core/lib/json/json_writer_new.cc
- src/core/lib/slice/b64.cc - src/core/lib/slice/b64.cc
- src/core/lib/slice/percent_encoding.cc - src/core/lib/slice/percent_encoding.cc
- src/core/lib/slice/slice.cc - src/core/lib/slice/slice.cc
@ -5393,6 +5395,17 @@ targets:
- mac - mac
- linux - linux
- posix - posix
- name: json_test_new
gtest: true
build: test
language: c++
src:
- test/core/json/json_test_new.cc
deps:
- grpc_test_util
- grpc
- gpr
uses_polling: false
- name: logical_thread_test - name: logical_thread_test
cpu_cost: 10 cpu_cost: 10
build: test build: test

@ -348,7 +348,9 @@ if test "$PHP_GRPC" != "no"; then
src/core/lib/iomgr/wakeup_fd_posix.cc \ src/core/lib/iomgr/wakeup_fd_posix.cc \
src/core/lib/json/json.cc \ src/core/lib/json/json.cc \
src/core/lib/json/json_reader.cc \ src/core/lib/json/json_reader.cc \
src/core/lib/json/json_reader_new.cc \
src/core/lib/json/json_writer.cc \ src/core/lib/json/json_writer.cc \
src/core/lib/json/json_writer_new.cc \
src/core/lib/profiling/basic_timers.cc \ src/core/lib/profiling/basic_timers.cc \
src/core/lib/profiling/stap_timers.cc \ src/core/lib/profiling/stap_timers.cc \
src/core/lib/security/context/security_context.cc \ src/core/lib/security/context/security_context.cc \

@ -317,7 +317,9 @@ if (PHP_GRPC != "no") {
"src\\core\\lib\\iomgr\\wakeup_fd_posix.cc " + "src\\core\\lib\\iomgr\\wakeup_fd_posix.cc " +
"src\\core\\lib\\json\\json.cc " + "src\\core\\lib\\json\\json.cc " +
"src\\core\\lib\\json\\json_reader.cc " + "src\\core\\lib\\json\\json_reader.cc " +
"src\\core\\lib\\json\\json_reader_new.cc " +
"src\\core\\lib\\json\\json_writer.cc " + "src\\core\\lib\\json\\json_writer.cc " +
"src\\core\\lib\\json\\json_writer_new.cc " +
"src\\core\\lib\\profiling\\basic_timers.cc " + "src\\core\\lib\\profiling\\basic_timers.cc " +
"src\\core\\lib\\profiling\\stap_timers.cc " + "src\\core\\lib\\profiling\\stap_timers.cc " +
"src\\core\\lib\\security\\context\\security_context.cc " + "src\\core\\lib\\security\\context\\security_context.cc " +

@ -753,7 +753,9 @@ Pod::Spec.new do |s|
'src/core/lib/json/json.cc', 'src/core/lib/json/json.cc',
'src/core/lib/json/json.h', 'src/core/lib/json/json.h',
'src/core/lib/json/json_reader.cc', 'src/core/lib/json/json_reader.cc',
'src/core/lib/json/json_reader_new.cc',
'src/core/lib/json/json_writer.cc', 'src/core/lib/json/json_writer.cc',
'src/core/lib/json/json_writer_new.cc',
'src/core/lib/profiling/basic_timers.cc', 'src/core/lib/profiling/basic_timers.cc',
'src/core/lib/profiling/stap_timers.cc', 'src/core/lib/profiling/stap_timers.cc',
'src/core/lib/profiling/timers.h', 'src/core/lib/profiling/timers.h',

@ -676,7 +676,9 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/json/json.cc ) s.files += %w( src/core/lib/json/json.cc )
s.files += %w( src/core/lib/json/json.h ) s.files += %w( src/core/lib/json/json.h )
s.files += %w( src/core/lib/json/json_reader.cc ) s.files += %w( src/core/lib/json/json_reader.cc )
s.files += %w( src/core/lib/json/json_reader_new.cc )
s.files += %w( src/core/lib/json/json_writer.cc ) s.files += %w( src/core/lib/json/json_writer.cc )
s.files += %w( src/core/lib/json/json_writer_new.cc )
s.files += %w( src/core/lib/profiling/basic_timers.cc ) s.files += %w( src/core/lib/profiling/basic_timers.cc )
s.files += %w( src/core/lib/profiling/stap_timers.cc ) s.files += %w( src/core/lib/profiling/stap_timers.cc )
s.files += %w( src/core/lib/profiling/timers.h ) s.files += %w( src/core/lib/profiling/timers.h )

@ -319,7 +319,9 @@
'src/core/lib/iomgr/wakeup_fd_posix.cc', 'src/core/lib/iomgr/wakeup_fd_posix.cc',
'src/core/lib/json/json.cc', 'src/core/lib/json/json.cc',
'src/core/lib/json/json_reader.cc', 'src/core/lib/json/json_reader.cc',
'src/core/lib/json/json_reader_new.cc',
'src/core/lib/json/json_writer.cc', 'src/core/lib/json/json_writer.cc',
'src/core/lib/json/json_writer_new.cc',
'src/core/lib/slice/b64.cc', 'src/core/lib/slice/b64.cc',
'src/core/lib/slice/percent_encoding.cc', 'src/core/lib/slice/percent_encoding.cc',
'src/core/lib/slice/slice.cc', 'src/core/lib/slice/slice.cc',
@ -617,7 +619,9 @@
'src/core/lib/iomgr/wakeup_fd_posix.cc', 'src/core/lib/iomgr/wakeup_fd_posix.cc',
'src/core/lib/json/json.cc', 'src/core/lib/json/json.cc',
'src/core/lib/json/json_reader.cc', 'src/core/lib/json/json_reader.cc',
'src/core/lib/json/json_reader_new.cc',
'src/core/lib/json/json_writer.cc', 'src/core/lib/json/json_writer.cc',
'src/core/lib/json/json_writer_new.cc',
'src/core/lib/slice/b64.cc', 'src/core/lib/slice/b64.cc',
'src/core/lib/slice/percent_encoding.cc', 'src/core/lib/slice/percent_encoding.cc',
'src/core/lib/slice/slice.cc', 'src/core/lib/slice/slice.cc',
@ -1040,7 +1044,9 @@
'src/core/lib/iomgr/wakeup_fd_posix.cc', 'src/core/lib/iomgr/wakeup_fd_posix.cc',
'src/core/lib/json/json.cc', 'src/core/lib/json/json.cc',
'src/core/lib/json/json_reader.cc', 'src/core/lib/json/json_reader.cc',
'src/core/lib/json/json_reader_new.cc',
'src/core/lib/json/json_writer.cc', 'src/core/lib/json/json_writer.cc',
'src/core/lib/json/json_writer_new.cc',
'src/core/lib/slice/b64.cc', 'src/core/lib/slice/b64.cc',
'src/core/lib/slice/percent_encoding.cc', 'src/core/lib/slice/percent_encoding.cc',
'src/core/lib/slice/slice.cc', 'src/core/lib/slice/slice.cc',
@ -1303,7 +1309,9 @@
'src/core/lib/iomgr/wakeup_fd_posix.cc', 'src/core/lib/iomgr/wakeup_fd_posix.cc',
'src/core/lib/json/json.cc', 'src/core/lib/json/json.cc',
'src/core/lib/json/json_reader.cc', 'src/core/lib/json/json_reader.cc',
'src/core/lib/json/json_reader_new.cc',
'src/core/lib/json/json_writer.cc', 'src/core/lib/json/json_writer.cc',
'src/core/lib/json/json_writer_new.cc',
'src/core/lib/slice/b64.cc', 'src/core/lib/slice/b64.cc',
'src/core/lib/slice/percent_encoding.cc', 'src/core/lib/slice/percent_encoding.cc',
'src/core/lib/slice/slice.cc', 'src/core/lib/slice/slice.cc',
@ -1542,7 +1550,9 @@
'src/core/lib/iomgr/wakeup_fd_posix.cc', 'src/core/lib/iomgr/wakeup_fd_posix.cc',
'src/core/lib/json/json.cc', 'src/core/lib/json/json.cc',
'src/core/lib/json/json_reader.cc', 'src/core/lib/json/json_reader.cc',
'src/core/lib/json/json_reader_new.cc',
'src/core/lib/json/json_writer.cc', 'src/core/lib/json/json_writer.cc',
'src/core/lib/json/json_writer_new.cc',
'src/core/lib/slice/b64.cc', 'src/core/lib/slice/b64.cc',
'src/core/lib/slice/percent_encoding.cc', 'src/core/lib/slice/percent_encoding.cc',
'src/core/lib/slice/slice.cc', 'src/core/lib/slice/slice.cc',

@ -659,7 +659,9 @@
<file baseinstalldir="/" name="src/core/lib/json/json.cc" role="src" /> <file baseinstalldir="/" name="src/core/lib/json/json.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/json/json.h" role="src" /> <file baseinstalldir="/" name="src/core/lib/json/json.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/json/json_reader.cc" role="src" /> <file baseinstalldir="/" name="src/core/lib/json/json_reader.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/json/json_reader_new.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/json/json_writer.cc" role="src" /> <file baseinstalldir="/" name="src/core/lib/json/json_writer.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/json/json_writer_new.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/profiling/basic_timers.cc" role="src" /> <file baseinstalldir="/" name="src/core/lib/profiling/basic_timers.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/profiling/stap_timers.cc" role="src" /> <file baseinstalldir="/" name="src/core/lib/profiling/stap_timers.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/profiling/timers.h" role="src" /> <file baseinstalldir="/" name="src/core/lib/profiling/timers.h" role="src" />

@ -21,9 +21,220 @@
#include <grpc/support/port_platform.h> #include <grpc/support/port_platform.h>
#include <stdbool.h>
#include <stdlib.h> #include <stdlib.h>
#include <map>
#include <string>
#include <vector>
#include "src/core/lib/gprpp/string_view.h"
#include "src/core/lib/iomgr/error.h"
namespace grpc_core {
// A JSON value, which can be any one of object, array, string,
// number, true, false, or null.
class Json {
public:
// TODO(roth): Currently, numbers are stored internally as strings,
// which makes the API a bit cumbersome to use. When we have time,
// consider whether there's a better alternative (e.g., maybe storing
// each numeric type as the native C++ type and automatically converting
// to string as needed).
enum class Type {
JSON_NULL,
JSON_TRUE,
JSON_FALSE,
NUMBER,
STRING,
OBJECT,
ARRAY
};
using Object = std::map<std::string, Json>;
using Array = std::vector<Json>;
// Parses JSON string from json_str. On error, sets *error.
static Json Parse(StringView json_str, grpc_error** error);
Json() = default;
// Copyable.
Json(const Json& other) { CopyFrom(other); }
Json& operator=(const Json& other) {
CopyFrom(other);
return *this;
}
// Moveable.
Json(Json&& other) { MoveFrom(std::move(other)); }
Json& operator=(Json&& other) {
MoveFrom(std::move(other));
return *this;
}
// Construct from copying a string.
// If is_number is true, the type will be NUMBER instead of STRING.
Json(const std::string& string, bool is_number = false)
: type_(is_number ? Type::NUMBER : Type::STRING), string_value_(string) {}
Json& operator=(const std::string& string) {
type_ = Type::STRING;
string_value_ = string;
return *this;
}
// Same thing for C-style strings, both const and mutable.
Json(const char* string, bool is_number = false)
: Json(std::string(string), is_number) {}
Json& operator=(const char* string) {
*this = std::string(string);
return *this;
}
Json(char* string, bool is_number = false)
: Json(std::string(string), is_number) {}
Json& operator=(char* string) {
*this = std::string(string);
return *this;
}
// Construct by moving a string.
Json(std::string&& string)
: type_(Type::STRING), string_value_(std::move(string)) {}
Json& operator=(std::string&& string) {
type_ = Type::STRING;
string_value_ = std::move(string);
return *this;
}
// Construct from bool.
Json(bool b) : type_(b ? Type::JSON_TRUE : Type::JSON_FALSE) {}
Json& operator=(bool b) {
type_ = b ? Type::JSON_TRUE : Type::JSON_FALSE;
return *this;
}
// Construct from any numeric type.
template <typename NumericType>
Json(NumericType number)
: type_(Type::NUMBER), string_value_(std::to_string(number)) {}
template <typename NumericType>
Json& operator=(NumericType number) {
type_ = Type::NUMBER;
string_value_ = std::to_string(number);
return *this;
}
// Construct by copying object.
Json(const Object& object) : type_(Type::OBJECT), object_value_(object) {}
Json& operator=(const Object& object) {
type_ = Type::OBJECT;
object_value_ = object;
return *this;
}
// Construct by moving object.
Json(Object&& object)
: type_(Type::OBJECT), object_value_(std::move(object)) {}
Json& operator=(Object&& object) {
type_ = Type::OBJECT;
object_value_ = std::move(object);
return *this;
}
// Construct by copying array.
Json(const Array& array) : type_(Type::ARRAY), array_value_(array) {}
Json& operator=(const Array& array) {
type_ = Type::ARRAY;
array_value_ = array;
return *this;
}
// Construct by moving array.
Json(Array&& array) : type_(Type::ARRAY), array_value_(std::move(array)) {}
Json& operator=(Array&& array) {
type_ = Type::ARRAY;
array_value_ = std::move(array);
return *this;
}
// Dumps JSON from value to string form.
std::string Dump(int indent = 0) const;
// Accessor methods.
Type type() const { return type_; }
const std::string& string_value() const { return string_value_; }
const Object& object_value() const { return object_value_; }
Object* mutable_object() { return &object_value_; }
const Array& array_value() const { return array_value_; }
Array* mutable_array() { return &array_value_; }
bool operator==(const Json& other) const {
if (type_ != other.type_) return false;
switch (type_) {
case Type::NUMBER:
case Type::STRING:
if (string_value_ != other.string_value_) return false;
break;
case Type::OBJECT:
if (object_value_ != other.object_value_) return false;
break;
case Type::ARRAY:
if (array_value_ != other.array_value_) return false;
break;
default:
break;
}
return true;
}
bool operator!=(const Json& other) const { return !(*this == other); }
private:
void CopyFrom(const Json& other) {
type_ = other.type_;
switch (type_) {
case Type::NUMBER:
case Type::STRING:
string_value_ = other.string_value_;
break;
case Type::OBJECT:
object_value_ = other.object_value_;
break;
case Type::ARRAY:
array_value_ = other.array_value_;
break;
default:
break;
}
}
void MoveFrom(Json&& other) {
type_ = other.type_;
other.type_ = Type::JSON_NULL;
switch (type_) {
case Type::NUMBER:
case Type::STRING:
string_value_ = std::move(other.string_value_);
break;
case Type::OBJECT:
object_value_ = std::move(other.object_value_);
break;
case Type::ARRAY:
array_value_ = std::move(other.array_value_);
break;
default:
break;
}
}
Type type_ = Type::JSON_NULL;
std::string string_value_;
Object object_value_;
Array array_value_;
};
} // namespace grpc_core
/* The various json types. */ /* The various json types. */
typedef enum { typedef enum {
GRPC_JSON_OBJECT, GRPC_JSON_OBJECT,

@ -0,0 +1,808 @@
/*
*
* Copyright 2015-2016 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#include <grpc/support/port_platform.h>
#include <string.h>
#include <grpc/support/log.h>
#include "src/core/lib/json/json.h"
namespace grpc_core {
namespace {
class JsonReader {
public:
enum class Status {
GRPC_JSON_DONE, /* The parser finished successfully. */
GRPC_JSON_PARSE_ERROR, /* The parser found an error in the json stream. */
GRPC_JSON_INTERNAL_ERROR /* The parser got an internal error. */
};
static Status Parse(StringView input, Json* output);
private:
enum class State {
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
};
/* 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.
*/
static constexpr uint32_t GRPC_JSON_READ_CHAR_EOF = 0x7ffffff0;
explicit JsonReader(StringView input)
: input_(reinterpret_cast<const uint8_t*>(input.data())),
remaining_input_(input.size()) {}
Status Run();
uint32_t ReadChar();
bool IsComplete();
void StringAddChar(uint32_t c);
void StringAddUtf32(uint32_t c);
Json* CreateAndLinkValue();
void StartContainer(Json::Type type);
void EndContainer();
void SetKey();
void SetString();
bool SetNumber();
void SetTrue();
void SetFalse();
void SetNull();
const uint8_t* input_;
size_t remaining_input_;
State state_ = State::GRPC_JSON_STATE_VALUE_BEGIN;
bool escaped_string_was_key_ = false;
bool container_just_begun_ = false;
uint16_t unicode_char_ = 0;
uint16_t unicode_high_surrogate_ = 0;
bool duplicate_key_found_ = false;
Json root_value_;
std::vector<Json*> stack_;
std::string key_;
std::string string_;
};
void JsonReader::StringAddChar(uint32_t c) {
string_.push_back(static_cast<uint8_t>(c));
}
void JsonReader::StringAddUtf32(uint32_t c) {
if (c <= 0x7f) {
StringAddChar(c);
} else if (c <= 0x7ff) {
uint32_t b1 = 0xc0 | ((c >> 6) & 0x1f);
uint32_t b2 = 0x80 | (c & 0x3f);
StringAddChar(b1);
StringAddChar(b2);
} else if (c <= 0xffff) {
uint32_t b1 = 0xe0 | ((c >> 12) & 0x0f);
uint32_t b2 = 0x80 | ((c >> 6) & 0x3f);
uint32_t b3 = 0x80 | (c & 0x3f);
StringAddChar(b1);
StringAddChar(b2);
StringAddChar(b3);
} else if (c <= 0x1fffff) {
uint32_t b1 = 0xf0 | ((c >> 18) & 0x07);
uint32_t b2 = 0x80 | ((c >> 12) & 0x3f);
uint32_t b3 = 0x80 | ((c >> 6) & 0x3f);
uint32_t b4 = 0x80 | (c & 0x3f);
StringAddChar(b1);
StringAddChar(b2);
StringAddChar(b3);
StringAddChar(b4);
}
}
uint32_t JsonReader::ReadChar() {
if (remaining_input_ == 0) return GRPC_JSON_READ_CHAR_EOF;
const uint32_t r = *input_++;
--remaining_input_;
if (r == 0) {
remaining_input_ = 0;
return GRPC_JSON_READ_CHAR_EOF;
}
return r;
}
Json* JsonReader::CreateAndLinkValue() {
Json* value;
if (stack_.empty()) {
value = &root_value_;
} else {
Json* parent = stack_.back();
if (parent->type() == Json::Type::OBJECT) {
if (parent->object_value().find(key_) != parent->object_value().end()) {
duplicate_key_found_ = true;
}
value = &(*parent->mutable_object())[std::move(key_)];
} else {
GPR_ASSERT(parent->type() == Json::Type::ARRAY);
parent->mutable_array()->emplace_back();
value = &parent->mutable_array()->back();
}
}
return value;
}
void JsonReader::StartContainer(Json::Type type) {
Json* value = CreateAndLinkValue();
if (type == Json::Type::OBJECT) {
*value = Json::Object();
} else {
GPR_ASSERT(type == Json::Type::ARRAY);
*value = Json::Array();
}
stack_.push_back(value);
}
void JsonReader::EndContainer() {
GPR_ASSERT(!stack_.empty());
stack_.pop_back();
}
void JsonReader::SetKey() {
key_ = std::move(string_);
string_.clear();
}
void JsonReader::SetString() {
Json* value = CreateAndLinkValue();
*value = std::move(string_);
string_.clear();
}
bool JsonReader::SetNumber() {
Json* value = CreateAndLinkValue();
*value = Json(std::move(string_), /*is_number=*/true);
string_.clear();
return true;
}
void JsonReader::SetTrue() {
Json* value = CreateAndLinkValue();
*value = true;
string_.clear();
}
void JsonReader::SetFalse() {
Json* value = CreateAndLinkValue();
*value = false;
string_.clear();
}
void JsonReader::SetNull() { CreateAndLinkValue(); }
bool JsonReader::IsComplete() {
return (stack_.empty() && (state_ == State::GRPC_JSON_STATE_END ||
state_ == State::GRPC_JSON_STATE_VALUE_END));
}
/* 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_PARSE_ERROR if the input was somehow invalid.
* . GRPC_JSON_INTERNAL_ERROR if the parser somehow ended into an invalid
* internal state.
*/
JsonReader::Status JsonReader::Run() {
uint32_t c;
/* This state-machine is a strict implementation of ECMA-404 */
while (true) {
c = ReadChar();
switch (c) {
/* Let's process the error case first. */
case GRPC_JSON_READ_CHAR_EOF:
if (IsComplete()) {
return Status::GRPC_JSON_DONE;
} else {
return Status::GRPC_JSON_PARSE_ERROR;
}
break;
/* Processing whitespaces. */
case ' ':
case '\t':
case '\n':
case '\r':
switch (state_) {
case State::GRPC_JSON_STATE_OBJECT_KEY_BEGIN:
case State::GRPC_JSON_STATE_OBJECT_KEY_END:
case State::GRPC_JSON_STATE_VALUE_BEGIN:
case State::GRPC_JSON_STATE_VALUE_END:
case State::GRPC_JSON_STATE_END:
break;
case State::GRPC_JSON_STATE_OBJECT_KEY_STRING:
case State::GRPC_JSON_STATE_VALUE_STRING:
if (c != ' ') return Status::GRPC_JSON_PARSE_ERROR;
if (unicode_high_surrogate_ != 0) {
return Status::GRPC_JSON_PARSE_ERROR;
}
StringAddChar(c);
break;
case State::GRPC_JSON_STATE_VALUE_NUMBER:
case State::GRPC_JSON_STATE_VALUE_NUMBER_WITH_DECIMAL:
case State::GRPC_JSON_STATE_VALUE_NUMBER_ZERO:
case State::GRPC_JSON_STATE_VALUE_NUMBER_EPM:
if (!SetNumber()) return Status::GRPC_JSON_PARSE_ERROR;
state_ = State::GRPC_JSON_STATE_VALUE_END;
break;
default:
return Status::GRPC_JSON_PARSE_ERROR;
}
break;
/* Value, object or array terminations. */
case ',':
case '}':
case ']':
switch (state_) {
case State::GRPC_JSON_STATE_OBJECT_KEY_STRING:
case State::GRPC_JSON_STATE_VALUE_STRING:
if (unicode_high_surrogate_ != 0) {
return Status::GRPC_JSON_PARSE_ERROR;
}
StringAddChar(c);
break;
case State::GRPC_JSON_STATE_VALUE_NUMBER:
case State::GRPC_JSON_STATE_VALUE_NUMBER_WITH_DECIMAL:
case State::GRPC_JSON_STATE_VALUE_NUMBER_ZERO:
case State::GRPC_JSON_STATE_VALUE_NUMBER_EPM:
if (stack_.empty()) {
return Status::GRPC_JSON_PARSE_ERROR;
} else if (c == '}' &&
stack_.back()->type() != Json::Type::OBJECT) {
return Status::GRPC_JSON_PARSE_ERROR;
return Status::GRPC_JSON_PARSE_ERROR;
} else if (c == ']' && stack_.back()->type() != Json::Type::ARRAY) {
return Status::GRPC_JSON_PARSE_ERROR;
}
if (!SetNumber()) return Status::GRPC_JSON_PARSE_ERROR;
state_ = State::GRPC_JSON_STATE_VALUE_END;
/* The missing break here is intentional. */
/* fallthrough */
case State::GRPC_JSON_STATE_VALUE_END:
case State::GRPC_JSON_STATE_OBJECT_KEY_BEGIN:
case State::GRPC_JSON_STATE_VALUE_BEGIN:
if (c == ',') {
if (state_ != State::GRPC_JSON_STATE_VALUE_END) {
return Status::GRPC_JSON_PARSE_ERROR;
}
if (!stack_.empty() &&
stack_.back()->type() == Json::Type::OBJECT) {
state_ = State::GRPC_JSON_STATE_OBJECT_KEY_BEGIN;
} else if (!stack_.empty() &&
stack_.back()->type() == Json::Type::ARRAY) {
state_ = State::GRPC_JSON_STATE_VALUE_BEGIN;
} else {
return Status::GRPC_JSON_PARSE_ERROR;
}
} else {
if (stack_.empty()) {
return Status::GRPC_JSON_PARSE_ERROR;
}
if (c == '}' && stack_.back()->type() != Json::Type::OBJECT) {
return Status::GRPC_JSON_PARSE_ERROR;
}
if (c == '}' &&
state_ == State::GRPC_JSON_STATE_OBJECT_KEY_BEGIN &&
!container_just_begun_) {
return Status::GRPC_JSON_PARSE_ERROR;
}
if (c == ']' && stack_.back()->type() != Json::Type::ARRAY) {
return Status::GRPC_JSON_PARSE_ERROR;
}
if (c == ']' && state_ == State::GRPC_JSON_STATE_VALUE_BEGIN &&
!container_just_begun_) {
return Status::GRPC_JSON_PARSE_ERROR;
}
state_ = State::GRPC_JSON_STATE_VALUE_END;
EndContainer();
if (stack_.empty()) {
state_ = State::GRPC_JSON_STATE_END;
}
}
break;
default:
return Status::GRPC_JSON_PARSE_ERROR;
}
break;
/* In-string escaping. */
case '\\':
switch (state_) {
case State::GRPC_JSON_STATE_OBJECT_KEY_STRING:
escaped_string_was_key_ = true;
state_ = State::GRPC_JSON_STATE_STRING_ESCAPE;
break;
case State::GRPC_JSON_STATE_VALUE_STRING:
escaped_string_was_key_ = false;
state_ = State::GRPC_JSON_STATE_STRING_ESCAPE;
break;
/* This is the \\ case. */
case State::GRPC_JSON_STATE_STRING_ESCAPE:
if (unicode_high_surrogate_ != 0)
return Status::GRPC_JSON_PARSE_ERROR;
StringAddChar('\\');
if (escaped_string_was_key_) {
state_ = State::GRPC_JSON_STATE_OBJECT_KEY_STRING;
} else {
state_ = State::GRPC_JSON_STATE_VALUE_STRING;
}
break;
default:
return Status::GRPC_JSON_PARSE_ERROR;
}
break;
default:
container_just_begun_ = false;
switch (state_) {
case State::GRPC_JSON_STATE_OBJECT_KEY_BEGIN:
if (c != '"') return Status::GRPC_JSON_PARSE_ERROR;
state_ = State::GRPC_JSON_STATE_OBJECT_KEY_STRING;
break;
case State::GRPC_JSON_STATE_OBJECT_KEY_STRING:
if (unicode_high_surrogate_ != 0) {
return Status::GRPC_JSON_PARSE_ERROR;
}
if (c == '"') {
state_ = State::GRPC_JSON_STATE_OBJECT_KEY_END;
SetKey();
} else {
if (c < 32) return Status::GRPC_JSON_PARSE_ERROR;
StringAddChar(c);
}
break;
case State::GRPC_JSON_STATE_VALUE_STRING:
if (unicode_high_surrogate_ != 0) {
return Status::GRPC_JSON_PARSE_ERROR;
}
if (c == '"') {
state_ = State::GRPC_JSON_STATE_VALUE_END;
SetString();
} else {
if (c < 32) return Status::GRPC_JSON_PARSE_ERROR;
StringAddChar(c);
}
break;
case State::GRPC_JSON_STATE_OBJECT_KEY_END:
if (c != ':') return Status::GRPC_JSON_PARSE_ERROR;
state_ = State::GRPC_JSON_STATE_VALUE_BEGIN;
break;
case State::GRPC_JSON_STATE_VALUE_BEGIN:
switch (c) {
case 't':
state_ = State::GRPC_JSON_STATE_VALUE_TRUE_R;
break;
case 'f':
state_ = State::GRPC_JSON_STATE_VALUE_FALSE_A;
break;
case 'n':
state_ = State::GRPC_JSON_STATE_VALUE_NULL_U;
break;
case '"':
state_ = State::GRPC_JSON_STATE_VALUE_STRING;
break;
case '0':
StringAddChar(c);
state_ = State::GRPC_JSON_STATE_VALUE_NUMBER_ZERO;
break;
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
case '-':
StringAddChar(c);
state_ = State::GRPC_JSON_STATE_VALUE_NUMBER;
break;
case '{':
container_just_begun_ = true;
StartContainer(Json::Type::OBJECT);
state_ = State::GRPC_JSON_STATE_OBJECT_KEY_BEGIN;
break;
case '[':
container_just_begun_ = true;
StartContainer(Json::Type::ARRAY);
break;
default:
return Status::GRPC_JSON_PARSE_ERROR;
}
break;
case State::GRPC_JSON_STATE_STRING_ESCAPE:
if (escaped_string_was_key_) {
state_ = State::GRPC_JSON_STATE_OBJECT_KEY_STRING;
} else {
state_ = State::GRPC_JSON_STATE_VALUE_STRING;
}
if (unicode_high_surrogate_ && c != 'u') {
return Status::GRPC_JSON_PARSE_ERROR;
}
switch (c) {
case '"':
case '/':
StringAddChar(c);
break;
case 'b':
StringAddChar('\b');
break;
case 'f':
StringAddChar('\f');
break;
case 'n':
StringAddChar('\n');
break;
case 'r':
StringAddChar('\r');
break;
case 't':
StringAddChar('\t');
break;
case 'u':
state_ = State::GRPC_JSON_STATE_STRING_ESCAPE_U1;
unicode_char_ = 0;
break;
default:
return Status::GRPC_JSON_PARSE_ERROR;
}
break;
case State::GRPC_JSON_STATE_STRING_ESCAPE_U1:
case State::GRPC_JSON_STATE_STRING_ESCAPE_U2:
case State::GRPC_JSON_STATE_STRING_ESCAPE_U3:
case State::GRPC_JSON_STATE_STRING_ESCAPE_U4:
if ((c >= '0') && (c <= '9')) {
c -= '0';
} else if ((c >= 'A') && (c <= 'F')) {
c -= 'A' - 10;
} else if ((c >= 'a') && (c <= 'f')) {
c -= 'a' - 10;
} else {
return Status::GRPC_JSON_PARSE_ERROR;
}
unicode_char_ = static_cast<uint16_t>(unicode_char_ << 4);
unicode_char_ = static_cast<uint16_t>(unicode_char_ | c);
switch (state_) {
case State::GRPC_JSON_STATE_STRING_ESCAPE_U1:
state_ = State::GRPC_JSON_STATE_STRING_ESCAPE_U2;
break;
case State::GRPC_JSON_STATE_STRING_ESCAPE_U2:
state_ = State::GRPC_JSON_STATE_STRING_ESCAPE_U3;
break;
case State::GRPC_JSON_STATE_STRING_ESCAPE_U3:
state_ = State::GRPC_JSON_STATE_STRING_ESCAPE_U4;
break;
case State::GRPC_JSON_STATE_STRING_ESCAPE_U4:
/* See grpc_json_writer_escape_string to have a description
* of what's going on here.
*/
if ((unicode_char_ & 0xfc00) == 0xd800) {
/* high surrogate utf-16 */
if (unicode_high_surrogate_ != 0)
return Status::GRPC_JSON_PARSE_ERROR;
unicode_high_surrogate_ = unicode_char_;
} else if ((unicode_char_ & 0xfc00) == 0xdc00) {
/* low surrogate utf-16 */
uint32_t utf32;
if (unicode_high_surrogate_ == 0)
return Status::GRPC_JSON_PARSE_ERROR;
utf32 = 0x10000;
utf32 += static_cast<uint32_t>(
(unicode_high_surrogate_ - 0xd800) * 0x400);
utf32 += static_cast<uint32_t>(unicode_char_ - 0xdc00);
StringAddUtf32(utf32);
unicode_high_surrogate_ = 0;
} else {
/* anything else */
if (unicode_high_surrogate_ != 0)
return Status::GRPC_JSON_PARSE_ERROR;
StringAddUtf32(unicode_char_);
}
if (escaped_string_was_key_) {
state_ = State::GRPC_JSON_STATE_OBJECT_KEY_STRING;
} else {
state_ = State::GRPC_JSON_STATE_VALUE_STRING;
}
break;
default:
GPR_UNREACHABLE_CODE(return Status::GRPC_JSON_INTERNAL_ERROR);
}
break;
case State::GRPC_JSON_STATE_VALUE_NUMBER:
StringAddChar(c);
switch (c) {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
break;
case 'e':
case 'E':
state_ = State::GRPC_JSON_STATE_VALUE_NUMBER_E;
break;
case '.':
state_ = State::GRPC_JSON_STATE_VALUE_NUMBER_DOT;
break;
default:
return Status::GRPC_JSON_PARSE_ERROR;
}
break;
case State::GRPC_JSON_STATE_VALUE_NUMBER_WITH_DECIMAL:
StringAddChar(c);
switch (c) {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
break;
case 'e':
case 'E':
state_ = State::GRPC_JSON_STATE_VALUE_NUMBER_E;
break;
default:
return Status::GRPC_JSON_PARSE_ERROR;
}
break;
case State::GRPC_JSON_STATE_VALUE_NUMBER_ZERO:
if (c != '.') return Status::GRPC_JSON_PARSE_ERROR;
StringAddChar(c);
state_ = State::GRPC_JSON_STATE_VALUE_NUMBER_DOT;
break;
case State::GRPC_JSON_STATE_VALUE_NUMBER_DOT:
StringAddChar(c);
switch (c) {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
state_ = State::GRPC_JSON_STATE_VALUE_NUMBER_WITH_DECIMAL;
break;
default:
return Status::GRPC_JSON_PARSE_ERROR;
}
break;
case State::GRPC_JSON_STATE_VALUE_NUMBER_E:
StringAddChar(c);
switch (c) {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
case '+':
case '-':
state_ = State::GRPC_JSON_STATE_VALUE_NUMBER_EPM;
break;
default:
return Status::GRPC_JSON_PARSE_ERROR;
}
break;
case State::GRPC_JSON_STATE_VALUE_NUMBER_EPM:
StringAddChar(c);
switch (c) {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
break;
default:
return Status::GRPC_JSON_PARSE_ERROR;
}
break;
case State::GRPC_JSON_STATE_VALUE_TRUE_R:
if (c != 'r') return Status::GRPC_JSON_PARSE_ERROR;
state_ = State::GRPC_JSON_STATE_VALUE_TRUE_U;
break;
case State::GRPC_JSON_STATE_VALUE_TRUE_U:
if (c != 'u') return Status::GRPC_JSON_PARSE_ERROR;
state_ = State::GRPC_JSON_STATE_VALUE_TRUE_E;
break;
case State::GRPC_JSON_STATE_VALUE_TRUE_E:
if (c != 'e') return Status::GRPC_JSON_PARSE_ERROR;
SetTrue();
state_ = State::GRPC_JSON_STATE_VALUE_END;
break;
case State::GRPC_JSON_STATE_VALUE_FALSE_A:
if (c != 'a') return Status::GRPC_JSON_PARSE_ERROR;
state_ = State::GRPC_JSON_STATE_VALUE_FALSE_L;
break;
case State::GRPC_JSON_STATE_VALUE_FALSE_L:
if (c != 'l') return Status::GRPC_JSON_PARSE_ERROR;
state_ = State::GRPC_JSON_STATE_VALUE_FALSE_S;
break;
case State::GRPC_JSON_STATE_VALUE_FALSE_S:
if (c != 's') return Status::GRPC_JSON_PARSE_ERROR;
state_ = State::GRPC_JSON_STATE_VALUE_FALSE_E;
break;
case State::GRPC_JSON_STATE_VALUE_FALSE_E:
if (c != 'e') return Status::GRPC_JSON_PARSE_ERROR;
SetFalse();
state_ = State::GRPC_JSON_STATE_VALUE_END;
break;
case State::GRPC_JSON_STATE_VALUE_NULL_U:
if (c != 'u') return Status::GRPC_JSON_PARSE_ERROR;
state_ = State::GRPC_JSON_STATE_VALUE_NULL_L1;
break;
case State::GRPC_JSON_STATE_VALUE_NULL_L1:
if (c != 'l') return Status::GRPC_JSON_PARSE_ERROR;
state_ = State::GRPC_JSON_STATE_VALUE_NULL_L2;
break;
case State::GRPC_JSON_STATE_VALUE_NULL_L2:
if (c != 'l') return Status::GRPC_JSON_PARSE_ERROR;
SetNull();
state_ = State::GRPC_JSON_STATE_VALUE_END;
break;
/* All of the VALUE_END cases are handled in the specialized case
* above. */
case State::GRPC_JSON_STATE_VALUE_END:
switch (c) {
case ',':
case '}':
case ']':
GPR_UNREACHABLE_CODE(return Status::GRPC_JSON_INTERNAL_ERROR);
break;
default:
return Status::GRPC_JSON_PARSE_ERROR;
}
break;
case State::GRPC_JSON_STATE_END:
return Status::GRPC_JSON_PARSE_ERROR;
}
}
}
GPR_UNREACHABLE_CODE(return Status::GRPC_JSON_INTERNAL_ERROR);
}
JsonReader::Status JsonReader::Parse(StringView input, Json* output) {
JsonReader reader(input);
Status status = reader.Run();
if (reader.duplicate_key_found_) status = Status::GRPC_JSON_PARSE_ERROR;
if (status == Status::GRPC_JSON_DONE) {
*output = std::move(reader.root_value_);
}
return status;
}
} // namespace
Json Json::Parse(StringView json_str, grpc_error** error) {
Json value;
JsonReader::Status status = JsonReader::Parse(json_str, &value);
if (status == JsonReader::Status::GRPC_JSON_PARSE_ERROR) {
*error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("JSON parse error");
} else if (status == JsonReader::Status::GRPC_JSON_INTERNAL_ERROR) {
*error =
GRPC_ERROR_CREATE_FROM_STATIC_STRING("internal error in JSON parser");
}
return value;
}
} // namespace grpc_core

@ -0,0 +1,336 @@
/*
*
* Copyright 2015 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#include <grpc/support/port_platform.h>
#include <stdlib.h>
#include <string.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include "src/core/lib/json/json.h"
#include "src/core/lib/gprpp/string_view.h"
namespace grpc_core {
namespace {
/* 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.
*/
class JsonWriter {
public:
static std::string Dump(const Json& value, int indent);
private:
explicit JsonWriter(int indent) : indent_(indent) {}
void OutputCheck(size_t needed);
void OutputChar(char c);
void OutputString(const StringView str);
void OutputIndent();
void ValueEnd();
void EscapeUtf16(uint16_t utf16);
void EscapeString(const std::string& string);
void ContainerBegins(Json::Type type);
void ContainerEnds(Json::Type type);
void ObjectKey(const std::string& string);
void ValueRaw(const std::string& string);
void ValueString(const std::string& string);
void DumpObject(const Json::Object& object);
void DumpArray(const Json::Array& array);
void DumpValue(const Json& value);
int indent_;
int depth_ = 0;
bool container_empty_ = true;
bool got_key_ = false;
std::string output_;
};
/* 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).
*/
void JsonWriter::OutputCheck(size_t needed) {
size_t free_space = output_.capacity() - output_.size();
if (free_space >= needed) return;
needed -= free_space;
/* Round up by 256 bytes. */
needed = (needed + 0xff) & ~0xffU;
output_.reserve(output_.capacity() + needed);
}
void JsonWriter::OutputChar(char c) {
OutputCheck(1);
output_.push_back(c);
}
void JsonWriter::OutputString(const StringView str) {
OutputCheck(str.size());
output_.append(str.data(), str.size());
}
void JsonWriter::OutputIndent() {
static const char spacesstr[] =
" "
" "
" "
" ";
unsigned spaces = static_cast<unsigned>(depth_ * indent_);
if (indent_ == 0) return;
if (got_key_) {
OutputChar(' ');
return;
}
while (spaces >= (sizeof(spacesstr) - 1)) {
OutputString(StringView(spacesstr, sizeof(spacesstr) - 1));
spaces -= static_cast<unsigned>(sizeof(spacesstr) - 1);
}
if (spaces == 0) return;
OutputString(StringView(spacesstr + sizeof(spacesstr) - 1 - spaces, spaces));
}
void JsonWriter::ValueEnd() {
if (container_empty_) {
container_empty_ = false;
if (indent_ == 0 || depth_ == 0) return;
OutputChar('\n');
} else {
OutputChar(',');
if (indent_ == 0) return;
OutputChar('\n');
}
}
void JsonWriter::EscapeUtf16(uint16_t utf16) {
static const char hex[] = "0123456789abcdef";
OutputString(StringView("\\u", 2));
OutputChar(hex[(utf16 >> 12) & 0x0f]);
OutputChar(hex[(utf16 >> 8) & 0x0f]);
OutputChar(hex[(utf16 >> 4) & 0x0f]);
OutputChar(hex[(utf16)&0x0f]);
}
void JsonWriter::EscapeString(const std::string& string) {
OutputChar('"');
for (size_t idx = 0; idx < string.size(); ++idx) {
uint8_t c = static_cast<uint8_t>(string[idx]);
if (c == 0) {
break;
} else if (c >= 32 && c <= 126) {
if (c == '\\' || c == '"') OutputChar('\\');
OutputChar(static_cast<char>(c));
} else if (c < 32 || c == 127) {
switch (c) {
case '\b':
OutputString(StringView("\\b", 2));
break;
case '\f':
OutputString(StringView("\\f", 2));
break;
case '\n':
OutputString(StringView("\\n", 2));
break;
case '\r':
OutputString(StringView("\\r", 2));
break;
case '\t':
OutputString(StringView("\\t", 2));
break;
default:
EscapeUtf16(c);
break;
}
} else {
uint32_t 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;
++idx;
/* Breaks out and bail if we hit the end of the string. */
if (idx == string.size()) {
valid = 0;
break;
}
c = static_cast<uint8_t>(string[idx]);
/* Breaks out and bail on any invalid UTF-8 sequence, including \0. */
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;
EscapeUtf16(static_cast<uint16_t>(0xd800 | (utf32 >> 10)));
EscapeUtf16(static_cast<uint16_t>(0xdc00 | (utf32 & 0x3ff)));
} else {
EscapeUtf16(static_cast<uint16_t>(utf32));
}
}
}
OutputChar('"');
}
void JsonWriter::ContainerBegins(Json::Type type) {
if (!got_key_) ValueEnd();
OutputIndent();
OutputChar(type == Json::Type::OBJECT ? '{' : '[');
container_empty_ = true;
got_key_ = false;
depth_++;
}
void JsonWriter::ContainerEnds(Json::Type type) {
if (indent_ && !container_empty_) OutputChar('\n');
depth_--;
if (!container_empty_) OutputIndent();
OutputChar(type == Json::Type::OBJECT ? '}' : ']');
container_empty_ = false;
got_key_ = false;
}
void JsonWriter::ObjectKey(const std::string& string) {
ValueEnd();
OutputIndent();
EscapeString(string);
OutputChar(':');
got_key_ = true;
}
void JsonWriter::ValueRaw(const std::string& string) {
if (!got_key_) ValueEnd();
OutputIndent();
OutputString(string);
got_key_ = false;
}
void JsonWriter::ValueString(const std::string& string) {
if (!got_key_) ValueEnd();
OutputIndent();
EscapeString(string);
got_key_ = false;
}
void JsonWriter::DumpObject(const Json::Object& object) {
ContainerBegins(Json::Type::OBJECT);
for (const auto& p : object) {
ObjectKey(p.first.data());
DumpValue(p.second);
}
ContainerEnds(Json::Type::OBJECT);
}
void JsonWriter::DumpArray(const Json::Array& array) {
ContainerBegins(Json::Type::ARRAY);
for (const auto& v : array) {
DumpValue(v);
}
ContainerEnds(Json::Type::ARRAY);
}
void JsonWriter::DumpValue(const Json& value) {
switch (value.type()) {
case Json::Type::OBJECT:
DumpObject(value.object_value());
break;
case Json::Type::ARRAY:
DumpArray(value.array_value());
break;
case Json::Type::STRING:
ValueString(value.string_value());
break;
case Json::Type::NUMBER:
ValueRaw(value.string_value());
break;
case Json::Type::JSON_TRUE:
ValueRaw(std::string("true", 4));
break;
case Json::Type::JSON_FALSE:
ValueRaw(std::string("false", 5));
break;
case Json::Type::JSON_NULL:
ValueRaw(std::string("null", 4));
break;
default:
GPR_UNREACHABLE_CODE(abort());
}
}
std::string JsonWriter::Dump(const Json& value, int indent) {
JsonWriter writer(indent);
writer.DumpValue(value);
return std::move(writer.output_);
}
} // namespace
std::string Json::Dump(int indent) const {
return JsonWriter::Dump(*this, indent);
}
} // namespace grpc_core

@ -326,7 +326,9 @@ CORE_SOURCE_FILES = [
'src/core/lib/iomgr/wakeup_fd_posix.cc', 'src/core/lib/iomgr/wakeup_fd_posix.cc',
'src/core/lib/json/json.cc', 'src/core/lib/json/json.cc',
'src/core/lib/json/json_reader.cc', 'src/core/lib/json/json_reader.cc',
'src/core/lib/json/json_reader_new.cc',
'src/core/lib/json/json_writer.cc', 'src/core/lib/json/json_writer.cc',
'src/core/lib/json/json_writer_new.cc',
'src/core/lib/profiling/basic_timers.cc', 'src/core/lib/profiling/basic_timers.cc',
'src/core/lib/profiling/stap_timers.cc', 'src/core/lib/profiling/stap_timers.cc',
'src/core/lib/security/context/security_context.cc', 'src/core/lib/security/context/security_context.cc',

@ -44,3 +44,18 @@ grpc_cc_test(
"//test/core/util:grpc_test_util", "//test/core/util:grpc_test_util",
], ],
) )
grpc_cc_test(
name = "json_test_new",
srcs = ["json_test_new.cc"],
external_deps = [
"gtest",
],
language = "C++",
uses_polling = False,
deps = [
"//:gpr",
"//:grpc",
"//test/core/util:grpc_test_util",
],
)

@ -0,0 +1,295 @@
/*
*
* Copyright 2015-2016 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#include <string.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "src/core/lib/gpr/string.h"
#include "src/core/lib/gpr/useful.h"
#include "src/core/lib/json/json.h"
#include "test/core/util/test_config.h"
namespace grpc_core {
void ValidateValue(const Json& actual, const Json& expected);
void ValidateObject(const Json::Object& actual, const Json::Object& expected) {
ASSERT_EQ(actual.size(), expected.size());
auto actual_it = actual.begin();
for (const auto& p : expected) {
EXPECT_EQ(actual_it->first, p.first);
ValidateValue(actual_it->second, p.second);
++actual_it;
}
}
void ValidateArray(const Json::Array& actual, const Json::Array& expected) {
ASSERT_EQ(actual.size(), expected.size());
for (size_t i = 0; i < expected.size(); ++i) {
ValidateValue(actual[i], expected[i]);
}
}
void ValidateValue(const Json& actual, const Json& expected) {
ASSERT_EQ(actual.type(), expected.type());
switch (expected.type()) {
case Json::Type::JSON_NULL:
case Json::Type::JSON_TRUE:
case Json::Type::JSON_FALSE:
break;
case Json::Type::STRING:
case Json::Type::NUMBER:
EXPECT_EQ(actual.string_value(), expected.string_value());
break;
case Json::Type::OBJECT:
ValidateObject(actual.object_value(), expected.object_value());
break;
case Json::Type::ARRAY:
ValidateArray(actual.array_value(), expected.array_value());
break;
}
}
void RunSuccessTest(const char* input, const Json& expected,
const char* expected_output) {
gpr_log(GPR_INFO, "parsing string \"%s\" - should succeed", input);
grpc_error* error = GRPC_ERROR_NONE;
Json json = Json::Parse(input, &error);
ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
ValidateValue(json, expected);
std::string output = json.Dump();
EXPECT_EQ(output, expected_output);
}
TEST(Json, Whitespace) {
RunSuccessTest(" 0 ", 0, "0");
RunSuccessTest(" 1 ", 1, "1");
RunSuccessTest(" \" \" ", " ", "\" \"");
RunSuccessTest(" \"a\" ", "a", "\"a\"");
RunSuccessTest(" true ", true, "true");
}
TEST(Json, Utf16) {
RunSuccessTest("\"\\u0020\\\\\\u0010\\u000a\\u000D\"", " \\\u0010\n\r",
"\" \\\\\\u0010\\n\\r\"");
}
TEST(Json, Utf8) {
RunSuccessTest("\"ßâñć௵⇒\"", "ßâñć௵⇒",
"\"\\u00df\\u00e2\\u00f1\\u0107\\u0bf5\\u21d2\"");
RunSuccessTest("\"\\u00df\\u00e2\\u00f1\\u0107\\u0bf5\\u21d2\"", "ßâñć௵⇒",
"\"\\u00df\\u00e2\\u00f1\\u0107\\u0bf5\\u21d2\"");
// Testing UTF-8 character "𝄞", U+11D1E.
RunSuccessTest("\"\xf0\x9d\x84\x9e\"", "\xf0\x9d\x84\x9e",
"\"\\ud834\\udd1e\"");
RunSuccessTest("\"\\ud834\\udd1e\"", "\xf0\x9d\x84\x9e",
"\"\\ud834\\udd1e\"");
RunSuccessTest("{\"\\ud834\\udd1e\":0}",
Json::Object{{"\xf0\x9d\x84\x9e", 0}},
"{\"\\ud834\\udd1e\":0}");
}
TEST(Json, NestedEmptyContainers) {
RunSuccessTest(" [ [ ] , { } , [ ] ] ",
Json::Array{
Json::Array(),
Json::Object(),
Json::Array(),
},
"[[],{},[]]");
}
TEST(Json, EscapesAndControlCharactersInKeyStrings) {
RunSuccessTest(" { \"\\u007f\x7f\\n\\r\\\"\\f\\b\\\\a , b\": 1, \"\": 0 } ",
Json::Object{
{"\u007f\u007f\n\r\"\f\b\\a , b", 1},
{"", 0},
},
"{\"\":0,\"\\u007f\\u007f\\n\\r\\\"\\f\\b\\\\a , b\":1}");
}
TEST(Json, WriterCutsOffInvalidUtf8) {
RunSuccessTest("\"abc\xf0\x9d\x24\"", "abc\xf0\x9d\x24", "\"abc\"");
RunSuccessTest("\"\xff\"", "\xff", "\"\"");
}
TEST(Json, ValidNumbers) {
RunSuccessTest("[0, 42 , 0.0123, 123.456]",
Json::Array{
0,
42,
Json("0.0123", /*is_number=*/true),
Json("123.456", /*is_number=*/true),
},
"[0,42,0.0123,123.456]");
RunSuccessTest("[1e4,-53.235e-31, 0.3e+3]",
Json::Array{
Json("1e4", /*is_number=*/true),
Json("-53.235e-31", /*is_number=*/true),
Json("0.3e+3", /*is_number=*/true),
},
"[1e4,-53.235e-31,0.3e+3]");
}
TEST(Json, Keywords) {
RunSuccessTest("[true, false, null]",
Json::Array{
Json(true),
Json(false),
Json(),
},
"[true,false,null]");
}
void RunParseFailureTest(const char* input) {
gpr_log(GPR_INFO, "parsing string \"%s\" - should fail", input);
grpc_error* error = GRPC_ERROR_NONE;
Json json = Json::Parse(input, &error);
gpr_log(GPR_INFO, "error: %s", grpc_error_string(error));
EXPECT_NE(error, GRPC_ERROR_NONE);
GRPC_ERROR_UNREF(error);
}
TEST(Json, InvalidInput) {
RunParseFailureTest("\\");
RunParseFailureTest("nu ll");
RunParseFailureTest("{\"foo\": bar}");
RunParseFailureTest("{\"foo\": bar\"x\"}");
RunParseFailureTest("fals");
RunParseFailureTest("0,0 ");
RunParseFailureTest("\"foo\",[]");
}
TEST(Json, UnterminatedString) { RunParseFailureTest("\"\\x"); }
TEST(Json, InvalidUtf16) {
RunParseFailureTest("\"\\u123x");
RunParseFailureTest("{\"\\u123x");
}
TEST(Json, ImbalancedSurrogatePairs) {
RunParseFailureTest("\"\\ud834f");
RunParseFailureTest("{\"\\ud834f\":0}");
RunParseFailureTest("\"\\ud834\\n");
RunParseFailureTest("{\"\\ud834\\n\":0}");
RunParseFailureTest("\"\\udd1ef");
RunParseFailureTest("{\"\\udd1ef\":0}");
RunParseFailureTest("\"\\ud834\\ud834\"");
RunParseFailureTest("{\"\\ud834\\ud834\"\":0}");
RunParseFailureTest("\"\\ud834\\u1234\"");
RunParseFailureTest("{\"\\ud834\\u1234\"\":0}");
RunParseFailureTest("\"\\ud834]\"");
RunParseFailureTest("{\"\\ud834]\"\":0}");
RunParseFailureTest("\"\\ud834 \"");
RunParseFailureTest("{\"\\ud834 \"\":0}");
RunParseFailureTest("\"\\ud834\\\\\"");
RunParseFailureTest("{\"\\ud834\\\\\"\":0}");
}
TEST(Json, EmbeddedInvalidWhitechars) {
RunParseFailureTest("\"\n\"");
RunParseFailureTest("\"\t\"");
}
TEST(Json, EmptyString) { RunParseFailureTest(""); }
TEST(Json, ExtraCharsAtEndOfParsing) {
RunParseFailureTest("{},");
RunParseFailureTest("{}x");
}
TEST(Json, ImbalancedContainers) {
RunParseFailureTest("{}}");
RunParseFailureTest("[]]");
RunParseFailureTest("{{}");
RunParseFailureTest("[[]");
RunParseFailureTest("[}");
RunParseFailureTest("{]");
}
TEST(Json, BadContainers) {
RunParseFailureTest("{x}");
RunParseFailureTest("{x=0,y}");
}
TEST(Json, DuplicateObjectKeys) { RunParseFailureTest("{\"x\": 1, \"x\": 1}"); }
TEST(Json, TrailingComma) {
RunParseFailureTest("{,}");
RunParseFailureTest("[1,2,3,4,]");
RunParseFailureTest("{\"a\": 1, }");
}
TEST(Json, KeySyntaxInArray) { RunParseFailureTest("[\"x\":0]"); }
TEST(Json, InvalidNumbers) {
RunParseFailureTest("1.");
RunParseFailureTest("1e");
RunParseFailureTest(".12");
RunParseFailureTest("1.x");
RunParseFailureTest("1.12x");
RunParseFailureTest("1ex");
RunParseFailureTest("1e12x");
RunParseFailureTest(".12x");
RunParseFailureTest("000");
};
TEST(Json, Equality) {
// Null.
EXPECT_EQ(Json(), Json());
// Numbers.
EXPECT_EQ(Json(1), Json(1));
EXPECT_NE(Json(1), Json(2));
EXPECT_EQ(Json(1), Json("1", /*is_number=*/true));
EXPECT_EQ(Json("-5e5", /*is_number=*/true), Json("-5e5", /*is_number=*/true));
// Booleans.
EXPECT_EQ(Json(true), Json(true));
EXPECT_EQ(Json(false), Json(false));
EXPECT_NE(Json(true), Json(false));
// Strings.
EXPECT_EQ(Json("foo"), Json("foo"));
EXPECT_NE(Json("foo"), Json("bar"));
// Arrays.
EXPECT_EQ(Json(Json::Array{"foo"}), Json(Json::Array{"foo"}));
EXPECT_NE(Json(Json::Array{"foo"}), Json(Json::Array{"bar"}));
// Objects.
EXPECT_EQ(Json(Json::Object{{"foo", 1}}), Json(Json::Object{{"foo", 1}}));
EXPECT_NE(Json(Json::Object{{"foo", 1}}), Json(Json::Object{{"foo", 2}}));
EXPECT_NE(Json(Json::Object{{"foo", 1}}), Json(Json::Object{{"bar", 1}}));
// Differing types.
EXPECT_NE(Json(1), Json("foo"));
EXPECT_NE(Json(1), Json(true));
EXPECT_NE(Json(1), Json(Json::Array{}));
EXPECT_NE(Json(1), Json(Json::Object{}));
EXPECT_NE(Json(1), Json());
}
} // namespace grpc_core
int main(int argc, char** argv) {
grpc::testing::TestEnvironment env(argc, argv);
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

@ -1466,7 +1466,9 @@ src/core/lib/iomgr/wakeup_fd_posix.h \
src/core/lib/json/json.cc \ src/core/lib/json/json.cc \
src/core/lib/json/json.h \ src/core/lib/json/json.h \
src/core/lib/json/json_reader.cc \ src/core/lib/json/json_reader.cc \
src/core/lib/json/json_reader_new.cc \
src/core/lib/json/json_writer.cc \ src/core/lib/json/json_writer.cc \
src/core/lib/json/json_writer_new.cc \
src/core/lib/profiling/basic_timers.cc \ src/core/lib/profiling/basic_timers.cc \
src/core/lib/profiling/stap_timers.cc \ src/core/lib/profiling/stap_timers.cc \
src/core/lib/profiling/timers.h \ src/core/lib/profiling/timers.h \

@ -5019,6 +5019,30 @@
], ],
"uses_polling": true "uses_polling": true
}, },
{
"args": [],
"benchmark": false,
"ci_platforms": [
"linux",
"mac",
"posix",
"windows"
],
"cpu_cost": 1.0,
"exclude_configs": [],
"exclude_iomgrs": [],
"flaky": false,
"gtest": true,
"language": "c++",
"name": "json_test_new",
"platforms": [
"linux",
"mac",
"posix",
"windows"
],
"uses_polling": false
},
{ {
"args": [], "args": [],
"benchmark": false, "benchmark": false,

Loading…
Cancel
Save