diff --git a/Makefile b/Makefile
index 77935bcb6ef21e702500cdffd9a231174c71f11e..b252ea2eba4c001a5f0a15e359f060d4fffac1d7 100644
--- a/Makefile
+++ b/Makefile
@@ -374,6 +374,8 @@ time_averaged_stats_test: bins/$(CONFIG)/time_averaged_stats_test
 time_test: bins/$(CONFIG)/time_test
 timeout_encoding_test: bins/$(CONFIG)/timeout_encoding_test
 transport_metadata_test: bins/$(CONFIG)/transport_metadata_test
+json_test: bins/$(CONFIG)/json_test
+json_rewrite: bins/$(CONFIG)/json_rewrite
 channel_arguments_test: bins/$(CONFIG)/channel_arguments_test
 cpp_plugin: bins/$(CONFIG)/cpp_plugin
 credentials_test: bins/$(CONFIG)/credentials_test
@@ -565,7 +567,7 @@ privatelibs_cxx:  libs/$(CONFIG)/libgrpc++_test_util.a libs/$(CONFIG)/libtips_cl
 
 buildtests: buildtests_c buildtests_cxx
 
-buildtests_c: privatelibs_c bins/$(CONFIG)/alarm_heap_test bins/$(CONFIG)/alarm_list_test bins/$(CONFIG)/alarm_test bins/$(CONFIG)/alpn_test bins/$(CONFIG)/bin_encoder_test bins/$(CONFIG)/census_hash_table_test bins/$(CONFIG)/census_statistics_multiple_writers_circular_buffer_test bins/$(CONFIG)/census_statistics_multiple_writers_test bins/$(CONFIG)/census_statistics_performance_test bins/$(CONFIG)/census_statistics_quick_test bins/$(CONFIG)/census_statistics_small_log_test bins/$(CONFIG)/census_stub_test bins/$(CONFIG)/census_window_stats_test bins/$(CONFIG)/chttp2_status_conversion_test bins/$(CONFIG)/chttp2_stream_encoder_test bins/$(CONFIG)/chttp2_stream_map_test bins/$(CONFIG)/chttp2_transport_end2end_test bins/$(CONFIG)/dualstack_socket_test bins/$(CONFIG)/echo_client bins/$(CONFIG)/echo_server bins/$(CONFIG)/echo_test bins/$(CONFIG)/fd_posix_test bins/$(CONFIG)/fling_client bins/$(CONFIG)/fling_server bins/$(CONFIG)/fling_stream_test bins/$(CONFIG)/fling_test bins/$(CONFIG)/gpr_cancellable_test bins/$(CONFIG)/gpr_cmdline_test bins/$(CONFIG)/gpr_histogram_test bins/$(CONFIG)/gpr_host_port_test bins/$(CONFIG)/gpr_log_test bins/$(CONFIG)/gpr_slice_buffer_test bins/$(CONFIG)/gpr_slice_test bins/$(CONFIG)/gpr_string_test bins/$(CONFIG)/gpr_sync_test bins/$(CONFIG)/gpr_thd_test bins/$(CONFIG)/gpr_time_test bins/$(CONFIG)/gpr_useful_test bins/$(CONFIG)/grpc_base64_test bins/$(CONFIG)/grpc_byte_buffer_reader_test bins/$(CONFIG)/grpc_channel_stack_test bins/$(CONFIG)/grpc_completion_queue_test bins/$(CONFIG)/grpc_credentials_test bins/$(CONFIG)/grpc_json_token_test bins/$(CONFIG)/grpc_stream_op_test bins/$(CONFIG)/hpack_parser_test bins/$(CONFIG)/hpack_table_test bins/$(CONFIG)/httpcli_format_request_test bins/$(CONFIG)/httpcli_parser_test bins/$(CONFIG)/httpcli_test bins/$(CONFIG)/lame_client_test bins/$(CONFIG)/message_compress_test bins/$(CONFIG)/metadata_buffer_test bins/$(CONFIG)/murmur_hash_test bins/$(CONFIG)/no_server_test bins/$(CONFIG)/poll_kick_test bins/$(CONFIG)/resolve_address_test bins/$(CONFIG)/secure_endpoint_test bins/$(CONFIG)/sockaddr_utils_test bins/$(CONFIG)/tcp_client_posix_test bins/$(CONFIG)/tcp_posix_test bins/$(CONFIG)/tcp_server_posix_test bins/$(CONFIG)/time_averaged_stats_test bins/$(CONFIG)/time_test bins/$(CONFIG)/timeout_encoding_test bins/$(CONFIG)/transport_metadata_test bins/$(CONFIG)/chttp2_fake_security_cancel_after_accept_test bins/$(CONFIG)/chttp2_fake_security_cancel_after_accept_and_writes_closed_test bins/$(CONFIG)/chttp2_fake_security_cancel_after_invoke_test bins/$(CONFIG)/chttp2_fake_security_cancel_before_invoke_test bins/$(CONFIG)/chttp2_fake_security_cancel_in_a_vacuum_test bins/$(CONFIG)/chttp2_fake_security_census_simple_request_test bins/$(CONFIG)/chttp2_fake_security_disappearing_server_test bins/$(CONFIG)/chttp2_fake_security_early_server_shutdown_finishes_inflight_calls_test bins/$(CONFIG)/chttp2_fake_security_early_server_shutdown_finishes_tags_test bins/$(CONFIG)/chttp2_fake_security_graceful_server_shutdown_test bins/$(CONFIG)/chttp2_fake_security_invoke_large_request_test bins/$(CONFIG)/chttp2_fake_security_max_concurrent_streams_test bins/$(CONFIG)/chttp2_fake_security_no_op_test bins/$(CONFIG)/chttp2_fake_security_ping_pong_streaming_test bins/$(CONFIG)/chttp2_fake_security_request_response_with_binary_metadata_and_payload_test bins/$(CONFIG)/chttp2_fake_security_request_response_with_metadata_and_payload_test bins/$(CONFIG)/chttp2_fake_security_request_response_with_payload_test bins/$(CONFIG)/chttp2_fake_security_request_response_with_trailing_metadata_and_payload_test bins/$(CONFIG)/chttp2_fake_security_simple_delayed_request_test bins/$(CONFIG)/chttp2_fake_security_simple_request_test bins/$(CONFIG)/chttp2_fake_security_thread_stress_test bins/$(CONFIG)/chttp2_fake_security_writes_done_hangs_with_pending_read_test bins/$(CONFIG)/chttp2_fullstack_cancel_after_accept_test bins/$(CONFIG)/chttp2_fullstack_cancel_after_accept_and_writes_closed_test bins/$(CONFIG)/chttp2_fullstack_cancel_after_invoke_test bins/$(CONFIG)/chttp2_fullstack_cancel_before_invoke_test bins/$(CONFIG)/chttp2_fullstack_cancel_in_a_vacuum_test bins/$(CONFIG)/chttp2_fullstack_census_simple_request_test bins/$(CONFIG)/chttp2_fullstack_disappearing_server_test bins/$(CONFIG)/chttp2_fullstack_early_server_shutdown_finishes_inflight_calls_test bins/$(CONFIG)/chttp2_fullstack_early_server_shutdown_finishes_tags_test bins/$(CONFIG)/chttp2_fullstack_graceful_server_shutdown_test bins/$(CONFIG)/chttp2_fullstack_invoke_large_request_test bins/$(CONFIG)/chttp2_fullstack_max_concurrent_streams_test bins/$(CONFIG)/chttp2_fullstack_no_op_test bins/$(CONFIG)/chttp2_fullstack_ping_pong_streaming_test bins/$(CONFIG)/chttp2_fullstack_request_response_with_binary_metadata_and_payload_test bins/$(CONFIG)/chttp2_fullstack_request_response_with_metadata_and_payload_test bins/$(CONFIG)/chttp2_fullstack_request_response_with_payload_test bins/$(CONFIG)/chttp2_fullstack_request_response_with_trailing_metadata_and_payload_test bins/$(CONFIG)/chttp2_fullstack_simple_delayed_request_test bins/$(CONFIG)/chttp2_fullstack_simple_request_test bins/$(CONFIG)/chttp2_fullstack_thread_stress_test bins/$(CONFIG)/chttp2_fullstack_writes_done_hangs_with_pending_read_test bins/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_after_accept_test bins/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_after_accept_and_writes_closed_test bins/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_after_invoke_test bins/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_before_invoke_test bins/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_in_a_vacuum_test bins/$(CONFIG)/chttp2_simple_ssl_fullstack_census_simple_request_test bins/$(CONFIG)/chttp2_simple_ssl_fullstack_disappearing_server_test bins/$(CONFIG)/chttp2_simple_ssl_fullstack_early_server_shutdown_finishes_inflight_calls_test bins/$(CONFIG)/chttp2_simple_ssl_fullstack_early_server_shutdown_finishes_tags_test bins/$(CONFIG)/chttp2_simple_ssl_fullstack_graceful_server_shutdown_test bins/$(CONFIG)/chttp2_simple_ssl_fullstack_invoke_large_request_test bins/$(CONFIG)/chttp2_simple_ssl_fullstack_max_concurrent_streams_test bins/$(CONFIG)/chttp2_simple_ssl_fullstack_no_op_test bins/$(CONFIG)/chttp2_simple_ssl_fullstack_ping_pong_streaming_test bins/$(CONFIG)/chttp2_simple_ssl_fullstack_request_response_with_binary_metadata_and_payload_test bins/$(CONFIG)/chttp2_simple_ssl_fullstack_request_response_with_metadata_and_payload_test bins/$(CONFIG)/chttp2_simple_ssl_fullstack_request_response_with_payload_test bins/$(CONFIG)/chttp2_simple_ssl_fullstack_request_response_with_trailing_metadata_and_payload_test bins/$(CONFIG)/chttp2_simple_ssl_fullstack_simple_delayed_request_test bins/$(CONFIG)/chttp2_simple_ssl_fullstack_simple_request_test bins/$(CONFIG)/chttp2_simple_ssl_fullstack_thread_stress_test bins/$(CONFIG)/chttp2_simple_ssl_fullstack_writes_done_hangs_with_pending_read_test bins/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_test bins/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_and_writes_closed_test bins/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_invoke_test bins/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_before_invoke_test bins/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_in_a_vacuum_test bins/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_census_simple_request_test bins/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_disappearing_server_test bins/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_early_server_shutdown_finishes_inflight_calls_test bins/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_early_server_shutdown_finishes_tags_test bins/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_graceful_server_shutdown_test bins/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_invoke_large_request_test bins/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_max_concurrent_streams_test bins/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_no_op_test bins/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_ping_pong_streaming_test bins/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_binary_metadata_and_payload_test bins/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_metadata_and_payload_test bins/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_payload_test bins/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_trailing_metadata_and_payload_test bins/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_simple_delayed_request_test bins/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_simple_request_test bins/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_thread_stress_test bins/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_writes_done_hangs_with_pending_read_test bins/$(CONFIG)/chttp2_socket_pair_cancel_after_accept_test bins/$(CONFIG)/chttp2_socket_pair_cancel_after_accept_and_writes_closed_test bins/$(CONFIG)/chttp2_socket_pair_cancel_after_invoke_test bins/$(CONFIG)/chttp2_socket_pair_cancel_before_invoke_test bins/$(CONFIG)/chttp2_socket_pair_cancel_in_a_vacuum_test bins/$(CONFIG)/chttp2_socket_pair_census_simple_request_test bins/$(CONFIG)/chttp2_socket_pair_disappearing_server_test bins/$(CONFIG)/chttp2_socket_pair_early_server_shutdown_finishes_inflight_calls_test bins/$(CONFIG)/chttp2_socket_pair_early_server_shutdown_finishes_tags_test bins/$(CONFIG)/chttp2_socket_pair_graceful_server_shutdown_test bins/$(CONFIG)/chttp2_socket_pair_invoke_large_request_test bins/$(CONFIG)/chttp2_socket_pair_max_concurrent_streams_test bins/$(CONFIG)/chttp2_socket_pair_no_op_test bins/$(CONFIG)/chttp2_socket_pair_ping_pong_streaming_test bins/$(CONFIG)/chttp2_socket_pair_request_response_with_binary_metadata_and_payload_test bins/$(CONFIG)/chttp2_socket_pair_request_response_with_metadata_and_payload_test bins/$(CONFIG)/chttp2_socket_pair_request_response_with_payload_test bins/$(CONFIG)/chttp2_socket_pair_request_response_with_trailing_metadata_and_payload_test bins/$(CONFIG)/chttp2_socket_pair_simple_delayed_request_test bins/$(CONFIG)/chttp2_socket_pair_simple_request_test bins/$(CONFIG)/chttp2_socket_pair_thread_stress_test bins/$(CONFIG)/chttp2_socket_pair_writes_done_hangs_with_pending_read_test bins/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_after_accept_test bins/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_after_accept_and_writes_closed_test bins/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_after_invoke_test bins/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_before_invoke_test bins/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_in_a_vacuum_test bins/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_census_simple_request_test bins/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_disappearing_server_test bins/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_early_server_shutdown_finishes_inflight_calls_test bins/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_early_server_shutdown_finishes_tags_test bins/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_graceful_server_shutdown_test bins/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_invoke_large_request_test bins/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_max_concurrent_streams_test bins/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_no_op_test bins/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_ping_pong_streaming_test bins/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_binary_metadata_and_payload_test bins/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_metadata_and_payload_test bins/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_payload_test bins/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_trailing_metadata_and_payload_test bins/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_simple_delayed_request_test bins/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_simple_request_test bins/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_thread_stress_test bins/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_writes_done_hangs_with_pending_read_test
+buildtests_c: privatelibs_c bins/$(CONFIG)/alarm_heap_test bins/$(CONFIG)/alarm_list_test bins/$(CONFIG)/alarm_test bins/$(CONFIG)/alpn_test bins/$(CONFIG)/bin_encoder_test bins/$(CONFIG)/census_hash_table_test bins/$(CONFIG)/census_statistics_multiple_writers_circular_buffer_test bins/$(CONFIG)/census_statistics_multiple_writers_test bins/$(CONFIG)/census_statistics_performance_test bins/$(CONFIG)/census_statistics_quick_test bins/$(CONFIG)/census_statistics_small_log_test bins/$(CONFIG)/census_stub_test bins/$(CONFIG)/census_window_stats_test bins/$(CONFIG)/chttp2_status_conversion_test bins/$(CONFIG)/chttp2_stream_encoder_test bins/$(CONFIG)/chttp2_stream_map_test bins/$(CONFIG)/chttp2_transport_end2end_test bins/$(CONFIG)/dualstack_socket_test bins/$(CONFIG)/echo_client bins/$(CONFIG)/echo_server bins/$(CONFIG)/echo_test bins/$(CONFIG)/fd_posix_test bins/$(CONFIG)/fling_client bins/$(CONFIG)/fling_server bins/$(CONFIG)/fling_stream_test bins/$(CONFIG)/fling_test bins/$(CONFIG)/gpr_cancellable_test bins/$(CONFIG)/gpr_cmdline_test bins/$(CONFIG)/gpr_histogram_test bins/$(CONFIG)/gpr_host_port_test bins/$(CONFIG)/gpr_log_test bins/$(CONFIG)/gpr_slice_buffer_test bins/$(CONFIG)/gpr_slice_test bins/$(CONFIG)/gpr_string_test bins/$(CONFIG)/gpr_sync_test bins/$(CONFIG)/gpr_thd_test bins/$(CONFIG)/gpr_time_test bins/$(CONFIG)/gpr_useful_test bins/$(CONFIG)/grpc_base64_test bins/$(CONFIG)/grpc_byte_buffer_reader_test bins/$(CONFIG)/grpc_channel_stack_test bins/$(CONFIG)/grpc_completion_queue_test bins/$(CONFIG)/grpc_credentials_test bins/$(CONFIG)/grpc_json_token_test bins/$(CONFIG)/grpc_stream_op_test bins/$(CONFIG)/hpack_parser_test bins/$(CONFIG)/hpack_table_test bins/$(CONFIG)/httpcli_format_request_test bins/$(CONFIG)/httpcli_parser_test bins/$(CONFIG)/httpcli_test bins/$(CONFIG)/lame_client_test bins/$(CONFIG)/message_compress_test bins/$(CONFIG)/metadata_buffer_test bins/$(CONFIG)/murmur_hash_test bins/$(CONFIG)/no_server_test bins/$(CONFIG)/poll_kick_test bins/$(CONFIG)/resolve_address_test bins/$(CONFIG)/secure_endpoint_test bins/$(CONFIG)/sockaddr_utils_test bins/$(CONFIG)/tcp_client_posix_test bins/$(CONFIG)/tcp_posix_test bins/$(CONFIG)/tcp_server_posix_test bins/$(CONFIG)/time_averaged_stats_test bins/$(CONFIG)/time_test bins/$(CONFIG)/timeout_encoding_test bins/$(CONFIG)/transport_metadata_test bins/$(CONFIG)/json_test bins/$(CONFIG)/json_rewrite bins/$(CONFIG)/chttp2_fake_security_cancel_after_accept_test bins/$(CONFIG)/chttp2_fake_security_cancel_after_accept_and_writes_closed_test bins/$(CONFIG)/chttp2_fake_security_cancel_after_invoke_test bins/$(CONFIG)/chttp2_fake_security_cancel_before_invoke_test bins/$(CONFIG)/chttp2_fake_security_cancel_in_a_vacuum_test bins/$(CONFIG)/chttp2_fake_security_census_simple_request_test bins/$(CONFIG)/chttp2_fake_security_disappearing_server_test bins/$(CONFIG)/chttp2_fake_security_early_server_shutdown_finishes_inflight_calls_test bins/$(CONFIG)/chttp2_fake_security_early_server_shutdown_finishes_tags_test bins/$(CONFIG)/chttp2_fake_security_graceful_server_shutdown_test bins/$(CONFIG)/chttp2_fake_security_invoke_large_request_test bins/$(CONFIG)/chttp2_fake_security_max_concurrent_streams_test bins/$(CONFIG)/chttp2_fake_security_no_op_test bins/$(CONFIG)/chttp2_fake_security_ping_pong_streaming_test bins/$(CONFIG)/chttp2_fake_security_request_response_with_binary_metadata_and_payload_test bins/$(CONFIG)/chttp2_fake_security_request_response_with_metadata_and_payload_test bins/$(CONFIG)/chttp2_fake_security_request_response_with_payload_test bins/$(CONFIG)/chttp2_fake_security_request_response_with_trailing_metadata_and_payload_test bins/$(CONFIG)/chttp2_fake_security_simple_delayed_request_test bins/$(CONFIG)/chttp2_fake_security_simple_request_test bins/$(CONFIG)/chttp2_fake_security_thread_stress_test bins/$(CONFIG)/chttp2_fake_security_writes_done_hangs_with_pending_read_test bins/$(CONFIG)/chttp2_fullstack_cancel_after_accept_test bins/$(CONFIG)/chttp2_fullstack_cancel_after_accept_and_writes_closed_test bins/$(CONFIG)/chttp2_fullstack_cancel_after_invoke_test bins/$(CONFIG)/chttp2_fullstack_cancel_before_invoke_test bins/$(CONFIG)/chttp2_fullstack_cancel_in_a_vacuum_test bins/$(CONFIG)/chttp2_fullstack_census_simple_request_test bins/$(CONFIG)/chttp2_fullstack_disappearing_server_test bins/$(CONFIG)/chttp2_fullstack_early_server_shutdown_finishes_inflight_calls_test bins/$(CONFIG)/chttp2_fullstack_early_server_shutdown_finishes_tags_test bins/$(CONFIG)/chttp2_fullstack_graceful_server_shutdown_test bins/$(CONFIG)/chttp2_fullstack_invoke_large_request_test bins/$(CONFIG)/chttp2_fullstack_max_concurrent_streams_test bins/$(CONFIG)/chttp2_fullstack_no_op_test bins/$(CONFIG)/chttp2_fullstack_ping_pong_streaming_test bins/$(CONFIG)/chttp2_fullstack_request_response_with_binary_metadata_and_payload_test bins/$(CONFIG)/chttp2_fullstack_request_response_with_metadata_and_payload_test bins/$(CONFIG)/chttp2_fullstack_request_response_with_payload_test bins/$(CONFIG)/chttp2_fullstack_request_response_with_trailing_metadata_and_payload_test bins/$(CONFIG)/chttp2_fullstack_simple_delayed_request_test bins/$(CONFIG)/chttp2_fullstack_simple_request_test bins/$(CONFIG)/chttp2_fullstack_thread_stress_test bins/$(CONFIG)/chttp2_fullstack_writes_done_hangs_with_pending_read_test bins/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_after_accept_test bins/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_after_accept_and_writes_closed_test bins/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_after_invoke_test bins/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_before_invoke_test bins/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_in_a_vacuum_test bins/$(CONFIG)/chttp2_simple_ssl_fullstack_census_simple_request_test bins/$(CONFIG)/chttp2_simple_ssl_fullstack_disappearing_server_test bins/$(CONFIG)/chttp2_simple_ssl_fullstack_early_server_shutdown_finishes_inflight_calls_test bins/$(CONFIG)/chttp2_simple_ssl_fullstack_early_server_shutdown_finishes_tags_test bins/$(CONFIG)/chttp2_simple_ssl_fullstack_graceful_server_shutdown_test bins/$(CONFIG)/chttp2_simple_ssl_fullstack_invoke_large_request_test bins/$(CONFIG)/chttp2_simple_ssl_fullstack_max_concurrent_streams_test bins/$(CONFIG)/chttp2_simple_ssl_fullstack_no_op_test bins/$(CONFIG)/chttp2_simple_ssl_fullstack_ping_pong_streaming_test bins/$(CONFIG)/chttp2_simple_ssl_fullstack_request_response_with_binary_metadata_and_payload_test bins/$(CONFIG)/chttp2_simple_ssl_fullstack_request_response_with_metadata_and_payload_test bins/$(CONFIG)/chttp2_simple_ssl_fullstack_request_response_with_payload_test bins/$(CONFIG)/chttp2_simple_ssl_fullstack_request_response_with_trailing_metadata_and_payload_test bins/$(CONFIG)/chttp2_simple_ssl_fullstack_simple_delayed_request_test bins/$(CONFIG)/chttp2_simple_ssl_fullstack_simple_request_test bins/$(CONFIG)/chttp2_simple_ssl_fullstack_thread_stress_test bins/$(CONFIG)/chttp2_simple_ssl_fullstack_writes_done_hangs_with_pending_read_test bins/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_test bins/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_and_writes_closed_test bins/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_invoke_test bins/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_before_invoke_test bins/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_in_a_vacuum_test bins/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_census_simple_request_test bins/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_disappearing_server_test bins/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_early_server_shutdown_finishes_inflight_calls_test bins/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_early_server_shutdown_finishes_tags_test bins/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_graceful_server_shutdown_test bins/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_invoke_large_request_test bins/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_max_concurrent_streams_test bins/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_no_op_test bins/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_ping_pong_streaming_test bins/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_binary_metadata_and_payload_test bins/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_metadata_and_payload_test bins/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_payload_test bins/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_trailing_metadata_and_payload_test bins/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_simple_delayed_request_test bins/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_simple_request_test bins/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_thread_stress_test bins/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_writes_done_hangs_with_pending_read_test bins/$(CONFIG)/chttp2_socket_pair_cancel_after_accept_test bins/$(CONFIG)/chttp2_socket_pair_cancel_after_accept_and_writes_closed_test bins/$(CONFIG)/chttp2_socket_pair_cancel_after_invoke_test bins/$(CONFIG)/chttp2_socket_pair_cancel_before_invoke_test bins/$(CONFIG)/chttp2_socket_pair_cancel_in_a_vacuum_test bins/$(CONFIG)/chttp2_socket_pair_census_simple_request_test bins/$(CONFIG)/chttp2_socket_pair_disappearing_server_test bins/$(CONFIG)/chttp2_socket_pair_early_server_shutdown_finishes_inflight_calls_test bins/$(CONFIG)/chttp2_socket_pair_early_server_shutdown_finishes_tags_test bins/$(CONFIG)/chttp2_socket_pair_graceful_server_shutdown_test bins/$(CONFIG)/chttp2_socket_pair_invoke_large_request_test bins/$(CONFIG)/chttp2_socket_pair_max_concurrent_streams_test bins/$(CONFIG)/chttp2_socket_pair_no_op_test bins/$(CONFIG)/chttp2_socket_pair_ping_pong_streaming_test bins/$(CONFIG)/chttp2_socket_pair_request_response_with_binary_metadata_and_payload_test bins/$(CONFIG)/chttp2_socket_pair_request_response_with_metadata_and_payload_test bins/$(CONFIG)/chttp2_socket_pair_request_response_with_payload_test bins/$(CONFIG)/chttp2_socket_pair_request_response_with_trailing_metadata_and_payload_test bins/$(CONFIG)/chttp2_socket_pair_simple_delayed_request_test bins/$(CONFIG)/chttp2_socket_pair_simple_request_test bins/$(CONFIG)/chttp2_socket_pair_thread_stress_test bins/$(CONFIG)/chttp2_socket_pair_writes_done_hangs_with_pending_read_test bins/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_after_accept_test bins/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_after_accept_and_writes_closed_test bins/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_after_invoke_test bins/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_before_invoke_test bins/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_in_a_vacuum_test bins/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_census_simple_request_test bins/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_disappearing_server_test bins/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_early_server_shutdown_finishes_inflight_calls_test bins/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_early_server_shutdown_finishes_tags_test bins/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_graceful_server_shutdown_test bins/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_invoke_large_request_test bins/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_max_concurrent_streams_test bins/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_no_op_test bins/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_ping_pong_streaming_test bins/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_binary_metadata_and_payload_test bins/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_metadata_and_payload_test bins/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_payload_test bins/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_trailing_metadata_and_payload_test bins/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_simple_delayed_request_test bins/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_simple_request_test bins/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_thread_stress_test bins/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_writes_done_hangs_with_pending_read_test
 
 buildtests_cxx: privatelibs_cxx bins/$(CONFIG)/channel_arguments_test bins/$(CONFIG)/credentials_test bins/$(CONFIG)/end2end_test bins/$(CONFIG)/interop_client bins/$(CONFIG)/interop_server bins/$(CONFIG)/tips_client bins/$(CONFIG)/tips_client_test bins/$(CONFIG)/qps_client bins/$(CONFIG)/qps_server bins/$(CONFIG)/status_test bins/$(CONFIG)/sync_client_async_server_test bins/$(CONFIG)/thread_pool_test
 
@@ -696,6 +698,8 @@ test_c: buildtests_c
 	$(Q) ./bins/$(CONFIG)/timeout_encoding_test || ( echo test timeout_encoding_test failed ; exit 1 )
 	$(E) "[RUN]     Testing transport_metadata_test"
 	$(Q) ./bins/$(CONFIG)/transport_metadata_test || ( echo test transport_metadata_test failed ; exit 1 )
+	$(E) "[RUN]     Testing json_test"
+	$(Q) ./bins/$(CONFIG)/json_test || ( echo test json_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_fake_security_cancel_after_accept_test"
 	$(Q) ./bins/$(CONFIG)/chttp2_fake_security_cancel_after_accept_test || ( echo test chttp2_fake_security_cancel_after_accept_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_fake_security_cancel_after_accept_and_writes_closed_test"
@@ -5372,6 +5376,68 @@ endif
 endif
 
 
+JSON_TEST_SRC = \
+    test/core/json/json_test.c \
+
+JSON_TEST_OBJS = $(addprefix objs/$(CONFIG)/, $(addsuffix .o, $(basename $(JSON_TEST_SRC))))
+
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL with ALPN.
+
+bins/$(CONFIG)/json_test: openssl_dep_error
+
+else
+
+bins/$(CONFIG)/json_test: $(JSON_TEST_OBJS) libs/$(CONFIG)/libgrpc_test_util.a libs/$(CONFIG)/libgrpc.a libs/$(CONFIG)/libgpr_test_util.a libs/$(CONFIG)/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LD) $(LDFLAGS) $(JSON_TEST_OBJS) libs/$(CONFIG)/libgrpc_test_util.a libs/$(CONFIG)/libgrpc.a libs/$(CONFIG)/libgpr_test_util.a libs/$(CONFIG)/libgpr.a $(LDLIBS) $(LDLIBS_SECURE) -o bins/$(CONFIG)/json_test
+
+endif
+
+objs/$(CONFIG)/test/core/json/json_test.o:  libs/$(CONFIG)/libgrpc_test_util.a libs/$(CONFIG)/libgrpc.a libs/$(CONFIG)/libgpr_test_util.a libs/$(CONFIG)/libgpr.a
+
+deps_json_test: $(JSON_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(JSON_TEST_OBJS:.o=.dep)
+endif
+endif
+
+
+JSON_REWRITE_SRC = \
+    test/core/json/json_rewrite.c \
+
+JSON_REWRITE_OBJS = $(addprefix objs/$(CONFIG)/, $(addsuffix .o, $(basename $(JSON_REWRITE_SRC))))
+
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL with ALPN.
+
+bins/$(CONFIG)/json_rewrite: openssl_dep_error
+
+else
+
+bins/$(CONFIG)/json_rewrite: $(JSON_REWRITE_OBJS) libs/$(CONFIG)/libgrpc_test_util.a libs/$(CONFIG)/libgrpc.a libs/$(CONFIG)/libgpr_test_util.a libs/$(CONFIG)/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LD) $(LDFLAGS) $(JSON_REWRITE_OBJS) libs/$(CONFIG)/libgrpc_test_util.a libs/$(CONFIG)/libgrpc.a libs/$(CONFIG)/libgpr_test_util.a libs/$(CONFIG)/libgpr.a $(LDLIBS) $(LDLIBS_SECURE) -o bins/$(CONFIG)/json_rewrite
+
+endif
+
+objs/$(CONFIG)/test/core/json/json_rewrite.o:  libs/$(CONFIG)/libgrpc_test_util.a libs/$(CONFIG)/libgrpc.a libs/$(CONFIG)/libgpr_test_util.a libs/$(CONFIG)/libgpr.a
+
+deps_json_rewrite: $(JSON_REWRITE_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(JSON_REWRITE_OBJS:.o=.dep)
+endif
+endif
+
+
 CHANNEL_ARGUMENTS_TEST_SRC = \
     test/cpp/client/channel_arguments_test.cc \
 
diff --git a/build.json b/build.json
index c2f44efc17200503b82cab8da4988df5af768c78..c501c12b5852812a17d7d1b0be08e9e7060e21a0 100644
--- a/build.json
+++ b/build.json
@@ -1422,6 +1422,35 @@
         "gpr"
       ]
     },
+    {
+      "name": "json_test",
+      "build": "test",
+      "language": "c",
+      "src": [
+        "test/core/json/json_test.c"
+      ],
+      "deps": [
+        "grpc_test_util",
+        "grpc",
+        "gpr_test_util",
+        "gpr"
+      ]
+    },
+    {
+      "name": "json_rewrite",
+      "build": "test",
+      "language": "c",
+      "src": [
+        "test/core/json/json_rewrite.c"
+      ],
+      "deps": [
+        "grpc_test_util",
+        "grpc",
+        "gpr_test_util",
+        "gpr"
+      ],
+      "run": false
+    },
     {
       "name": "channel_arguments_test",
       "build": "test",
diff --git a/src/core/json/json_reader.c b/src/core/json/json_reader.c
index 304da2a26b74b6fced931bfa8b7e6900995b10bf..75aa87eb03c749a6a44cdff512e31d16d8bdd69e 100644
--- a/src/core/json/json_reader.c
+++ b/src/core/json/json_reader.c
@@ -323,6 +323,7 @@ grpc_json_reader_status grpc_json_reader_run(grpc_json_reader* reader) {
                 break;
 
               case '0':
+                json_reader_string_add_char(reader, c);
                 reader->state = GRPC_JSON_STATE_VALUE_NUMBER_ZERO;
                 break;
 
@@ -454,7 +455,7 @@ grpc_json_reader_status grpc_json_reader_run(grpc_json_reader* reader) {
                 }
                 break;
               default:
-                return GRPC_JSON_PARSE_ERROR;
+                return GRPC_JSON_INTERNAL_ERROR;
             }
             break;
 
@@ -472,6 +473,10 @@ grpc_json_reader_status grpc_json_reader_run(grpc_json_reader* reader) {
               case '8':
               case '9':
                 break;
+              case 'e':
+              case 'E':
+                reader->state = GRPC_JSON_STATE_VALUE_NUMBER_E;
+                break;
               case '.':
                 reader->state = GRPC_JSON_STATE_VALUE_NUMBER_DOT;
                 break;
@@ -549,6 +554,7 @@ grpc_json_reader_status grpc_json_reader_run(grpc_json_reader* reader) {
               default:
                 return GRPC_JSON_PARSE_ERROR;
             }
+            break;
 
           case GRPC_JSON_STATE_VALUE_NUMBER_EPM:
             json_reader_string_add_char(reader, c);
@@ -567,6 +573,7 @@ grpc_json_reader_status grpc_json_reader_run(grpc_json_reader* reader) {
               default:
                 return GRPC_JSON_PARSE_ERROR;
             }
+            break;
 
           case GRPC_JSON_STATE_VALUE_TRUE_R:
             if (c != 'r') return GRPC_JSON_PARSE_ERROR;
diff --git a/src/core/json/json_string.c b/src/core/json/json_string.c
index d016f07c5a5ad605393f6b9ca7951f94d3d5e108..d29e9e30e8211dfb0bbf28e46dea294ec5221f52 100644
--- a/src/core/json/json_string.c
+++ b/src/core/json/json_string.c
@@ -56,10 +56,10 @@ typedef struct {
   grpc_json* top;
   grpc_json* current_container;
   grpc_json* current_value;
-  char* input;
-  char* key;
-  char* string;
-  char* string_ptr;
+  gpr_uint8* input;
+  gpr_uint8* key;
+  gpr_uint8* string;
+  gpr_uint8* string_ptr;
   size_t remaining_input;
 } json_reader_userdata;
 
@@ -201,7 +201,7 @@ static grpc_json* json_create_and_link(void* userdata,
       json->parent->child = json;
     }
     if (json->parent->type == GRPC_JSON_OBJECT) {
-      json->key = state->key;
+      json->key = (char*) state->key;
     }
   }
   if (!state->top) {
@@ -261,13 +261,13 @@ static void json_reader_set_key(void* userdata) {
 static void json_reader_set_string(void* userdata) {
   json_reader_userdata* state = userdata;
   grpc_json* json = json_create_and_link(userdata, GRPC_JSON_STRING);
-  json->value = state->string;
+  json->value = (char*) state->string;
 }
 
 static int json_reader_set_number(void* userdata) {
   json_reader_userdata* state = userdata;
   grpc_json* json = json_create_and_link(userdata, GRPC_JSON_NUMBER);
-  json->value = state->string;
+  json->value = (char*) state->string;
   return 1;
 }
 
@@ -312,7 +312,7 @@ grpc_json* grpc_json_parse_string_with_len(char* input, size_t size) {
 
   state.top = state.current_container = state.current_value = NULL;
   state.string = state.key = NULL;
-  state.string_ptr = state.input = input;
+  state.string_ptr = state.input = (gpr_uint8*) input;
   state.remaining_input = size;
   grpc_json_reader_init(&reader, &reader_vtable, &state);
 
diff --git a/src/core/json/json_writer.c b/src/core/json/json_writer.c
index 5e7b107a03657ff5fd54794284887120f98451bb..63c86ac00852b8241ae1610b5b4285b55a62f9c1 100644
--- a/src/core/json/json_writer.c
+++ b/src/core/json/json_writer.c
@@ -121,22 +121,21 @@ static void json_writer_escape_string(grpc_json_writer* writer,
       if ((c == '\\') || (c == '"')) json_writer_output_char(writer, '\\');
       json_writer_output_char(writer, c);
     } else if (c < 32) {
-      json_writer_output_char(writer, '\\');
       switch (c) {
         case '\b':
-          json_writer_output_char(writer, 'b');
+          json_writer_output_string_with_len(writer, "\\b", 2);
           break;
         case '\f':
-          json_writer_output_char(writer, 'f');
+          json_writer_output_string_with_len(writer, "\\f", 2);
           break;
         case '\n':
-          json_writer_output_char(writer, 'n');
+          json_writer_output_string_with_len(writer, "\\n", 2);
           break;
         case '\r':
-          json_writer_output_char(writer, 'r');
+          json_writer_output_string_with_len(writer, "\\r", 2);
           break;
         case '\t':
-          json_writer_output_char(writer, 't');
+          json_writer_output_string_with_len(writer, "\\t", 2);
           break;
         default:
           json_writer_escape_utf16(writer, c);
@@ -194,7 +193,7 @@ static void json_writer_escape_string(grpc_json_writer* writer,
          */
         utf32 -= 0x10000;
         json_writer_escape_utf16(writer, 0xd800 | (utf32 >> 10));
-        json_writer_escape_utf16(writer, 0xdc00 | (utf32 && 0x3ff));
+        json_writer_escape_utf16(writer, 0xdc00 | (utf32 & 0x3ff));
       } else {
         json_writer_escape_utf16(writer, utf32);
       }
diff --git a/test/core/json/json_rewrite.c b/test/core/json/json_rewrite.c
new file mode 100644
index 0000000000000000000000000000000000000000..f29f124e301b0e320669985be27f614a54f0c9e9
--- /dev/null
+++ b/test/core/json/json_rewrite.c
@@ -0,0 +1,261 @@
+/*
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+
+#include <grpc/support/cmdline.h>
+#include <grpc/support/alloc.h>
+
+#include "src/core/json/json_reader.h"
+#include "src/core/json/json_writer.h"
+
+typedef struct json_writer_userdata {
+  FILE* out;
+} json_writer_userdata;
+
+typedef struct stacked_container {
+  grpc_json_type type;
+  struct stacked_container* next;
+} stacked_container;
+
+typedef struct json_reader_userdata {
+  FILE* in;
+  grpc_json_writer* writer;
+  char* scratchpad;
+  char* ptr;
+  size_t free_space;
+  size_t allocated;
+  size_t string_len;
+  stacked_container* top;
+} json_reader_userdata;
+
+static void json_writer_output_char(void* userdata, char c) {
+  json_writer_userdata* state = userdata;
+  fputc(c, state->out);
+}
+
+static void json_writer_output_string(void* userdata, const char* str) {
+  json_writer_userdata* state = userdata;
+  fputs(str, state->out);
+}
+
+static void json_writer_output_string_with_len(void* userdata, const char* str,
+                                               size_t len) {
+  json_writer_userdata* state = userdata;
+  fwrite(str, len, 1, state->out);
+}
+
+grpc_json_writer_vtable writer_vtable = {
+  json_writer_output_char,
+  json_writer_output_string,
+  json_writer_output_string_with_len
+};
+
+static void check_string(json_reader_userdata* state, size_t needed) {
+  if (state->free_space >= needed) return;
+  needed -= state->free_space;
+  needed = (needed + 0xff) & ~0xff;
+  state->scratchpad = gpr_realloc(state->scratchpad, state->allocated + needed);
+  state->free_space += needed;
+  state->allocated += needed;
+}
+
+static void json_reader_string_clear(void* userdata) {
+  json_reader_userdata* state = userdata;
+  state->free_space = state->allocated;
+  state->string_len = 0;
+}
+
+static void json_reader_string_add_char(void* userdata, gpr_uint32 c) {
+  json_reader_userdata* state = userdata;
+  check_string(state, 1);
+  state->scratchpad[state->string_len++] = c;
+}
+
+static void json_reader_string_add_utf32(void* userdata, gpr_uint32 c) {
+  if (c <= 0x7f) {
+    json_reader_string_add_char(userdata, c);
+  } else if (c <= 0x7ff) {
+    int b1 = 0xc0 | ((c >> 6) & 0x1f);
+    int b2 = 0x80 | (c & 0x3f);
+    json_reader_string_add_char(userdata, b1);
+    json_reader_string_add_char(userdata, b2);
+  } else if (c <= 0xffff) {
+    int b1 = 0xe0 | ((c >> 12) & 0x0f);
+    int b2 = 0x80 | ((c >> 6) & 0x3f);
+    int b3 = 0x80 | (c & 0x3f);
+    json_reader_string_add_char(userdata, b1);
+    json_reader_string_add_char(userdata, b2);
+    json_reader_string_add_char(userdata, 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);
+    json_reader_string_add_char(userdata, b1);
+    json_reader_string_add_char(userdata, b2);
+    json_reader_string_add_char(userdata, b3);
+    json_reader_string_add_char(userdata, b4);
+  }
+}
+
+static gpr_uint32 json_reader_read_char(void* userdata) {
+  gpr_uint32 r;
+  json_reader_userdata* state = userdata;
+
+  r = fgetc(state->in);
+  if (r == EOF) r = GRPC_JSON_READ_CHAR_EOF;
+  return r;
+}
+
+static void json_reader_container_begins(void* userdata, grpc_json_type type) {
+  json_reader_userdata* state = userdata;
+  stacked_container* container = gpr_malloc(sizeof(stacked_container));
+
+  container->type = type;
+  container->next = state->top;
+  state->top = container;
+
+  grpc_json_writer_container_begins(state->writer, type);
+}
+
+static grpc_json_type json_reader_container_ends(void* userdata) {
+  json_reader_userdata* state = userdata;
+  stacked_container* container = state->top;
+
+  grpc_json_writer_container_ends(state->writer, container->type);
+  state->top = container->next;
+  gpr_free(container);
+  return state->top ? state->top->type : GRPC_JSON_TOP_LEVEL;
+}
+
+static void json_reader_set_key(void* userdata) {
+  json_reader_userdata* state = userdata;
+  json_reader_string_add_char(userdata, 0);
+
+  grpc_json_writer_object_key(state->writer, state->scratchpad);
+}
+
+static void json_reader_set_string(void* userdata) {
+  json_reader_userdata* state = userdata;
+  json_reader_string_add_char(userdata, 0);
+
+  grpc_json_writer_value_string(state->writer, state->scratchpad);
+}
+
+static int json_reader_set_number(void* userdata) {
+  json_reader_userdata* state = userdata;
+
+  grpc_json_writer_value_raw_with_len(state->writer, state->scratchpad,
+                                      state->string_len - 1);
+
+  return 1;
+}
+
+static void json_reader_set_true(void* userdata) {
+  json_reader_userdata* state = userdata;
+
+  grpc_json_writer_value_raw_with_len(state->writer, "true", 4);
+}
+
+static void json_reader_set_false(void* userdata) {
+  json_reader_userdata* state = userdata;
+
+  grpc_json_writer_value_raw_with_len(state->writer, "false", 5);
+}
+
+static void json_reader_set_null(void* userdata) {
+  json_reader_userdata* state = userdata;
+
+  grpc_json_writer_value_raw_with_len(state->writer, "null", 4);
+}
+
+static grpc_json_reader_vtable reader_vtable = {
+  json_reader_string_clear,
+  json_reader_string_add_char,
+  json_reader_string_add_utf32,
+  json_reader_read_char,
+  json_reader_container_begins,
+  json_reader_container_ends,
+  json_reader_set_key,
+  json_reader_set_string,
+  json_reader_set_number,
+  json_reader_set_true,
+  json_reader_set_false,
+  json_reader_set_null
+};
+
+int rewrite(FILE* in, FILE* out, int indent) {
+  grpc_json_writer writer;
+  grpc_json_reader reader;
+  grpc_json_reader_status status;
+  json_writer_userdata writer_user;
+  json_reader_userdata reader_user;
+
+  reader_user.writer = &writer;
+  reader_user.in = in;
+  reader_user.top = NULL;
+  reader_user.scratchpad = NULL;
+  reader_user.string_len = 0;
+  reader_user.free_space = 0;
+  reader_user.allocated = 0;
+
+  writer_user.out = out;
+
+  grpc_json_writer_init(&writer, indent, &writer_vtable, &writer_user);
+  grpc_json_reader_init(&reader, &reader_vtable, &reader_user);
+
+  status = grpc_json_reader_run(&reader);
+
+  free(reader_user.scratchpad);
+  while (reader_user.top) {
+    stacked_container* container = reader_user.top;
+    reader_user.top = container->next;
+    free(container);
+  }
+
+  return status == GRPC_JSON_DONE;
+}
+
+int main(int argc, char** argv) {
+  int indent = 2;
+  gpr_cmdline* cl;
+
+  cl = gpr_cmdline_create(NULL);
+  gpr_cmdline_add_int(cl, "indent", NULL, &indent);
+  gpr_cmdline_parse(cl, argc, argv);
+  gpr_cmdline_destroy(cl);
+
+  return rewrite(stdin, stdout, indent) ? 0 : 1;
+}
diff --git a/test/core/json/json_test.c b/test/core/json/json_test.c
new file mode 100644
index 0000000000000000000000000000000000000000..582ad181aa6b6936c063353fd6718e7da0a5e5bb
--- /dev/null
+++ b/test/core/json/json_test.c
@@ -0,0 +1,124 @@
+/*
+ *
+ * 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/useful.h>
+#include <grpc/support/log.h>
+#include "src/core/json/json.h"
+#include "src/core/support/string.h"
+
+#include "test/core/util/test_config.h"
+
+typedef struct testing_pair {
+  const char* input;
+  const char* output;
+} testing_pair;
+
+static testing_pair testing_pairs[] = {
+  { " \"a\" ", "\"a\"" },
+  { "\"\\u0020\\\\\\u0010\\u000a\\u000D\"", "\" \\\\\\u0010\\n\\r\"" },
+  { "\"𝄞\"", "\"\\ud834\\udd1e\"" },
+  { "\"\\ud834\\udd1e\"", "\"\\ud834\\udd1e\"" },
+  { "\"\xf0\x9d\x84\x9e\"", "\"\\ud834\\udd1e\"" },
+  { " [ [ ] , { } , [ ] ] ", "[[],{},[]]", },
+  { " { \"\\na , b\": [] } ", "{\"\\na , b\":[]}" },
+  { "\"abc\xf0\x9d\x24\"", "\"abc\"" },
+  { "[0, 42 , 0.0123, 123.456]", "[0,42,0.0123,123.456]"},
+  { "[1e4,-53.235e-31, 0.3e+3]", "[1e4,-53.235e-31,0.3e+3]" },
+  { "[true, false, null]", "[true,false,null]" },
+  { "\\", NULL },
+  { "\"\\x", NULL },
+  { "\"\\u123x", NULL },
+  { "\"\\ud834f", NULL },
+  { "\"\\udd1ef", NULL },
+  { "\"\\ud834\\ud834\"", NULL },
+  { "\"\\ud834\\u1234\"", NULL },
+  { "\"\n\"", NULL },
+  { "", NULL },
+  { "{},", NULL },
+  { "{}}", NULL },
+  { "[]]", NULL },
+  { "{,}", NULL },
+  { "[1,2,3,4,]", NULL },
+  { "[\"x\":0]", NULL },
+  { "1.", NULL },
+  { "1e", NULL },
+  { ".12", NULL },
+  { "1.x", NULL },
+  { "1.12x", NULL },
+  { "1ex", NULL },
+  { "1e12x", NULL },
+  { ".12x", NULL },
+  { "000", NULL },
+};
+
+static void test_pairs() {
+  int i;
+
+  for (i = 0; i < GPR_ARRAY_SIZE(testing_pairs); i++) {
+    testing_pair* pair = testing_pairs + i;
+    char* scratchpad = gpr_strdup(pair->input);
+    grpc_json* json;
+
+    gpr_log(GPR_INFO, "parsing string %i - should %s", i,
+            pair->output ? "succeed" : "fail");
+    json = grpc_json_parse_string(scratchpad);
+
+    if (pair->output) {
+      char* output;
+
+      GPR_ASSERT(json);
+      output = grpc_json_dump_to_string(json, 0);
+      GPR_ASSERT(output);
+      gpr_log(GPR_INFO, "succeeded with output = %s", output);
+      GPR_ASSERT(strcmp(output, pair->output) == 0);
+
+      grpc_json_destroy(json);
+      gpr_free(output);
+    } else {
+      gpr_log(GPR_INFO, "failed");
+      GPR_ASSERT(!json);
+    }
+
+    free(scratchpad);
+  }
+}
+
+int main(int argc, char **argv) {
+  grpc_test_init(argc, argv);
+  test_pairs();
+  gpr_log(GPR_INFO, "json_test success");
+  return 0;
+}
diff --git a/test/core/json/rewrite_test_input.json b/test/core/json/rewrite_test_input.json
new file mode 100644
index 0000000000000000000000000000000000000000..568891474f7853ae4785276c6095bb21a5ca4e85
--- /dev/null
+++ b/test/core/json/rewrite_test_input.json
@@ -0,0 +1,203 @@
+{
+"unicode, escape and empty test": { "a\tb": "\u00eb", "empty": [{},[],{}] },
+"some more unicode tests": {
+  "typical utf-8 input (plane 0)": "ßâñć⇒",
+  "atypical utf-8 input (plane 1)": "𝄞"
+},
+
+"whitespace test": { "trying"   :  
+"to"  
+  ,
+  
+  "break"
+  :
+  "the"  , 
+  "parser": "a bit" }  ,  
+
+"#": "All these examples are from http://json.org/example",
+"test1":
+{
+    "glossary": {
+        "title": "example glossary",
+        "GlossDiv": {
+            "title": "S",
+            "GlossList": {
+                "GlossEntry": {
+                    "ID": "SGML",
+                    "SortAs": "SGML",
+                    "GlossTerm": "Standard Generalized Markup Language",
+                    "Acronym": "SGML",
+                    "Abbrev": "ISO 8879:1986",
+                    "GlossDef": {
+                        "para": "A meta-markup language, used to create markup languages such as DocBook.",
+                        "GlossSeeAlso": ["GML", "XML"]
+                    },
+                    "GlossSee": "markup"
+                }
+            }
+        }
+    }
+},
+
+"test2":
+{"menu": {
+  "id": "file",
+  "value": "File",
+  "popup": {
+    "menuitem": [
+      {"value": "New", "onclick": "CreateNewDoc()"},
+      {"value": "Open", "onclick": "OpenDoc()"},
+      {"value": "Close", "onclick": "CloseDoc()"}
+    ]
+  }
+}},
+
+"test3":
+{"widget": {
+    "debug": "on",
+    "window": {
+        "title": "Sample Konfabulator Widget",
+        "name": "main_window",
+        "width": 500,
+        "height": 500
+    },
+    "image": { 
+        "src": "Images/Sun.png",
+        "name": "sun1",
+        "hOffset": 250,
+        "vOffset": 250,
+        "alignment": "center"
+    },
+    "text": {
+        "data": "Click Here",
+        "size": 36,
+        "style": "bold",
+        "name": "text1",
+        "hOffset": 250,
+        "vOffset": 100,
+        "alignment": "center",
+        "onMouseUp": "sun1.opacity = (sun1.opacity / 100) * 90;"
+    }
+}},
+
+"test4":
+{"web-app": {
+  "servlet": [   
+    {
+      "servlet-name": "cofaxCDS",
+      "servlet-class": "org.cofax.cds.CDSServlet",
+      "init-param": {
+        "configGlossary:installationAt": "Philadelphia, PA",
+        "configGlossary:adminEmail": "ksm@pobox.com",
+        "configGlossary:poweredBy": "Cofax",
+        "configGlossary:poweredByIcon": "/images/cofax.gif",
+        "configGlossary:staticPath": "/content/static",
+        "templateProcessorClass": "org.cofax.WysiwygTemplate",
+        "templateLoaderClass": "org.cofax.FilesTemplateLoader",
+        "templatePath": "templates",
+        "templateOverridePath": "",
+        "defaultListTemplate": "listTemplate.htm",
+        "defaultFileTemplate": "articleTemplate.htm",
+        "useJSP": false,
+        "jspListTemplate": "listTemplate.jsp",
+        "jspFileTemplate": "articleTemplate.jsp",
+        "cachePackageTagsTrack": 200,
+        "cachePackageTagsStore": 200,
+        "cachePackageTagsRefresh": 60,
+        "cacheTemplatesTrack": 100,
+        "cacheTemplatesStore": 50,
+        "cacheTemplatesRefresh": 15,
+        "cachePagesTrack": 200,
+        "cachePagesStore": 100,
+        "cachePagesRefresh": 10,
+        "cachePagesDirtyRead": 10,
+        "searchEngineListTemplate": "forSearchEnginesList.htm",
+        "searchEngineFileTemplate": "forSearchEngines.htm",
+        "searchEngineRobotsDb": "WEB-INF/robots.db",
+        "useDataStore": true,
+        "dataStoreClass": "org.cofax.SqlDataStore",
+        "redirectionClass": "org.cofax.SqlRedirection",
+        "dataStoreName": "cofax",
+        "dataStoreDriver": "com.microsoft.jdbc.sqlserver.SQLServerDriver",
+        "dataStoreUrl": "jdbc:microsoft:sqlserver://LOCALHOST:1433;DatabaseName=goon",
+        "dataStoreUser": "sa",
+        "dataStorePassword": "dataStoreTestQuery",
+        "dataStoreTestQuery": "SET NOCOUNT ON;select test='test';",
+        "dataStoreLogFile": "/usr/local/tomcat/logs/datastore.log",
+        "dataStoreInitConns": 10,
+        "dataStoreMaxConns": 100,
+        "dataStoreConnUsageLimit": 100,
+        "dataStoreLogLevel": "debug",
+        "maxUrlLength": 500}},
+    {
+      "servlet-name": "cofaxEmail",
+      "servlet-class": "org.cofax.cds.EmailServlet",
+      "init-param": {
+      "mailHost": "mail1",
+      "mailHostOverride": "mail2"}},
+    {
+      "servlet-name": "cofaxAdmin",
+      "servlet-class": "org.cofax.cds.AdminServlet"},
+ 
+    {
+      "servlet-name": "fileServlet",
+      "servlet-class": "org.cofax.cds.FileServlet"},
+    {
+      "servlet-name": "cofaxTools",
+      "servlet-class": "org.cofax.cms.CofaxToolsServlet",
+      "init-param": {
+        "templatePath": "toolstemplates/",
+        "log": 1,
+        "logLocation": "/usr/local/tomcat/logs/CofaxTools.log",
+        "logMaxSize": "",
+        "dataLog": 1,
+        "dataLogLocation": "/usr/local/tomcat/logs/dataLog.log",
+        "dataLogMaxSize": "",
+        "removePageCache": "/content/admin/remove?cache=pages&id=",
+        "removeTemplateCache": "/content/admin/remove?cache=templates&id=",
+        "fileTransferFolder": "/usr/local/tomcat/webapps/content/fileTransferFolder",
+        "lookInContext": 1,
+        "adminGroupID": 4,
+        "betaServer": true}}],
+  "servlet-mapping": {
+    "cofaxCDS": "/",
+    "cofaxEmail": "/cofaxutil/aemail/*",
+    "cofaxAdmin": "/admin/*",
+    "fileServlet": "/static/*",
+    "cofaxTools": "/tools/*"},
+ 
+  "taglib": {
+    "taglib-uri": "cofax.tld",
+    "taglib-location": "/WEB-INF/tlds/cofax.tld"}}},
+
+"test5":
+{"menu": {
+    "header": "SVG Viewer",
+    "items": [
+        {"id": "Open"},
+        {"id": "OpenNew", "label": "Open New"},
+        null,
+        {"id": "ZoomIn", "label": "Zoom In"},
+        {"id": "ZoomOut", "label": "Zoom Out"},
+        {"id": "OriginalView", "label": "Original View"},
+        null,
+        {"id": "Quality"},
+        {"id": "Pause"},
+        {"id": "Mute"},
+        null,
+        {"id": "Find", "label": "Find..."},
+        {"id": "FindAgain", "label": "Find Again"},
+        {"id": "Copy"},
+        {"id": "CopyAgain", "label": "Copy Again"},
+        {"id": "CopySVG", "label": "Copy SVG"},
+        {"id": "ViewSVG", "label": "View SVG"},
+        {"id": "ViewSource", "label": "View Source"},
+        {"id": "SaveAs", "label": "Save As"},
+        null,
+        {"id": "Help"},
+        {"id": "About", "label": "About Adobe CVG Viewer..."}
+    ]
+}}
+
+
+}
diff --git a/test/core/json/rewrite_test_output_condensed.json b/test/core/json/rewrite_test_output_condensed.json
new file mode 100644
index 0000000000000000000000000000000000000000..e32603f47073ac60e5804eb0f8f4c41bdd055d67
--- /dev/null
+++ b/test/core/json/rewrite_test_output_condensed.json
@@ -0,0 +1 @@
+{"unicode, escape and empty test":{"a\tb":"\u00eb","empty":[{},[],{}]},"some more unicode tests":{"typical utf-8 input (plane 0)":"\u00df\u00e2\u00f1\u0107\u21d2","atypical utf-8 input (plane 1)":"\ud834\udd1e"},"whitespace test":{"trying":"to","break":"the","parser":"a bit"},"#":"All these examples are from http://json.org/example","test1":{"glossary":{"title":"example glossary","GlossDiv":{"title":"S","GlossList":{"GlossEntry":{"ID":"SGML","SortAs":"SGML","GlossTerm":"Standard Generalized Markup Language","Acronym":"SGML","Abbrev":"ISO 8879:1986","GlossDef":{"para":"A meta-markup language, used to create markup languages such as DocBook.","GlossSeeAlso":["GML","XML"]},"GlossSee":"markup"}}}}},"test2":{"menu":{"id":"file","value":"File","popup":{"menuitem":[{"value":"New","onclick":"CreateNewDoc()"},{"value":"Open","onclick":"OpenDoc()"},{"value":"Close","onclick":"CloseDoc()"}]}}},"test3":{"widget":{"debug":"on","window":{"title":"Sample Konfabulator Widget","name":"main_window","width":50,"height":50},"image":{"src":"Images/Sun.png","name":"sun1","hOffset":25,"vOffset":25,"alignment":"center"},"text":{"data":"Click Here","size":3,"style":"bold","name":"text1","hOffset":25,"vOffset":10,"alignment":"center","onMouseUp":"sun1.opacity = (sun1.opacity / 100) * 90;"}}},"test4":{"web-app":{"servlet":[{"servlet-name":"cofaxCDS","servlet-class":"org.cofax.cds.CDSServlet","init-param":{"configGlossary:installationAt":"Philadelphia, PA","configGlossary:adminEmail":"ksm@pobox.com","configGlossary:poweredBy":"Cofax","configGlossary:poweredByIcon":"/images/cofax.gif","configGlossary:staticPath":"/content/static","templateProcessorClass":"org.cofax.WysiwygTemplate","templateLoaderClass":"org.cofax.FilesTemplateLoader","templatePath":"templates","templateOverridePath":"","defaultListTemplate":"listTemplate.htm","defaultFileTemplate":"articleTemplate.htm","useJSP":false,"jspListTemplate":"listTemplate.jsp","jspFileTemplate":"articleTemplate.jsp","cachePackageTagsTrack":20,"cachePackageTagsStore":20,"cachePackageTagsRefresh":6,"cacheTemplatesTrack":10,"cacheTemplatesStore":5,"cacheTemplatesRefresh":1,"cachePagesTrack":20,"cachePagesStore":10,"cachePagesRefresh":1,"cachePagesDirtyRead":1,"searchEngineListTemplate":"forSearchEnginesList.htm","searchEngineFileTemplate":"forSearchEngines.htm","searchEngineRobotsDb":"WEB-INF/robots.db","useDataStore":true,"dataStoreClass":"org.cofax.SqlDataStore","redirectionClass":"org.cofax.SqlRedirection","dataStoreName":"cofax","dataStoreDriver":"com.microsoft.jdbc.sqlserver.SQLServerDriver","dataStoreUrl":"jdbc:microsoft:sqlserver://LOCALHOST:1433;DatabaseName=goon","dataStoreUser":"sa","dataStorePassword":"dataStoreTestQuery","dataStoreTestQuery":"SET NOCOUNT ON;select test='test';","dataStoreLogFile":"/usr/local/tomcat/logs/datastore.log","dataStoreInitConns":1,"dataStoreMaxConns":10,"dataStoreConnUsageLimit":10,"dataStoreLogLevel":"debug","maxUrlLength":50}},{"servlet-name":"cofaxEmail","servlet-class":"org.cofax.cds.EmailServlet","init-param":{"mailHost":"mail1","mailHostOverride":"mail2"}},{"servlet-name":"cofaxAdmin","servlet-class":"org.cofax.cds.AdminServlet"},{"servlet-name":"fileServlet","servlet-class":"org.cofax.cds.FileServlet"},{"servlet-name":"cofaxTools","servlet-class":"org.cofax.cms.CofaxToolsServlet","init-param":{"templatePath":"toolstemplates/","log":,"logLocation":"/usr/local/tomcat/logs/CofaxTools.log","logMaxSize":"","dataLog":,"dataLogLocation":"/usr/local/tomcat/logs/dataLog.log","dataLogMaxSize":"","removePageCache":"/content/admin/remove?cache=pages&id=","removeTemplateCache":"/content/admin/remove?cache=templates&id=","fileTransferFolder":"/usr/local/tomcat/webapps/content/fileTransferFolder","lookInContext":,"adminGroupID":,"betaServer":true}}],"servlet-mapping":{"cofaxCDS":"/","cofaxEmail":"/cofaxutil/aemail/*","cofaxAdmin":"/admin/*","fileServlet":"/static/*","cofaxTools":"/tools/*"},"taglib":{"taglib-uri":"cofax.tld","taglib-location":"/WEB-INF/tlds/cofax.tld"}}},"test5":{"menu":{"header":"SVG Viewer","items":[{"id":"Open"},{"id":"OpenNew","label":"Open New"},null,{"id":"ZoomIn","label":"Zoom In"},{"id":"ZoomOut","label":"Zoom Out"},{"id":"OriginalView","label":"Original View"},null,{"id":"Quality"},{"id":"Pause"},{"id":"Mute"},null,{"id":"Find","label":"Find..."},{"id":"FindAgain","label":"Find Again"},{"id":"Copy"},{"id":"CopyAgain","label":"Copy Again"},{"id":"CopySVG","label":"Copy SVG"},{"id":"ViewSVG","label":"View SVG"},{"id":"ViewSource","label":"View Source"},{"id":"SaveAs","label":"Save As"},null,{"id":"Help"},{"id":"About","label":"About Adobe CVG Viewer..."}]}}}
\ No newline at end of file
diff --git a/test/core/json/rewrite_test_output_indented.json b/test/core/json/rewrite_test_output_indented.json
new file mode 100644
index 0000000000000000000000000000000000000000..fdc6d4ca5680358d8ae4c1efd410a0630339e2c6
--- /dev/null
+++ b/test/core/json/rewrite_test_output_indented.json
@@ -0,0 +1,272 @@
+{
+  "unicode, escape and empty test": {
+    "a\tb": "\u00eb",
+    "empty": [
+      {},
+      [],
+      {}
+    ]
+  },
+  "some more unicode tests": {
+    "typical utf-8 input (plane 0)": "\u00df\u00e2\u00f1\u0107\u21d2",
+    "atypical utf-8 input (plane 1)": "\ud834\udd1e"
+  },
+  "whitespace test": {
+    "trying": "to",
+    "break": "the",
+    "parser": "a bit"
+  },
+  "#": "All these examples are from http://json.org/example",
+  "test1": {
+    "glossary": {
+      "title": "example glossary",
+      "GlossDiv": {
+        "title": "S",
+        "GlossList": {
+          "GlossEntry": {
+            "ID": "SGML",
+            "SortAs": "SGML",
+            "GlossTerm": "Standard Generalized Markup Language",
+            "Acronym": "SGML",
+            "Abbrev": "ISO 8879:1986",
+            "GlossDef": {
+              "para": "A meta-markup language, used to create markup languages such as DocBook.",
+              "GlossSeeAlso": [
+                "GML",
+                "XML"
+              ]
+            },
+            "GlossSee": "markup"
+          }
+        }
+      }
+    }
+  },
+  "test2": {
+    "menu": {
+      "id": "file",
+      "value": "File",
+      "popup": {
+        "menuitem": [
+          {
+            "value": "New",
+            "onclick": "CreateNewDoc()"
+          },
+          {
+            "value": "Open",
+            "onclick": "OpenDoc()"
+          },
+          {
+            "value": "Close",
+            "onclick": "CloseDoc()"
+          }
+        ]
+      }
+    }
+  },
+  "test3": {
+    "widget": {
+      "debug": "on",
+      "window": {
+        "title": "Sample Konfabulator Widget",
+        "name": "main_window",
+        "width": 50,
+        "height": 50
+      },
+      "image": {
+        "src": "Images/Sun.png",
+        "name": "sun1",
+        "hOffset": 25,
+        "vOffset": 25,
+        "alignment": "center"
+      },
+      "text": {
+        "data": "Click Here",
+        "size": 3,
+        "style": "bold",
+        "name": "text1",
+        "hOffset": 25,
+        "vOffset": 10,
+        "alignment": "center",
+        "onMouseUp": "sun1.opacity = (sun1.opacity / 100) * 90;"
+      }
+    }
+  },
+  "test4": {
+    "web-app": {
+      "servlet": [
+        {
+          "servlet-name": "cofaxCDS",
+          "servlet-class": "org.cofax.cds.CDSServlet",
+          "init-param": {
+            "configGlossary:installationAt": "Philadelphia, PA",
+            "configGlossary:adminEmail": "ksm@pobox.com",
+            "configGlossary:poweredBy": "Cofax",
+            "configGlossary:poweredByIcon": "/images/cofax.gif",
+            "configGlossary:staticPath": "/content/static",
+            "templateProcessorClass": "org.cofax.WysiwygTemplate",
+            "templateLoaderClass": "org.cofax.FilesTemplateLoader",
+            "templatePath": "templates",
+            "templateOverridePath": "",
+            "defaultListTemplate": "listTemplate.htm",
+            "defaultFileTemplate": "articleTemplate.htm",
+            "useJSP": false,
+            "jspListTemplate": "listTemplate.jsp",
+            "jspFileTemplate": "articleTemplate.jsp",
+            "cachePackageTagsTrack": 20,
+            "cachePackageTagsStore": 20,
+            "cachePackageTagsRefresh": 6,
+            "cacheTemplatesTrack": 10,
+            "cacheTemplatesStore": 5,
+            "cacheTemplatesRefresh": 1,
+            "cachePagesTrack": 20,
+            "cachePagesStore": 10,
+            "cachePagesRefresh": 1,
+            "cachePagesDirtyRead": 1,
+            "searchEngineListTemplate": "forSearchEnginesList.htm",
+            "searchEngineFileTemplate": "forSearchEngines.htm",
+            "searchEngineRobotsDb": "WEB-INF/robots.db",
+            "useDataStore": true,
+            "dataStoreClass": "org.cofax.SqlDataStore",
+            "redirectionClass": "org.cofax.SqlRedirection",
+            "dataStoreName": "cofax",
+            "dataStoreDriver": "com.microsoft.jdbc.sqlserver.SQLServerDriver",
+            "dataStoreUrl": "jdbc:microsoft:sqlserver://LOCALHOST:1433;DatabaseName=goon",
+            "dataStoreUser": "sa",
+            "dataStorePassword": "dataStoreTestQuery",
+            "dataStoreTestQuery": "SET NOCOUNT ON;select test='test';",
+            "dataStoreLogFile": "/usr/local/tomcat/logs/datastore.log",
+            "dataStoreInitConns": 1,
+            "dataStoreMaxConns": 10,
+            "dataStoreConnUsageLimit": 10,
+            "dataStoreLogLevel": "debug",
+            "maxUrlLength": 50
+          }
+        },
+        {
+          "servlet-name": "cofaxEmail",
+          "servlet-class": "org.cofax.cds.EmailServlet",
+          "init-param": {
+            "mailHost": "mail1",
+            "mailHostOverride": "mail2"
+          }
+        },
+        {
+          "servlet-name": "cofaxAdmin",
+          "servlet-class": "org.cofax.cds.AdminServlet"
+        },
+        {
+          "servlet-name": "fileServlet",
+          "servlet-class": "org.cofax.cds.FileServlet"
+        },
+        {
+          "servlet-name": "cofaxTools",
+          "servlet-class": "org.cofax.cms.CofaxToolsServlet",
+          "init-param": {
+            "templatePath": "toolstemplates/",
+            "log": ,
+            "logLocation": "/usr/local/tomcat/logs/CofaxTools.log",
+            "logMaxSize": "",
+            "dataLog": ,
+            "dataLogLocation": "/usr/local/tomcat/logs/dataLog.log",
+            "dataLogMaxSize": "",
+            "removePageCache": "/content/admin/remove?cache=pages&id=",
+            "removeTemplateCache": "/content/admin/remove?cache=templates&id=",
+            "fileTransferFolder": "/usr/local/tomcat/webapps/content/fileTransferFolder",
+            "lookInContext": ,
+            "adminGroupID": ,
+            "betaServer": true
+          }
+        }
+      ],
+      "servlet-mapping": {
+        "cofaxCDS": "/",
+        "cofaxEmail": "/cofaxutil/aemail/*",
+        "cofaxAdmin": "/admin/*",
+        "fileServlet": "/static/*",
+        "cofaxTools": "/tools/*"
+      },
+      "taglib": {
+        "taglib-uri": "cofax.tld",
+        "taglib-location": "/WEB-INF/tlds/cofax.tld"
+      }
+    }
+  },
+  "test5": {
+    "menu": {
+      "header": "SVG Viewer",
+      "items": [
+        {
+          "id": "Open"
+        },
+        {
+          "id": "OpenNew",
+          "label": "Open New"
+        },
+        null,
+        {
+          "id": "ZoomIn",
+          "label": "Zoom In"
+        },
+        {
+          "id": "ZoomOut",
+          "label": "Zoom Out"
+        },
+        {
+          "id": "OriginalView",
+          "label": "Original View"
+        },
+        null,
+        {
+          "id": "Quality"
+        },
+        {
+          "id": "Pause"
+        },
+        {
+          "id": "Mute"
+        },
+        null,
+        {
+          "id": "Find",
+          "label": "Find..."
+        },
+        {
+          "id": "FindAgain",
+          "label": "Find Again"
+        },
+        {
+          "id": "Copy"
+        },
+        {
+          "id": "CopyAgain",
+          "label": "Copy Again"
+        },
+        {
+          "id": "CopySVG",
+          "label": "Copy SVG"
+        },
+        {
+          "id": "ViewSVG",
+          "label": "View SVG"
+        },
+        {
+          "id": "ViewSource",
+          "label": "View Source"
+        },
+        {
+          "id": "SaveAs",
+          "label": "Save As"
+        },
+        null,
+        {
+          "id": "Help"
+        },
+        {
+          "id": "About",
+          "label": "About Adobe CVG Viewer..."
+        }
+      ]
+    }
+  }
+}
\ No newline at end of file
diff --git a/tools/run_tests/tests.json b/tools/run_tests/tests.json
index 90571eaec6c229fe8062e44ca9738b9889c9b2ff..c0a2a52a15bc951dc80cba744687ed3896f88740 100644
--- a/tools/run_tests/tests.json
+++ b/tools/run_tests/tests.json
@@ -249,6 +249,10 @@
     "language": "c", 
     "name": "transport_metadata_test"
   }, 
+  {
+    "language": "c", 
+    "name": "json_test"
+  }, 
   {
     "language": "c++", 
     "name": "channel_arguments_test"