Merge pull request #10609 from makdharma/xcodebuild_cmdline

add cmdline arg for ObjC interop tests. Add objc to interop_tests.py
diff --git a/.gitignore b/.gitignore
index ad3ec64..5e38f5f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -118,3 +118,13 @@
 
 # ctags file
 tags
+
+# perf data
+perf.data
+perf.data.old
+
+# bm_diff
+bm_diff_new/
+bm_diff_old/
+bm_*.json
+
diff --git a/BUILD b/BUILD
index ab4c1cf..542c43f 100644
--- a/BUILD
+++ b/BUILD
@@ -37,11 +37,12 @@
 
 load("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_proto_plugin")
 
-g_stands_for = "green"
+# This should be updated along with build.yaml
+g_stands_for = "gentle"
 
 core_version = "3.0.0-dev"
 
-version = "1.3.0-dev"
+version = "1.4.0-dev"
 
 grpc_cc_library(
     name = "gpr",
@@ -76,6 +77,8 @@
         "grpc_transport_chttp2_client_secure",
         "grpc_transport_chttp2_server_insecure",
         "grpc_transport_chttp2_server_secure",
+        "grpc_message_size_filter",
+        "grpc_deadline_filter",
     ],
 )
 
@@ -90,6 +93,7 @@
         "grpc_base",
         "grpc_transport_chttp2_client_secure",
         "grpc_transport_cronet_client_secure",
+        "grpc_http_filters",
     ],
 )
 
@@ -114,6 +118,8 @@
         "grpc_resolver_sockaddr",
         "grpc_transport_chttp2_client_insecure",
         "grpc_transport_chttp2_server_insecure",
+        "grpc_message_size_filter",
+        "grpc_deadline_filter",
     ],
 )
 
@@ -165,6 +171,22 @@
 )
 
 grpc_cc_library(
+    name = "grpc++_error_details",
+    srcs = [
+        "src/cpp/util/error_details.cc",
+    ],
+    hdrs = [
+        "include/grpc++/support/error_details.h",
+    ],
+    language = "c++",
+    standalone = True,
+    deps = [
+        "grpc++",
+        "//src/proto/grpc/status:status_proto",
+    ],
+)
+
+grpc_cc_library(
     name = "grpc_plugin_support",
     srcs = [
         "src/compiler/cpp_generator.cc",
@@ -434,15 +456,10 @@
         "src/core/lib/channel/channel_args.c",
         "src/core/lib/channel/channel_stack.c",
         "src/core/lib/channel/channel_stack_builder.c",
-        "src/core/lib/channel/compress_filter.c",
         "src/core/lib/channel/connected_channel.c",
-        "src/core/lib/channel/deadline_filter.c",
         "src/core/lib/channel/handshaker.c",
         "src/core/lib/channel/handshaker_factory.c",
         "src/core/lib/channel/handshaker_registry.c",
-        "src/core/lib/channel/http_client_filter.c",
-        "src/core/lib/channel/http_server_filter.c",
-        "src/core/lib/channel/message_size_filter.c",
         "src/core/lib/compression/compression.c",
         "src/core/lib/compression/message_compress.c",
         "src/core/lib/debug/trace.c",
@@ -457,7 +474,6 @@
         "src/core/lib/iomgr/endpoint_pair_windows.c",
         "src/core/lib/iomgr/error.c",
         "src/core/lib/iomgr/ev_epoll_linux.c",
-        "src/core/lib/iomgr/lockfree_event.c",
         "src/core/lib/iomgr/ev_poll_posix.c",
         "src/core/lib/iomgr/ev_posix.c",
         "src/core/lib/iomgr/exec_ctx.c",
@@ -468,6 +484,7 @@
         "src/core/lib/iomgr/iomgr_uv.c",
         "src/core/lib/iomgr/iomgr_windows.c",
         "src/core/lib/iomgr/load_file.c",
+        "src/core/lib/iomgr/lockfree_event.c",
         "src/core/lib/iomgr/network_status_tracker.c",
         "src/core/lib/iomgr/polling_entity.c",
         "src/core/lib/iomgr/pollset_set_uv.c",
@@ -561,16 +578,11 @@
         "src/core/lib/channel/channel_args.h",
         "src/core/lib/channel/channel_stack.h",
         "src/core/lib/channel/channel_stack_builder.h",
-        "src/core/lib/channel/compress_filter.h",
         "src/core/lib/channel/connected_channel.h",
         "src/core/lib/channel/context.h",
-        "src/core/lib/channel/deadline_filter.h",
         "src/core/lib/channel/handshaker.h",
         "src/core/lib/channel/handshaker_factory.h",
         "src/core/lib/channel/handshaker_registry.h",
-        "src/core/lib/channel/http_client_filter.h",
-        "src/core/lib/channel/http_server_filter.h",
-        "src/core/lib/channel/message_size_filter.h",
         "src/core/lib/compression/algorithm_metadata.h",
         "src/core/lib/compression/message_compress.h",
         "src/core/lib/debug/trace.h",
@@ -584,7 +596,6 @@
         "src/core/lib/iomgr/error.h",
         "src/core/lib/iomgr/error_internal.h",
         "src/core/lib/iomgr/ev_epoll_linux.h",
-        "src/core/lib/iomgr/lockfree_event.h",
         "src/core/lib/iomgr/ev_poll_posix.h",
         "src/core/lib/iomgr/ev_posix.h",
         "src/core/lib/iomgr/exec_ctx.h",
@@ -594,6 +605,7 @@
         "src/core/lib/iomgr/iomgr_internal.h",
         "src/core/lib/iomgr/iomgr_posix.h",
         "src/core/lib/iomgr/load_file.h",
+        "src/core/lib/iomgr/lockfree_event.h",
         "src/core/lib/iomgr/network_status_tracker.h",
         "src/core/lib/iomgr/polling_entity.h",
         "src/core/lib/iomgr/pollset.h",
@@ -739,6 +751,7 @@
     language = "c",
     deps = [
         "grpc_base",
+        "grpc_deadline_filter",
     ],
 )
 
@@ -757,6 +770,53 @@
 )
 
 grpc_cc_library(
+    name = "grpc_deadline_filter",
+    srcs = [
+        "src/core/ext/filters/deadline/deadline_filter.c",
+    ],
+    hdrs = [
+        "src/core/ext/filters/deadline/deadline_filter.h",
+    ],
+    language = "c",
+    deps = [
+        "grpc_base",
+    ],
+)
+
+grpc_cc_library(
+    name = "grpc_message_size_filter",
+    srcs = [
+        "src/core/ext/filters/message_size/message_size_filter.c",
+    ],
+    hdrs = [
+        "src/core/ext/filters/message_size/message_size_filter.h",
+    ],
+    language = "c",
+    deps = [
+        "grpc_base",
+    ],
+)
+
+grpc_cc_library(
+    name = "grpc_http_filters",
+    hdrs = [
+        "src/core/ext/filters/http/message_compress/message_compress_filter.h",
+        "src/core/ext/filters/http/client/http_client_filter.h",
+        "src/core/ext/filters/http/server/http_server_filter.h",
+    ],
+    srcs = [
+        "src/core/ext/filters/http/message_compress/message_compress_filter.c",
+        "src/core/ext/filters/http/client/http_client_filter.c",
+        "src/core/ext/filters/http/server/http_server_filter.c",
+        "src/core/ext/filters/http/http_filters_plugin.c"
+    ],
+    language = "c",
+    deps = [
+        "grpc_base",
+    ],
+)
+
+grpc_cc_library(
     name = "grpc_codegen",
     language = "c",
     public_hdrs = [
@@ -984,6 +1044,7 @@
         "src/core/ext/transport/chttp2/transport/hpack_encoder.c",
         "src/core/ext/transport/chttp2/transport/hpack_parser.c",
         "src/core/ext/transport/chttp2/transport/hpack_table.c",
+        "src/core/ext/transport/chttp2/transport/http2_settings.c",
         "src/core/ext/transport/chttp2/transport/huffsyms.c",
         "src/core/ext/transport/chttp2/transport/incoming_metadata.c",
         "src/core/ext/transport/chttp2/transport/parsing.c",
@@ -1006,6 +1067,7 @@
         "src/core/ext/transport/chttp2/transport/hpack_encoder.h",
         "src/core/ext/transport/chttp2/transport/hpack_parser.h",
         "src/core/ext/transport/chttp2/transport/hpack_table.h",
+        "src/core/ext/transport/chttp2/transport/http2_settings.h",
         "src/core/ext/transport/chttp2/transport/huffsyms.h",
         "src/core/ext/transport/chttp2/transport/incoming_metadata.h",
         "src/core/ext/transport/chttp2/transport/internal.h",
@@ -1016,6 +1078,7 @@
     deps = [
         "grpc_base",
         "grpc_transport_chttp2_alpn",
+        "grpc_http_filters",
     ],
 )
 
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 2b94f86..a6a2af6 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -39,7 +39,7 @@
 cmake_minimum_required(VERSION 2.8)
 
 set(PACKAGE_NAME      "grpc")
-set(PACKAGE_VERSION   "1.3.0-dev")
+set(PACKAGE_VERSION   "1.4.0-dev")
 set(PACKAGE_STRING    "${PACKAGE_NAME} ${PACKAGE_VERSION}")
 set(PACKAGE_TARNAME   "${PACKAGE_NAME}-${PACKAGE_VERSION}")
 set(PACKAGE_BUGREPORT "https://github.com/grpc/grpc/issues/")
@@ -167,6 +167,7 @@
   if(NOT PROTOBUF_ROOT_DIR)
     set(PROTOBUF_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/third_party/protobuf)
   endif()
+  set(PROTOBUF_WELLKNOWN_IMPORT_DIR ${PROTOBUF_ROOT_DIR}/src)
   if(EXISTS "${PROTOBUF_ROOT_DIR}/cmake/CMakeLists.txt")
     set(protobuf_MSVC_STATIC_RUNTIME OFF CACHE BOOL "Link static runtime libraries")
     add_subdirectory(${PROTOBUF_ROOT_DIR}/cmake third_party/protobuf)
@@ -199,6 +200,7 @@
     find_package(Protobuf MODULE)
     set(_gRPC_FIND_PROTOBUF "if(NOT Protobuf_FOUND)\n  find_package(Protobuf)\nendif()")
   endif()
+  set(PROTOBUF_WELLKNOWN_IMPORT_DIR /usr/local/include)
 endif()
 
 if("${gRPC_SSL_PROVIDER}" STREQUAL "module")
@@ -301,7 +303,7 @@
     return()
   endif()
 
-  set(_protobuf_include_path -I .)
+  set(_protobuf_include_path -I . -I ${PROTOBUF_WELLKNOWN_IMPORT_DIR})
   foreach(FIL ${ARGN})
     get_filename_component(ABS_FIL ${FIL} ABSOLUTE)
     get_filename_component(FIL_WE ${FIL} NAME_WE)
@@ -389,6 +391,7 @@
 if(_gRPC_PLATFORM_LINUX)
 add_dependencies(buildtests_c ev_epoll_linux_test)
 endif()
+add_dependencies(buildtests_c fake_resolver_test)
 if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
 add_dependencies(buildtests_c fd_conservation_posix_test)
 endif()
@@ -469,6 +472,7 @@
 add_dependencies(buildtests_c memory_profile_test)
 endif()
 add_dependencies(buildtests_c message_compress_test)
+add_dependencies(buildtests_c minimal_stack_is_minimal_test)
 add_dependencies(buildtests_c mlog_test)
 add_dependencies(buildtests_c multiple_server_queues_test)
 add_dependencies(buildtests_c murmur_hash_test)
@@ -661,6 +665,7 @@
 add_dependencies(buildtests_cxx cxx_string_ref_test)
 add_dependencies(buildtests_cxx cxx_time_test)
 add_dependencies(buildtests_cxx end2end_test)
+add_dependencies(buildtests_cxx error_details_test)
 add_dependencies(buildtests_cxx filter_end2end_test)
 add_dependencies(buildtests_cxx generic_end2end_test)
 add_dependencies(buildtests_cxx golden_file_test)
@@ -910,15 +915,10 @@
   src/core/lib/channel/channel_args.c
   src/core/lib/channel/channel_stack.c
   src/core/lib/channel/channel_stack_builder.c
-  src/core/lib/channel/compress_filter.c
   src/core/lib/channel/connected_channel.c
-  src/core/lib/channel/deadline_filter.c
   src/core/lib/channel/handshaker.c
   src/core/lib/channel/handshaker_factory.c
   src/core/lib/channel/handshaker_registry.c
-  src/core/lib/channel/http_client_filter.c
-  src/core/lib/channel/http_server_filter.c
-  src/core/lib/channel/message_size_filter.c
   src/core/lib/compression/compression.c
   src/core/lib/compression/message_compress.c
   src/core/lib/debug/trace.c
@@ -1046,6 +1046,7 @@
   src/core/ext/transport/chttp2/transport/hpack_encoder.c
   src/core/ext/transport/chttp2/transport/hpack_parser.c
   src/core/ext/transport/chttp2/transport/hpack_table.c
+  src/core/ext/transport/chttp2/transport/http2_settings.c
   src/core/ext/transport/chttp2/transport/huffsyms.c
   src/core/ext/transport/chttp2/transport/incoming_metadata.c
   src/core/ext/transport/chttp2/transport/parsing.c
@@ -1054,6 +1055,10 @@
   src/core/ext/transport/chttp2/transport/varint.c
   src/core/ext/transport/chttp2/transport/writing.c
   src/core/ext/transport/chttp2/alpn/alpn.c
+  src/core/ext/filters/http/client/http_client_filter.c
+  src/core/ext/filters/http/http_filters_plugin.c
+  src/core/ext/filters/http/message_compress/message_compress_filter.c
+  src/core/ext/filters/http/server/http_server_filter.c
   src/core/lib/http/httpcli_security_connector.c
   src/core/lib/security/context/security_context.c
   src/core/lib/security/credentials/composite/composite_credentials.c
@@ -1103,6 +1108,7 @@
   src/core/ext/filters/client_channel/subchannel.c
   src/core/ext/filters/client_channel/subchannel_index.c
   src/core/ext/filters/client_channel/uri_parser.c
+  src/core/ext/filters/deadline/deadline_filter.c
   src/core/ext/transport/chttp2/client/chttp2_connector.c
   src/core/ext/transport/chttp2/server/insecure/server_chttp2.c
   src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c
@@ -1139,6 +1145,7 @@
   src/core/ext/census/trace_context.c
   src/core/ext/census/tracing.c
   src/core/ext/filters/max_age/max_age_filter.c
+  src/core/ext/filters/message_size/message_size_filter.c
   src/core/plugin_registry/grpc_plugin_registry.c
 )
 
@@ -1233,15 +1240,10 @@
   src/core/lib/channel/channel_args.c
   src/core/lib/channel/channel_stack.c
   src/core/lib/channel/channel_stack_builder.c
-  src/core/lib/channel/compress_filter.c
   src/core/lib/channel/connected_channel.c
-  src/core/lib/channel/deadline_filter.c
   src/core/lib/channel/handshaker.c
   src/core/lib/channel/handshaker_factory.c
   src/core/lib/channel/handshaker_registry.c
-  src/core/lib/channel/http_client_filter.c
-  src/core/lib/channel/http_server_filter.c
-  src/core/lib/channel/message_size_filter.c
   src/core/lib/compression/compression.c
   src/core/lib/compression/message_compress.c
   src/core/lib/debug/trace.c
@@ -1372,6 +1374,7 @@
   src/core/ext/transport/chttp2/transport/hpack_encoder.c
   src/core/ext/transport/chttp2/transport/hpack_parser.c
   src/core/ext/transport/chttp2/transport/hpack_table.c
+  src/core/ext/transport/chttp2/transport/http2_settings.c
   src/core/ext/transport/chttp2/transport/huffsyms.c
   src/core/ext/transport/chttp2/transport/incoming_metadata.c
   src/core/ext/transport/chttp2/transport/parsing.c
@@ -1380,6 +1383,10 @@
   src/core/ext/transport/chttp2/transport/varint.c
   src/core/ext/transport/chttp2/transport/writing.c
   src/core/ext/transport/chttp2/alpn/alpn.c
+  src/core/ext/filters/http/client/http_client_filter.c
+  src/core/ext/filters/http/http_filters_plugin.c
+  src/core/ext/filters/http/message_compress/message_compress_filter.c
+  src/core/ext/filters/http/server/http_server_filter.c
   src/core/ext/filters/client_channel/channel_connectivity.c
   src/core/ext/filters/client_channel/client_channel.c
   src/core/ext/filters/client_channel/client_channel_factory.c
@@ -1400,6 +1407,7 @@
   src/core/ext/filters/client_channel/subchannel.c
   src/core/ext/filters/client_channel/subchannel_index.c
   src/core/ext/filters/client_channel/uri_parser.c
+  src/core/ext/filters/deadline/deadline_filter.c
   src/core/lib/http/httpcli_security_connector.c
   src/core/lib/security/context/security_context.c
   src/core/lib/security/credentials/composite/composite_credentials.c
@@ -1542,15 +1550,10 @@
   src/core/lib/channel/channel_args.c
   src/core/lib/channel/channel_stack.c
   src/core/lib/channel/channel_stack_builder.c
-  src/core/lib/channel/compress_filter.c
   src/core/lib/channel/connected_channel.c
-  src/core/lib/channel/deadline_filter.c
   src/core/lib/channel/handshaker.c
   src/core/lib/channel/handshaker_factory.c
   src/core/lib/channel/handshaker_registry.c
-  src/core/lib/channel/http_client_filter.c
-  src/core/lib/channel/http_server_filter.c
-  src/core/lib/channel/message_size_filter.c
   src/core/lib/compression/compression.c
   src/core/lib/compression/message_compress.c
   src/core/lib/debug/trace.c
@@ -1803,15 +1806,10 @@
   src/core/lib/channel/channel_args.c
   src/core/lib/channel/channel_stack.c
   src/core/lib/channel/channel_stack_builder.c
-  src/core/lib/channel/compress_filter.c
   src/core/lib/channel/connected_channel.c
-  src/core/lib/channel/deadline_filter.c
   src/core/lib/channel/handshaker.c
   src/core/lib/channel/handshaker_factory.c
   src/core/lib/channel/handshaker_registry.c
-  src/core/lib/channel/http_client_filter.c
-  src/core/lib/channel/http_server_filter.c
-  src/core/lib/channel/message_size_filter.c
   src/core/lib/compression/compression.c
   src/core/lib/compression/message_compress.c
   src/core/lib/debug/trace.c
@@ -1940,6 +1938,7 @@
   src/core/ext/transport/chttp2/transport/hpack_encoder.c
   src/core/ext/transport/chttp2/transport/hpack_parser.c
   src/core/ext/transport/chttp2/transport/hpack_table.c
+  src/core/ext/transport/chttp2/transport/http2_settings.c
   src/core/ext/transport/chttp2/transport/huffsyms.c
   src/core/ext/transport/chttp2/transport/incoming_metadata.c
   src/core/ext/transport/chttp2/transport/parsing.c
@@ -1948,6 +1947,10 @@
   src/core/ext/transport/chttp2/transport/varint.c
   src/core/ext/transport/chttp2/transport/writing.c
   src/core/ext/transport/chttp2/alpn/alpn.c
+  src/core/ext/filters/http/client/http_client_filter.c
+  src/core/ext/filters/http/http_filters_plugin.c
+  src/core/ext/filters/http/message_compress/message_compress_filter.c
+  src/core/ext/filters/http/server/http_server_filter.c
   src/core/ext/transport/chttp2/server/chttp2_server.c
   src/core/ext/transport/chttp2/client/insecure/channel_create.c
   src/core/ext/transport/chttp2/client/insecure/channel_create_posix.c
@@ -1972,6 +1975,7 @@
   src/core/ext/filters/client_channel/subchannel.c
   src/core/ext/filters/client_channel/subchannel_index.c
   src/core/ext/filters/client_channel/uri_parser.c
+  src/core/ext/filters/deadline/deadline_filter.c
   src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.c
   src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.c
   src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.c
@@ -2003,6 +2007,7 @@
   src/core/ext/census/trace_context.c
   src/core/ext/census/tracing.c
   src/core/ext/filters/max_age/max_age_filter.c
+  src/core/ext/filters/message_size/message_size_filter.c
   src/core/plugin_registry/grpc_unsecure_plugin_registry.c
 )
 
@@ -2220,15 +2225,10 @@
   src/core/lib/channel/channel_args.c
   src/core/lib/channel/channel_stack.c
   src/core/lib/channel/channel_stack_builder.c
-  src/core/lib/channel/compress_filter.c
   src/core/lib/channel/connected_channel.c
-  src/core/lib/channel/deadline_filter.c
   src/core/lib/channel/handshaker.c
   src/core/lib/channel/handshaker_factory.c
   src/core/lib/channel/handshaker_registry.c
-  src/core/lib/channel/http_client_filter.c
-  src/core/lib/channel/http_server_filter.c
-  src/core/lib/channel/message_size_filter.c
   src/core/lib/compression/compression.c
   src/core/lib/compression/message_compress.c
   src/core/lib/debug/trace.c
@@ -2551,15 +2551,10 @@
   src/core/lib/channel/channel_args.c
   src/core/lib/channel/channel_stack.c
   src/core/lib/channel/channel_stack_builder.c
-  src/core/lib/channel/compress_filter.c
   src/core/lib/channel/connected_channel.c
-  src/core/lib/channel/deadline_filter.c
   src/core/lib/channel/handshaker.c
   src/core/lib/channel/handshaker_factory.c
   src/core/lib/channel/handshaker_registry.c
-  src/core/lib/channel/http_client_filter.c
-  src/core/lib/channel/http_server_filter.c
-  src/core/lib/channel/message_size_filter.c
   src/core/lib/compression/compression.c
   src/core/lib/compression/message_compress.c
   src/core/lib/debug/trace.c
@@ -2693,6 +2688,7 @@
   src/core/ext/transport/chttp2/transport/hpack_encoder.c
   src/core/ext/transport/chttp2/transport/hpack_parser.c
   src/core/ext/transport/chttp2/transport/hpack_table.c
+  src/core/ext/transport/chttp2/transport/http2_settings.c
   src/core/ext/transport/chttp2/transport/huffsyms.c
   src/core/ext/transport/chttp2/transport/incoming_metadata.c
   src/core/ext/transport/chttp2/transport/parsing.c
@@ -2701,6 +2697,10 @@
   src/core/ext/transport/chttp2/transport/varint.c
   src/core/ext/transport/chttp2/transport/writing.c
   src/core/ext/transport/chttp2/alpn/alpn.c
+  src/core/ext/filters/http/client/http_client_filter.c
+  src/core/ext/filters/http/http_filters_plugin.c
+  src/core/ext/filters/http/message_compress/message_compress_filter.c
+  src/core/ext/filters/http/server/http_server_filter.c
   src/core/ext/filters/client_channel/channel_connectivity.c
   src/core/ext/filters/client_channel/client_channel.c
   src/core/ext/filters/client_channel/client_channel_factory.c
@@ -2721,6 +2721,7 @@
   src/core/ext/filters/client_channel/subchannel.c
   src/core/ext/filters/client_channel/subchannel_index.c
   src/core/ext/filters/client_channel/uri_parser.c
+  src/core/ext/filters/deadline/deadline_filter.c
   src/core/ext/transport/chttp2/server/insecure/server_chttp2.c
   src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c
   src/core/ext/transport/chttp2/server/chttp2_server.c
@@ -2900,6 +2901,72 @@
   )
 endif()
 
+
+add_library(grpc++_error_details
+  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/status/status.pb.cc
+  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/status/status.grpc.pb.cc
+  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/status/status.pb.h
+  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/status/status.grpc.pb.h
+  src/cpp/util/error_details.cc
+)
+
+if(WIN32 AND MSVC)
+  set_target_properties(grpc++_error_details PROPERTIES COMPILE_PDB_NAME "grpc++_error_details"
+    COMPILE_PDB_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}"
+  )
+  if (gRPC_INSTALL)
+    install(FILES ${CMAKE_CURRENT_BINARY_DIR}/grpc++_error_details.pdb
+      DESTINATION ${CMAKE_INSTALL_LIBDIR} OPTIONAL
+    )
+  endif()
+endif()
+
+protobuf_generate_grpc_cpp(
+  src/proto/grpc/status/status.proto
+)
+
+target_include_directories(grpc++_error_details
+  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
+  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
+  PRIVATE ${BORINGSSL_ROOT_DIR}/include
+  PRIVATE ${PROTOBUF_ROOT_DIR}/src
+  PRIVATE ${ZLIB_INCLUDE_DIR}
+  PRIVATE ${BENCHMARK}/include
+  PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/zlib
+  PRIVATE ${CARES_BUILD_INCLUDE_DIR}
+  PRIVATE ${CARES_INCLUDE_DIR}
+  PRIVATE ${CARES_PLATFORM_INCLUDE_DIR}
+  PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
+  PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
+  PRIVATE ${_gRPC_PROTO_GENS_DIR}
+)
+
+target_link_libraries(grpc++_error_details
+  ${_gRPC_BASELIB_LIBRARIES}
+  ${_gRPC_PROTOBUF_LIBRARIES}
+  ${_gRPC_ALLTARGETS_LIBRARIES}
+  grpc++
+)
+
+foreach(_hdr
+  include/grpc++/support/error_details.h
+)
+  string(REPLACE "include/" "" _path ${_hdr})
+  get_filename_component(_path ${_path} PATH)
+  install(FILES ${_hdr}
+    DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/${_path}"
+  )
+endforeach()
+
+
+if (gRPC_INSTALL)
+  install(TARGETS grpc++_error_details EXPORT gRPCTargets
+    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+    LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+    ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+  )
+endif()
+
 if (gRPC_BUILD_TESTS)
 
 add_library(grpc++_proto_reflection_desc_db
@@ -3250,15 +3317,10 @@
   src/core/lib/channel/channel_args.c
   src/core/lib/channel/channel_stack.c
   src/core/lib/channel/channel_stack_builder.c
-  src/core/lib/channel/compress_filter.c
   src/core/lib/channel/connected_channel.c
-  src/core/lib/channel/deadline_filter.c
   src/core/lib/channel/handshaker.c
   src/core/lib/channel/handshaker_factory.c
   src/core/lib/channel/handshaker_registry.c
-  src/core/lib/channel/http_client_filter.c
-  src/core/lib/channel/http_server_filter.c
-  src/core/lib/channel/message_size_filter.c
   src/core/lib/compression/compression.c
   src/core/lib/compression/message_compress.c
   src/core/lib/debug/trace.c
@@ -5385,6 +5447,37 @@
 endif()
 endif (gRPC_BUILD_TESTS)
 if (gRPC_BUILD_TESTS)
+
+add_executable(fake_resolver_test
+  test/core/client_channel/resolvers/fake_resolver_test.c
+)
+
+
+target_include_directories(fake_resolver_test
+  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
+  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
+  PRIVATE ${BORINGSSL_ROOT_DIR}/include
+  PRIVATE ${PROTOBUF_ROOT_DIR}/src
+  PRIVATE ${BENCHMARK_ROOT_DIR}/include
+  PRIVATE ${ZLIB_ROOT_DIR}
+  PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/zlib
+  PRIVATE ${CARES_BUILD_INCLUDE_DIR}
+  PRIVATE ${CARES_INCLUDE_DIR}
+  PRIVATE ${CARES_PLATFORM_INCLUDE_DIR}
+  PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
+  PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
+)
+
+target_link_libraries(fake_resolver_test
+  ${_gRPC_ALLTARGETS_LIBRARIES}
+  grpc_test_util
+  grpc
+  gpr_test_util
+  gpr
+)
+
+endif (gRPC_BUILD_TESTS)
+if (gRPC_BUILD_TESTS)
 if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
 
 add_executable(fd_conservation_posix_test
@@ -7385,6 +7478,37 @@
 endif (gRPC_BUILD_TESTS)
 if (gRPC_BUILD_TESTS)
 
+add_executable(minimal_stack_is_minimal_test
+  test/core/channel/minimal_stack_is_minimal_test.c
+)
+
+
+target_include_directories(minimal_stack_is_minimal_test
+  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
+  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
+  PRIVATE ${BORINGSSL_ROOT_DIR}/include
+  PRIVATE ${PROTOBUF_ROOT_DIR}/src
+  PRIVATE ${BENCHMARK_ROOT_DIR}/include
+  PRIVATE ${ZLIB_ROOT_DIR}
+  PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/zlib
+  PRIVATE ${CARES_BUILD_INCLUDE_DIR}
+  PRIVATE ${CARES_INCLUDE_DIR}
+  PRIVATE ${CARES_PLATFORM_INCLUDE_DIR}
+  PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
+  PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
+)
+
+target_link_libraries(minimal_stack_is_minimal_test
+  ${_gRPC_ALLTARGETS_LIBRARIES}
+  grpc_test_util
+  grpc
+  gpr_test_util
+  gpr
+)
+
+endif (gRPC_BUILD_TESTS)
+if (gRPC_BUILD_TESTS)
+
 add_executable(mlog_test
   test/core/census/mlog_test.c
 )
@@ -9884,6 +10008,48 @@
 endif (gRPC_BUILD_TESTS)
 if (gRPC_BUILD_TESTS)
 
+add_executable(error_details_test
+  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/echo_messages.pb.cc
+  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/echo_messages.grpc.pb.cc
+  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/echo_messages.pb.h
+  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/echo_messages.grpc.pb.h
+  test/cpp/util/error_details_test.cc
+  third_party/googletest/googletest/src/gtest-all.cc
+)
+
+protobuf_generate_grpc_cpp(
+  src/proto/grpc/testing/echo_messages.proto
+)
+
+target_include_directories(error_details_test
+  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
+  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
+  PRIVATE ${BORINGSSL_ROOT_DIR}/include
+  PRIVATE ${PROTOBUF_ROOT_DIR}/src
+  PRIVATE ${BENCHMARK_ROOT_DIR}/include
+  PRIVATE ${ZLIB_ROOT_DIR}
+  PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/zlib
+  PRIVATE ${CARES_BUILD_INCLUDE_DIR}
+  PRIVATE ${CARES_INCLUDE_DIR}
+  PRIVATE ${CARES_PLATFORM_INCLUDE_DIR}
+  PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
+  PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
+  PRIVATE ${_gRPC_PROTO_GENS_DIR}
+)
+
+target_link_libraries(error_details_test
+  ${_gRPC_PROTOBUF_LIBRARIES}
+  ${_gRPC_ALLTARGETS_LIBRARIES}
+  grpc++_error_details
+  grpc++
+  ${_gRPC_GFLAGS_LIBRARIES}
+)
+
+endif (gRPC_BUILD_TESTS)
+if (gRPC_BUILD_TESTS)
+
 add_executable(filter_end2end_test
   test/cpp/end2end/filter_end2end_test.cc
   third_party/googletest/googletest/src/gtest-all.cc
diff --git a/Makefile b/Makefile
index 1fb0ad1..8898939 100644
--- a/Makefile
+++ b/Makefile
@@ -419,9 +419,9 @@
 Q = @
 endif
 
-CORE_VERSION = 3.0.0-dev
-CPP_VERSION = 1.3.0-dev
-CSHARP_VERSION = 1.3.0-dev
+CORE_VERSION = 4.0.0-dev
+CPP_VERSION = 1.4.0-dev
+CSHARP_VERSION = 1.4.0-dev
 
 CPPFLAGS_NO_ARCH += $(addprefix -I, $(INCLUDES)) $(addprefix -D, $(DEFINES))
 CPPFLAGS += $(CPPFLAGS_NO_ARCH) $(ARCH_FLAGS)
@@ -469,7 +469,7 @@
 SHARED_EXT_CPP = dll
 SHARED_EXT_CSHARP = dll
 SHARED_PREFIX =
-SHARED_VERSION_CORE = -3
+SHARED_VERSION_CORE = -4
 SHARED_VERSION_CPP = -1
 SHARED_VERSION_CSHARP = -1
 else ifeq ($(SYSTEM),Darwin)
@@ -981,6 +981,7 @@
 endpoint_pair_test: $(BINDIR)/$(CONFIG)/endpoint_pair_test
 error_test: $(BINDIR)/$(CONFIG)/error_test
 ev_epoll_linux_test: $(BINDIR)/$(CONFIG)/ev_epoll_linux_test
+fake_resolver_test: $(BINDIR)/$(CONFIG)/fake_resolver_test
 fd_conservation_posix_test: $(BINDIR)/$(CONFIG)/fd_conservation_posix_test
 fd_posix_test: $(BINDIR)/$(CONFIG)/fd_posix_test
 fling_client: $(BINDIR)/$(CONFIG)/fling_client
@@ -1050,6 +1051,7 @@
 memory_profile_server: $(BINDIR)/$(CONFIG)/memory_profile_server
 memory_profile_test: $(BINDIR)/$(CONFIG)/memory_profile_test
 message_compress_test: $(BINDIR)/$(CONFIG)/message_compress_test
+minimal_stack_is_minimal_test: $(BINDIR)/$(CONFIG)/minimal_stack_is_minimal_test
 mlog_test: $(BINDIR)/$(CONFIG)/mlog_test
 multiple_server_queues_test: $(BINDIR)/$(CONFIG)/multiple_server_queues_test
 murmur_hash_test: $(BINDIR)/$(CONFIG)/murmur_hash_test
@@ -1126,6 +1128,7 @@
 cxx_string_ref_test: $(BINDIR)/$(CONFIG)/cxx_string_ref_test
 cxx_time_test: $(BINDIR)/$(CONFIG)/cxx_time_test
 end2end_test: $(BINDIR)/$(CONFIG)/end2end_test
+error_details_test: $(BINDIR)/$(CONFIG)/error_details_test
 filter_end2end_test: $(BINDIR)/$(CONFIG)/filter_end2end_test
 generic_end2end_test: $(BINDIR)/$(CONFIG)/generic_end2end_test
 golden_file_test: $(BINDIR)/$(CONFIG)/golden_file_test
@@ -1305,12 +1308,12 @@
 
 static_c: pc_c pc_c_unsecure cache.mk  $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgrpc_cronet.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a
 
-static_cxx: pc_cxx pc_cxx_unsecure cache.mk  $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc++_cronet.a $(LIBDIR)/$(CONFIG)/libgrpc++_reflection.a $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure.a
+static_cxx: pc_cxx pc_cxx_unsecure cache.mk  $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc++_cronet.a $(LIBDIR)/$(CONFIG)/libgrpc++_error_details.a $(LIBDIR)/$(CONFIG)/libgrpc++_reflection.a $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure.a
 
 shared: shared_c shared_cxx
 
 shared_c: pc_c pc_c_unsecure cache.mk $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)gpr$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc_cronet$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc_unsecure$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE)
-shared_cxx: pc_cxx pc_cxx_unsecure cache.mk $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc++$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc++_cronet$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc++_reflection$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc++_unsecure$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP)
+shared_cxx: pc_cxx pc_cxx_unsecure cache.mk $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc++$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc++_cronet$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc++_error_details$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc++_reflection$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc++_unsecure$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP)
 
 shared_csharp: shared_c  $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc_csharp_ext$(SHARED_VERSION_CSHARP).$(SHARED_EXT_CSHARP)
 grpc_csharp_ext: shared_csharp
@@ -1364,6 +1367,7 @@
   $(BINDIR)/$(CONFIG)/endpoint_pair_test \
   $(BINDIR)/$(CONFIG)/error_test \
   $(BINDIR)/$(CONFIG)/ev_epoll_linux_test \
+  $(BINDIR)/$(CONFIG)/fake_resolver_test \
   $(BINDIR)/$(CONFIG)/fd_conservation_posix_test \
   $(BINDIR)/$(CONFIG)/fd_posix_test \
   $(BINDIR)/$(CONFIG)/fling_client \
@@ -1422,6 +1426,7 @@
   $(BINDIR)/$(CONFIG)/memory_profile_server \
   $(BINDIR)/$(CONFIG)/memory_profile_test \
   $(BINDIR)/$(CONFIG)/message_compress_test \
+  $(BINDIR)/$(CONFIG)/minimal_stack_is_minimal_test \
   $(BINDIR)/$(CONFIG)/mlog_test \
   $(BINDIR)/$(CONFIG)/multiple_server_queues_test \
   $(BINDIR)/$(CONFIG)/murmur_hash_test \
@@ -1552,6 +1557,7 @@
   $(BINDIR)/$(CONFIG)/cxx_string_ref_test \
   $(BINDIR)/$(CONFIG)/cxx_time_test \
   $(BINDIR)/$(CONFIG)/end2end_test \
+  $(BINDIR)/$(CONFIG)/error_details_test \
   $(BINDIR)/$(CONFIG)/filter_end2end_test \
   $(BINDIR)/$(CONFIG)/generic_end2end_test \
   $(BINDIR)/$(CONFIG)/golden_file_test \
@@ -1671,6 +1677,7 @@
   $(BINDIR)/$(CONFIG)/cxx_string_ref_test \
   $(BINDIR)/$(CONFIG)/cxx_time_test \
   $(BINDIR)/$(CONFIG)/end2end_test \
+  $(BINDIR)/$(CONFIG)/error_details_test \
   $(BINDIR)/$(CONFIG)/filter_end2end_test \
   $(BINDIR)/$(CONFIG)/generic_end2end_test \
   $(BINDIR)/$(CONFIG)/golden_file_test \
@@ -1772,6 +1779,8 @@
 	$(Q) $(BINDIR)/$(CONFIG)/error_test || ( echo test error_test failed ; exit 1 )
 	$(E) "[RUN]     Testing ev_epoll_linux_test"
 	$(Q) $(BINDIR)/$(CONFIG)/ev_epoll_linux_test || ( echo test ev_epoll_linux_test failed ; exit 1 )
+	$(E) "[RUN]     Testing fake_resolver_test"
+	$(Q) $(BINDIR)/$(CONFIG)/fake_resolver_test || ( echo test fake_resolver_test failed ; exit 1 )
 	$(E) "[RUN]     Testing fd_conservation_posix_test"
 	$(Q) $(BINDIR)/$(CONFIG)/fd_conservation_posix_test || ( echo test fd_conservation_posix_test failed ; exit 1 )
 	$(E) "[RUN]     Testing fd_posix_test"
@@ -1874,6 +1883,8 @@
 	$(Q) $(BINDIR)/$(CONFIG)/memory_profile_test || ( echo test memory_profile_test failed ; exit 1 )
 	$(E) "[RUN]     Testing message_compress_test"
 	$(Q) $(BINDIR)/$(CONFIG)/message_compress_test || ( echo test message_compress_test failed ; exit 1 )
+	$(E) "[RUN]     Testing minimal_stack_is_minimal_test"
+	$(Q) $(BINDIR)/$(CONFIG)/minimal_stack_is_minimal_test || ( echo test minimal_stack_is_minimal_test failed ; exit 1 )
 	$(E) "[RUN]     Testing multiple_server_queues_test"
 	$(Q) $(BINDIR)/$(CONFIG)/multiple_server_queues_test || ( echo test multiple_server_queues_test failed ; exit 1 )
 	$(E) "[RUN]     Testing murmur_hash_test"
@@ -2040,6 +2051,8 @@
 	$(Q) $(BINDIR)/$(CONFIG)/cxx_time_test || ( echo test cxx_time_test failed ; exit 1 )
 	$(E) "[RUN]     Testing end2end_test"
 	$(Q) $(BINDIR)/$(CONFIG)/end2end_test || ( echo test end2end_test failed ; exit 1 )
+	$(E) "[RUN]     Testing error_details_test"
+	$(Q) $(BINDIR)/$(CONFIG)/error_details_test || ( echo test error_details_test failed ; exit 1 )
 	$(E) "[RUN]     Testing filter_end2end_test"
 	$(Q) $(BINDIR)/$(CONFIG)/filter_end2end_test || ( echo test filter_end2end_test failed ; exit 1 )
 	$(E) "[RUN]     Testing generic_end2end_test"
@@ -2144,6 +2157,8 @@
 	$(Q) $(STRIP) $(LIBDIR)/$(CONFIG)/libgrpc++.a
 	$(E) "[STRIP]   Stripping libgrpc++_cronet.a"
 	$(Q) $(STRIP) $(LIBDIR)/$(CONFIG)/libgrpc++_cronet.a
+	$(E) "[STRIP]   Stripping libgrpc++_error_details.a"
+	$(Q) $(STRIP) $(LIBDIR)/$(CONFIG)/libgrpc++_error_details.a
 	$(E) "[STRIP]   Stripping libgrpc++_reflection.a"
 	$(Q) $(STRIP) $(LIBDIR)/$(CONFIG)/libgrpc++_reflection.a
 	$(E) "[STRIP]   Stripping libgrpc++_unsecure.a"
@@ -2168,6 +2183,8 @@
 	$(Q) $(STRIP) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc++$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP)
 	$(E) "[STRIP]   Stripping $(SHARED_PREFIX)grpc++_cronet$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP)"
 	$(Q) $(STRIP) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc++_cronet$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP)
+	$(E) "[STRIP]   Stripping $(SHARED_PREFIX)grpc++_error_details$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP)"
+	$(Q) $(STRIP) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc++_error_details$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP)
 	$(E) "[STRIP]   Stripping $(SHARED_PREFIX)grpc++_reflection$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP)"
 	$(Q) $(STRIP) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc++_reflection$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP)
 	$(E) "[STRIP]   Stripping $(SHARED_PREFIX)grpc++_unsecure$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP)"
@@ -2250,6 +2267,21 @@
 endif
 
 ifeq ($(NO_PROTOC),true)
+$(GENDIR)/src/proto/grpc/status/status.pb.cc: protoc_dep_error
+$(GENDIR)/src/proto/grpc/status/status.grpc.pb.cc: protoc_dep_error
+else
+$(GENDIR)/src/proto/grpc/status/status.pb.cc: src/proto/grpc/status/status.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) 
+	$(E) "[PROTOC]  Generating protobuf CC file from $<"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --cpp_out=$(GENDIR) $<
+
+$(GENDIR)/src/proto/grpc/status/status.grpc.pb.cc: src/proto/grpc/status/status.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) 
+	$(E) "[GRPC]    Generating gRPC's protobuf service CC file from $<"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(PROTOC_PLUGINS_DIR)/grpc_cpp_plugin$(EXECUTABLE_SUFFIX) $<
+endif
+
+ifeq ($(NO_PROTOC),true)
 $(GENDIR)/src/proto/grpc/testing/compiler_test.pb.cc: protoc_dep_error
 $(GENDIR)/src/proto/grpc/testing/compiler_test.grpc.pb.cc: protoc_dep_error
 else
@@ -2507,6 +2539,9 @@
 	$(E) "[INSTALL] Installing libgrpc++_cronet.a"
 	$(Q) $(INSTALL) -d $(prefix)/lib
 	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgrpc++_cronet.a $(prefix)/lib/libgrpc++_cronet.a
+	$(E) "[INSTALL] Installing libgrpc++_error_details.a"
+	$(Q) $(INSTALL) -d $(prefix)/lib
+	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgrpc++_error_details.a $(prefix)/lib/libgrpc++_error_details.a
 	$(E) "[INSTALL] Installing libgrpc++_reflection.a"
 	$(Q) $(INSTALL) -d $(prefix)/lib
 	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgrpc++_reflection.a $(prefix)/lib/libgrpc++_reflection.a
@@ -2523,7 +2558,7 @@
 ifeq ($(SYSTEM),MINGW32)
 	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgpr$(SHARED_VERSION_CORE)-dll.a $(prefix)/lib/libgpr.a
 else ifneq ($(SYSTEM),Darwin)
-	$(Q) ln -sf $(SHARED_PREFIX)gpr$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(prefix)/lib/libgpr.so.3
+	$(Q) ln -sf $(SHARED_PREFIX)gpr$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(prefix)/lib/libgpr.so.4
 	$(Q) ln -sf $(SHARED_PREFIX)gpr$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(prefix)/lib/libgpr.so
 endif
 	$(E) "[INSTALL] Installing $(SHARED_PREFIX)grpc$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE)"
@@ -2532,7 +2567,7 @@
 ifeq ($(SYSTEM),MINGW32)
 	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgrpc$(SHARED_VERSION_CORE)-dll.a $(prefix)/lib/libgrpc.a
 else ifneq ($(SYSTEM),Darwin)
-	$(Q) ln -sf $(SHARED_PREFIX)grpc$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(prefix)/lib/libgrpc.so.3
+	$(Q) ln -sf $(SHARED_PREFIX)grpc$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(prefix)/lib/libgrpc.so.4
 	$(Q) ln -sf $(SHARED_PREFIX)grpc$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(prefix)/lib/libgrpc.so
 endif
 	$(E) "[INSTALL] Installing $(SHARED_PREFIX)grpc_cronet$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE)"
@@ -2541,7 +2576,7 @@
 ifeq ($(SYSTEM),MINGW32)
 	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgrpc_cronet$(SHARED_VERSION_CORE)-dll.a $(prefix)/lib/libgrpc_cronet.a
 else ifneq ($(SYSTEM),Darwin)
-	$(Q) ln -sf $(SHARED_PREFIX)grpc_cronet$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(prefix)/lib/libgrpc_cronet.so.3
+	$(Q) ln -sf $(SHARED_PREFIX)grpc_cronet$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(prefix)/lib/libgrpc_cronet.so.4
 	$(Q) ln -sf $(SHARED_PREFIX)grpc_cronet$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(prefix)/lib/libgrpc_cronet.so
 endif
 	$(E) "[INSTALL] Installing $(SHARED_PREFIX)grpc_unsecure$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE)"
@@ -2550,7 +2585,7 @@
 ifeq ($(SYSTEM),MINGW32)
 	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgrpc_unsecure$(SHARED_VERSION_CORE)-dll.a $(prefix)/lib/libgrpc_unsecure.a
 else ifneq ($(SYSTEM),Darwin)
-	$(Q) ln -sf $(SHARED_PREFIX)grpc_unsecure$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(prefix)/lib/libgrpc_unsecure.so.3
+	$(Q) ln -sf $(SHARED_PREFIX)grpc_unsecure$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(prefix)/lib/libgrpc_unsecure.so.4
 	$(Q) ln -sf $(SHARED_PREFIX)grpc_unsecure$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(prefix)/lib/libgrpc_unsecure.so
 endif
 ifneq ($(SYSTEM),MINGW32)
@@ -2567,7 +2602,7 @@
 ifeq ($(SYSTEM),MINGW32)
 	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgrpc++$(SHARED_VERSION_CPP)-dll.a $(prefix)/lib/libgrpc++.a
 else ifneq ($(SYSTEM),Darwin)
-	$(Q) ln -sf $(SHARED_PREFIX)grpc++$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(prefix)/lib/libgrpc++.so.3
+	$(Q) ln -sf $(SHARED_PREFIX)grpc++$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(prefix)/lib/libgrpc++.so.4
 	$(Q) ln -sf $(SHARED_PREFIX)grpc++$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(prefix)/lib/libgrpc++.so
 endif
 	$(E) "[INSTALL] Installing $(SHARED_PREFIX)grpc++_cronet$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP)"
@@ -2576,16 +2611,25 @@
 ifeq ($(SYSTEM),MINGW32)
 	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgrpc++_cronet$(SHARED_VERSION_CPP)-dll.a $(prefix)/lib/libgrpc++_cronet.a
 else ifneq ($(SYSTEM),Darwin)
-	$(Q) ln -sf $(SHARED_PREFIX)grpc++_cronet$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(prefix)/lib/libgrpc++_cronet.so.3
+	$(Q) ln -sf $(SHARED_PREFIX)grpc++_cronet$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(prefix)/lib/libgrpc++_cronet.so.4
 	$(Q) ln -sf $(SHARED_PREFIX)grpc++_cronet$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(prefix)/lib/libgrpc++_cronet.so
 endif
+	$(E) "[INSTALL] Installing $(SHARED_PREFIX)grpc++_error_details$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP)"
+	$(Q) $(INSTALL) -d $(prefix)/lib
+	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc++_error_details$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(prefix)/lib/$(SHARED_PREFIX)grpc++_error_details$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP)
+ifeq ($(SYSTEM),MINGW32)
+	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgrpc++_error_details$(SHARED_VERSION_CPP)-dll.a $(prefix)/lib/libgrpc++_error_details.a
+else ifneq ($(SYSTEM),Darwin)
+	$(Q) ln -sf $(SHARED_PREFIX)grpc++_error_details$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(prefix)/lib/libgrpc++_error_details.so.4
+	$(Q) ln -sf $(SHARED_PREFIX)grpc++_error_details$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(prefix)/lib/libgrpc++_error_details.so
+endif
 	$(E) "[INSTALL] Installing $(SHARED_PREFIX)grpc++_reflection$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP)"
 	$(Q) $(INSTALL) -d $(prefix)/lib
 	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc++_reflection$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(prefix)/lib/$(SHARED_PREFIX)grpc++_reflection$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP)
 ifeq ($(SYSTEM),MINGW32)
 	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgrpc++_reflection$(SHARED_VERSION_CPP)-dll.a $(prefix)/lib/libgrpc++_reflection.a
 else ifneq ($(SYSTEM),Darwin)
-	$(Q) ln -sf $(SHARED_PREFIX)grpc++_reflection$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(prefix)/lib/libgrpc++_reflection.so.3
+	$(Q) ln -sf $(SHARED_PREFIX)grpc++_reflection$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(prefix)/lib/libgrpc++_reflection.so.4
 	$(Q) ln -sf $(SHARED_PREFIX)grpc++_reflection$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(prefix)/lib/libgrpc++_reflection.so
 endif
 	$(E) "[INSTALL] Installing $(SHARED_PREFIX)grpc++_unsecure$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP)"
@@ -2594,7 +2638,7 @@
 ifeq ($(SYSTEM),MINGW32)
 	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure$(SHARED_VERSION_CPP)-dll.a $(prefix)/lib/libgrpc++_unsecure.a
 else ifneq ($(SYSTEM),Darwin)
-	$(Q) ln -sf $(SHARED_PREFIX)grpc++_unsecure$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(prefix)/lib/libgrpc++_unsecure.so.3
+	$(Q) ln -sf $(SHARED_PREFIX)grpc++_unsecure$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(prefix)/lib/libgrpc++_unsecure.so.4
 	$(Q) ln -sf $(SHARED_PREFIX)grpc++_unsecure$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(prefix)/lib/libgrpc++_unsecure.so
 endif
 ifneq ($(SYSTEM),MINGW32)
@@ -2611,7 +2655,7 @@
 ifeq ($(SYSTEM),MINGW32)
 	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgrpc_csharp_ext$(SHARED_VERSION_CSHARP)-dll.a $(prefix)/lib/libgrpc_csharp_ext.a
 else ifneq ($(SYSTEM),Darwin)
-	$(Q) ln -sf $(SHARED_PREFIX)grpc_csharp_ext$(SHARED_VERSION_CSHARP).$(SHARED_EXT_CSHARP) $(prefix)/lib/libgrpc_csharp_ext.so.3
+	$(Q) ln -sf $(SHARED_PREFIX)grpc_csharp_ext$(SHARED_VERSION_CSHARP).$(SHARED_EXT_CSHARP) $(prefix)/lib/libgrpc_csharp_ext.so.4
 	$(Q) ln -sf $(SHARED_PREFIX)grpc_csharp_ext$(SHARED_VERSION_CSHARP).$(SHARED_EXT_CSHARP) $(prefix)/lib/libgrpc_csharp_ext.so
 endif
 ifneq ($(SYSTEM),MINGW32)
@@ -2776,8 +2820,8 @@
 ifeq ($(SYSTEM),Darwin)
 	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -install_name $(SHARED_PREFIX)gpr$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgpr$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBGPR_OBJS) $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(LDLIBS)
 else
-	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgpr.so.3 -o $(LIBDIR)/$(CONFIG)/libgpr$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBGPR_OBJS) $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(LDLIBS)
-	$(Q) ln -sf $(SHARED_PREFIX)gpr$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/libgpr$(SHARED_VERSION_CORE).so.3
+	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgpr.so.4 -o $(LIBDIR)/$(CONFIG)/libgpr$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBGPR_OBJS) $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(LDLIBS)
+	$(Q) ln -sf $(SHARED_PREFIX)gpr$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/libgpr$(SHARED_VERSION_CORE).so.4
 	$(Q) ln -sf $(SHARED_PREFIX)gpr$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/libgpr$(SHARED_VERSION_CORE).so
 endif
 endif
@@ -2817,15 +2861,10 @@
     src/core/lib/channel/channel_args.c \
     src/core/lib/channel/channel_stack.c \
     src/core/lib/channel/channel_stack_builder.c \
-    src/core/lib/channel/compress_filter.c \
     src/core/lib/channel/connected_channel.c \
-    src/core/lib/channel/deadline_filter.c \
     src/core/lib/channel/handshaker.c \
     src/core/lib/channel/handshaker_factory.c \
     src/core/lib/channel/handshaker_registry.c \
-    src/core/lib/channel/http_client_filter.c \
-    src/core/lib/channel/http_server_filter.c \
-    src/core/lib/channel/message_size_filter.c \
     src/core/lib/compression/compression.c \
     src/core/lib/compression/message_compress.c \
     src/core/lib/debug/trace.c \
@@ -2953,6 +2992,7 @@
     src/core/ext/transport/chttp2/transport/hpack_encoder.c \
     src/core/ext/transport/chttp2/transport/hpack_parser.c \
     src/core/ext/transport/chttp2/transport/hpack_table.c \
+    src/core/ext/transport/chttp2/transport/http2_settings.c \
     src/core/ext/transport/chttp2/transport/huffsyms.c \
     src/core/ext/transport/chttp2/transport/incoming_metadata.c \
     src/core/ext/transport/chttp2/transport/parsing.c \
@@ -2961,6 +3001,10 @@
     src/core/ext/transport/chttp2/transport/varint.c \
     src/core/ext/transport/chttp2/transport/writing.c \
     src/core/ext/transport/chttp2/alpn/alpn.c \
+    src/core/ext/filters/http/client/http_client_filter.c \
+    src/core/ext/filters/http/http_filters_plugin.c \
+    src/core/ext/filters/http/message_compress/message_compress_filter.c \
+    src/core/ext/filters/http/server/http_server_filter.c \
     src/core/lib/http/httpcli_security_connector.c \
     src/core/lib/security/context/security_context.c \
     src/core/lib/security/credentials/composite/composite_credentials.c \
@@ -3010,6 +3054,7 @@
     src/core/ext/filters/client_channel/subchannel.c \
     src/core/ext/filters/client_channel/subchannel_index.c \
     src/core/ext/filters/client_channel/uri_parser.c \
+    src/core/ext/filters/deadline/deadline_filter.c \
     src/core/ext/transport/chttp2/client/chttp2_connector.c \
     src/core/ext/transport/chttp2/server/insecure/server_chttp2.c \
     src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c \
@@ -3046,6 +3091,7 @@
     src/core/ext/census/trace_context.c \
     src/core/ext/census/tracing.c \
     src/core/ext/filters/max_age/max_age_filter.c \
+    src/core/ext/filters/message_size/message_size_filter.c \
     src/core/plugin_registry/grpc_plugin_registry.c \
 
 PUBLIC_HEADERS_C += \
@@ -3118,8 +3164,8 @@
 ifeq ($(SYSTEM),Darwin)
 	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -install_name $(SHARED_PREFIX)grpc$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgrpc$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBGRPC_OBJS) $(LIBDIR)/$(CONFIG)/libgpr.a $(OPENSSL_MERGE_LIBS) $(LDLIBS_SECURE) $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(LDLIBS)
 else
-	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgrpc.so.3 -o $(LIBDIR)/$(CONFIG)/libgrpc$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBGRPC_OBJS) $(LIBDIR)/$(CONFIG)/libgpr.a $(OPENSSL_MERGE_LIBS) $(LDLIBS_SECURE) $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(LDLIBS)
-	$(Q) ln -sf $(SHARED_PREFIX)grpc$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/libgrpc$(SHARED_VERSION_CORE).so.3
+	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgrpc.so.4 -o $(LIBDIR)/$(CONFIG)/libgrpc$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBGRPC_OBJS) $(LIBDIR)/$(CONFIG)/libgpr.a $(OPENSSL_MERGE_LIBS) $(LDLIBS_SECURE) $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(LDLIBS)
+	$(Q) ln -sf $(SHARED_PREFIX)grpc$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/libgrpc$(SHARED_VERSION_CORE).so.4
 	$(Q) ln -sf $(SHARED_PREFIX)grpc$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/libgrpc$(SHARED_VERSION_CORE).so
 endif
 endif
@@ -3138,15 +3184,10 @@
     src/core/lib/channel/channel_args.c \
     src/core/lib/channel/channel_stack.c \
     src/core/lib/channel/channel_stack_builder.c \
-    src/core/lib/channel/compress_filter.c \
     src/core/lib/channel/connected_channel.c \
-    src/core/lib/channel/deadline_filter.c \
     src/core/lib/channel/handshaker.c \
     src/core/lib/channel/handshaker_factory.c \
     src/core/lib/channel/handshaker_registry.c \
-    src/core/lib/channel/http_client_filter.c \
-    src/core/lib/channel/http_server_filter.c \
-    src/core/lib/channel/message_size_filter.c \
     src/core/lib/compression/compression.c \
     src/core/lib/compression/message_compress.c \
     src/core/lib/debug/trace.c \
@@ -3277,6 +3318,7 @@
     src/core/ext/transport/chttp2/transport/hpack_encoder.c \
     src/core/ext/transport/chttp2/transport/hpack_parser.c \
     src/core/ext/transport/chttp2/transport/hpack_table.c \
+    src/core/ext/transport/chttp2/transport/http2_settings.c \
     src/core/ext/transport/chttp2/transport/huffsyms.c \
     src/core/ext/transport/chttp2/transport/incoming_metadata.c \
     src/core/ext/transport/chttp2/transport/parsing.c \
@@ -3285,6 +3327,10 @@
     src/core/ext/transport/chttp2/transport/varint.c \
     src/core/ext/transport/chttp2/transport/writing.c \
     src/core/ext/transport/chttp2/alpn/alpn.c \
+    src/core/ext/filters/http/client/http_client_filter.c \
+    src/core/ext/filters/http/http_filters_plugin.c \
+    src/core/ext/filters/http/message_compress/message_compress_filter.c \
+    src/core/ext/filters/http/server/http_server_filter.c \
     src/core/ext/filters/client_channel/channel_connectivity.c \
     src/core/ext/filters/client_channel/client_channel.c \
     src/core/ext/filters/client_channel/client_channel_factory.c \
@@ -3305,6 +3351,7 @@
     src/core/ext/filters/client_channel/subchannel.c \
     src/core/ext/filters/client_channel/subchannel_index.c \
     src/core/ext/filters/client_channel/uri_parser.c \
+    src/core/ext/filters/deadline/deadline_filter.c \
     src/core/lib/http/httpcli_security_connector.c \
     src/core/lib/security/context/security_context.c \
     src/core/lib/security/credentials/composite/composite_credentials.c \
@@ -3407,8 +3454,8 @@
 ifeq ($(SYSTEM),Darwin)
 	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -install_name $(SHARED_PREFIX)grpc_cronet$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgrpc_cronet$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBGRPC_CRONET_OBJS) $(LIBDIR)/$(CONFIG)/libgpr.a $(OPENSSL_MERGE_LIBS) $(LDLIBS_SECURE) $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(LDLIBS)
 else
-	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgrpc_cronet.so.3 -o $(LIBDIR)/$(CONFIG)/libgrpc_cronet$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBGRPC_CRONET_OBJS) $(LIBDIR)/$(CONFIG)/libgpr.a $(OPENSSL_MERGE_LIBS) $(LDLIBS_SECURE) $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(LDLIBS)
-	$(Q) ln -sf $(SHARED_PREFIX)grpc_cronet$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/libgrpc_cronet$(SHARED_VERSION_CORE).so.3
+	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgrpc_cronet.so.4 -o $(LIBDIR)/$(CONFIG)/libgrpc_cronet$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBGRPC_CRONET_OBJS) $(LIBDIR)/$(CONFIG)/libgpr.a $(OPENSSL_MERGE_LIBS) $(LDLIBS_SECURE) $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(LDLIBS)
+	$(Q) ln -sf $(SHARED_PREFIX)grpc_cronet$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/libgrpc_cronet$(SHARED_VERSION_CORE).so.4
 	$(Q) ln -sf $(SHARED_PREFIX)grpc_cronet$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/libgrpc_cronet$(SHARED_VERSION_CORE).so
 endif
 endif
@@ -3446,15 +3493,10 @@
     src/core/lib/channel/channel_args.c \
     src/core/lib/channel/channel_stack.c \
     src/core/lib/channel/channel_stack_builder.c \
-    src/core/lib/channel/compress_filter.c \
     src/core/lib/channel/connected_channel.c \
-    src/core/lib/channel/deadline_filter.c \
     src/core/lib/channel/handshaker.c \
     src/core/lib/channel/handshaker_factory.c \
     src/core/lib/channel/handshaker_registry.c \
-    src/core/lib/channel/http_client_filter.c \
-    src/core/lib/channel/http_server_filter.c \
-    src/core/lib/channel/message_size_filter.c \
     src/core/lib/compression/compression.c \
     src/core/lib/compression/message_compress.c \
     src/core/lib/debug/trace.c \
@@ -3679,15 +3721,10 @@
     src/core/lib/channel/channel_args.c \
     src/core/lib/channel/channel_stack.c \
     src/core/lib/channel/channel_stack_builder.c \
-    src/core/lib/channel/compress_filter.c \
     src/core/lib/channel/connected_channel.c \
-    src/core/lib/channel/deadline_filter.c \
     src/core/lib/channel/handshaker.c \
     src/core/lib/channel/handshaker_factory.c \
     src/core/lib/channel/handshaker_registry.c \
-    src/core/lib/channel/http_client_filter.c \
-    src/core/lib/channel/http_server_filter.c \
-    src/core/lib/channel/message_size_filter.c \
     src/core/lib/compression/compression.c \
     src/core/lib/compression/message_compress.c \
     src/core/lib/debug/trace.c \
@@ -3816,6 +3853,7 @@
     src/core/ext/transport/chttp2/transport/hpack_encoder.c \
     src/core/ext/transport/chttp2/transport/hpack_parser.c \
     src/core/ext/transport/chttp2/transport/hpack_table.c \
+    src/core/ext/transport/chttp2/transport/http2_settings.c \
     src/core/ext/transport/chttp2/transport/huffsyms.c \
     src/core/ext/transport/chttp2/transport/incoming_metadata.c \
     src/core/ext/transport/chttp2/transport/parsing.c \
@@ -3824,6 +3862,10 @@
     src/core/ext/transport/chttp2/transport/varint.c \
     src/core/ext/transport/chttp2/transport/writing.c \
     src/core/ext/transport/chttp2/alpn/alpn.c \
+    src/core/ext/filters/http/client/http_client_filter.c \
+    src/core/ext/filters/http/http_filters_plugin.c \
+    src/core/ext/filters/http/message_compress/message_compress_filter.c \
+    src/core/ext/filters/http/server/http_server_filter.c \
     src/core/ext/transport/chttp2/server/chttp2_server.c \
     src/core/ext/transport/chttp2/client/insecure/channel_create.c \
     src/core/ext/transport/chttp2/client/insecure/channel_create_posix.c \
@@ -3848,6 +3890,7 @@
     src/core/ext/filters/client_channel/subchannel.c \
     src/core/ext/filters/client_channel/subchannel_index.c \
     src/core/ext/filters/client_channel/uri_parser.c \
+    src/core/ext/filters/deadline/deadline_filter.c \
     src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.c \
     src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.c \
     src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.c \
@@ -3879,6 +3922,7 @@
     src/core/ext/census/trace_context.c \
     src/core/ext/census/tracing.c \
     src/core/ext/filters/max_age/max_age_filter.c \
+    src/core/ext/filters/message_size/message_size_filter.c \
     src/core/plugin_registry/grpc_unsecure_plugin_registry.c \
 
 PUBLIC_HEADERS_C += \
@@ -3939,8 +3983,8 @@
 ifeq ($(SYSTEM),Darwin)
 	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -install_name $(SHARED_PREFIX)grpc_unsecure$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgrpc_unsecure$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBGRPC_UNSECURE_OBJS) $(LIBDIR)/$(CONFIG)/libgpr.a $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(LDLIBS)
 else
-	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgrpc_unsecure.so.3 -o $(LIBDIR)/$(CONFIG)/libgrpc_unsecure$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBGRPC_UNSECURE_OBJS) $(LIBDIR)/$(CONFIG)/libgpr.a $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(LDLIBS)
-	$(Q) ln -sf $(SHARED_PREFIX)grpc_unsecure$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/libgrpc_unsecure$(SHARED_VERSION_CORE).so.3
+	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgrpc_unsecure.so.4 -o $(LIBDIR)/$(CONFIG)/libgrpc_unsecure$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBGRPC_UNSECURE_OBJS) $(LIBDIR)/$(CONFIG)/libgpr.a $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(LDLIBS)
+	$(Q) ln -sf $(SHARED_PREFIX)grpc_unsecure$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/libgrpc_unsecure$(SHARED_VERSION_CORE).so.4
 	$(Q) ln -sf $(SHARED_PREFIX)grpc_unsecure$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/libgrpc_unsecure$(SHARED_VERSION_CORE).so
 endif
 endif
@@ -4073,15 +4117,10 @@
     src/core/lib/channel/channel_args.c \
     src/core/lib/channel/channel_stack.c \
     src/core/lib/channel/channel_stack_builder.c \
-    src/core/lib/channel/compress_filter.c \
     src/core/lib/channel/connected_channel.c \
-    src/core/lib/channel/deadline_filter.c \
     src/core/lib/channel/handshaker.c \
     src/core/lib/channel/handshaker_factory.c \
     src/core/lib/channel/handshaker_registry.c \
-    src/core/lib/channel/http_client_filter.c \
-    src/core/lib/channel/http_server_filter.c \
-    src/core/lib/channel/message_size_filter.c \
     src/core/lib/compression/compression.c \
     src/core/lib/compression/message_compress.c \
     src/core/lib/debug/trace.c \
@@ -4354,7 +4393,7 @@
 ifeq ($(SYSTEM),Darwin)
 	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -install_name $(SHARED_PREFIX)grpc++$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgrpc++$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBGRPC++_OBJS) $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) -lgrpc -lgpr
 else
-	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgrpc++.so.3 -o $(LIBDIR)/$(CONFIG)/libgrpc++$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBGRPC++_OBJS) $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) -lgrpc -lgpr
+	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgrpc++.so.1 -o $(LIBDIR)/$(CONFIG)/libgrpc++$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBGRPC++_OBJS) $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) -lgrpc -lgpr
 	$(Q) ln -sf $(SHARED_PREFIX)grpc++$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBDIR)/$(CONFIG)/libgrpc++$(SHARED_VERSION_CPP).so.1
 	$(Q) ln -sf $(SHARED_PREFIX)grpc++$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBDIR)/$(CONFIG)/libgrpc++$(SHARED_VERSION_CPP).so
 endif
@@ -4412,15 +4451,10 @@
     src/core/lib/channel/channel_args.c \
     src/core/lib/channel/channel_stack.c \
     src/core/lib/channel/channel_stack_builder.c \
-    src/core/lib/channel/compress_filter.c \
     src/core/lib/channel/connected_channel.c \
-    src/core/lib/channel/deadline_filter.c \
     src/core/lib/channel/handshaker.c \
     src/core/lib/channel/handshaker_factory.c \
     src/core/lib/channel/handshaker_registry.c \
-    src/core/lib/channel/http_client_filter.c \
-    src/core/lib/channel/http_server_filter.c \
-    src/core/lib/channel/message_size_filter.c \
     src/core/lib/compression/compression.c \
     src/core/lib/compression/message_compress.c \
     src/core/lib/debug/trace.c \
@@ -4554,6 +4588,7 @@
     src/core/ext/transport/chttp2/transport/hpack_encoder.c \
     src/core/ext/transport/chttp2/transport/hpack_parser.c \
     src/core/ext/transport/chttp2/transport/hpack_table.c \
+    src/core/ext/transport/chttp2/transport/http2_settings.c \
     src/core/ext/transport/chttp2/transport/huffsyms.c \
     src/core/ext/transport/chttp2/transport/incoming_metadata.c \
     src/core/ext/transport/chttp2/transport/parsing.c \
@@ -4562,6 +4597,10 @@
     src/core/ext/transport/chttp2/transport/varint.c \
     src/core/ext/transport/chttp2/transport/writing.c \
     src/core/ext/transport/chttp2/alpn/alpn.c \
+    src/core/ext/filters/http/client/http_client_filter.c \
+    src/core/ext/filters/http/http_filters_plugin.c \
+    src/core/ext/filters/http/message_compress/message_compress_filter.c \
+    src/core/ext/filters/http/server/http_server_filter.c \
     src/core/ext/filters/client_channel/channel_connectivity.c \
     src/core/ext/filters/client_channel/client_channel.c \
     src/core/ext/filters/client_channel/client_channel_factory.c \
@@ -4582,6 +4621,7 @@
     src/core/ext/filters/client_channel/subchannel.c \
     src/core/ext/filters/client_channel/subchannel_index.c \
     src/core/ext/filters/client_channel/uri_parser.c \
+    src/core/ext/filters/deadline/deadline_filter.c \
     src/core/ext/transport/chttp2/server/insecure/server_chttp2.c \
     src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c \
     src/core/ext/transport/chttp2/server/chttp2_server.c \
@@ -4753,7 +4793,7 @@
 ifeq ($(SYSTEM),Darwin)
 	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -install_name $(SHARED_PREFIX)grpc++_cronet$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgrpc++_cronet$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBGRPC++_CRONET_OBJS) $(OPENSSL_MERGE_LIBS) $(LDLIBS_SECURE) $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) -lgpr -lgrpc_cronet
 else
-	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgrpc++_cronet.so.3 -o $(LIBDIR)/$(CONFIG)/libgrpc++_cronet$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBGRPC++_CRONET_OBJS) $(OPENSSL_MERGE_LIBS) $(LDLIBS_SECURE) $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) -lgpr -lgrpc_cronet
+	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgrpc++_cronet.so.1 -o $(LIBDIR)/$(CONFIG)/libgrpc++_cronet$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBGRPC++_CRONET_OBJS) $(OPENSSL_MERGE_LIBS) $(LDLIBS_SECURE) $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) -lgpr -lgrpc_cronet
 	$(Q) ln -sf $(SHARED_PREFIX)grpc++_cronet$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBDIR)/$(CONFIG)/libgrpc++_cronet$(SHARED_VERSION_CPP).so.1
 	$(Q) ln -sf $(SHARED_PREFIX)grpc++_cronet$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBDIR)/$(CONFIG)/libgrpc++_cronet$(SHARED_VERSION_CPP).so
 endif
@@ -4770,6 +4810,77 @@
 endif
 
 
+LIBGRPC++_ERROR_DETAILS_SRC = \
+    $(GENDIR)/src/proto/grpc/status/status.pb.cc $(GENDIR)/src/proto/grpc/status/status.grpc.pb.cc \
+    src/cpp/util/error_details.cc \
+
+PUBLIC_HEADERS_CXX += \
+    include/grpc++/support/error_details.h \
+
+LIBGRPC++_ERROR_DETAILS_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBGRPC++_ERROR_DETAILS_SRC))))
+
+
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure libraries if you don't have OpenSSL.
+
+$(LIBDIR)/$(CONFIG)/libgrpc++_error_details.a: openssl_dep_error
+
+$(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc++_error_details$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP): openssl_dep_error
+
+else
+
+ifeq ($(NO_PROTOBUF),true)
+
+# You can't build a C++ library if you don't have protobuf - a bit overreached, but still okay.
+
+$(LIBDIR)/$(CONFIG)/libgrpc++_error_details.a: protobuf_dep_error
+
+$(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc++_error_details$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP): protobuf_dep_error
+
+else
+
+$(LIBDIR)/$(CONFIG)/libgrpc++_error_details.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(CARES_DEP) $(PROTOBUF_DEP) $(LIBGRPC++_ERROR_DETAILS_OBJS)  $(LIBGPR_OBJS)  $(ZLIB_MERGE_OBJS)  $(CARES_MERGE_OBJS) 
+	$(E) "[AR]      Creating $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libgrpc++_error_details.a
+	$(Q) $(AR) $(AROPTS) $(LIBDIR)/$(CONFIG)/libgrpc++_error_details.a $(LIBGRPC++_ERROR_DETAILS_OBJS)  $(LIBGPR_OBJS)  $(ZLIB_MERGE_OBJS)  $(CARES_MERGE_OBJS) 
+ifeq ($(SYSTEM),Darwin)
+	$(Q) ranlib -no_warning_for_no_symbols $(LIBDIR)/$(CONFIG)/libgrpc++_error_details.a
+endif
+
+
+
+ifeq ($(SYSTEM),MINGW32)
+$(LIBDIR)/$(CONFIG)/grpc++_error_details$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP): $(LIBGRPC++_ERROR_DETAILS_OBJS)  $(ZLIB_DEP) $(CARES_DEP) $(PROTOBUF_DEP) $(LIBDIR)/$(CONFIG)/grpc++$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(OPENSSL_DEP)
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,--output-def=$(LIBDIR)/$(CONFIG)/grpc++_error_details$(SHARED_VERSION_CPP).def -Wl,--out-implib=$(LIBDIR)/$(CONFIG)/libgrpc++_error_details$(SHARED_VERSION_CPP)-dll.a -o $(LIBDIR)/$(CONFIG)/grpc++_error_details$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBGRPC++_ERROR_DETAILS_OBJS) $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) -lgrpc++$(SHARED_VERSION_CPP)-dll
+else
+$(LIBDIR)/$(CONFIG)/libgrpc++_error_details$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP): $(LIBGRPC++_ERROR_DETAILS_OBJS)  $(ZLIB_DEP) $(CARES_DEP) $(PROTOBUF_DEP) $(LIBDIR)/$(CONFIG)/libgrpc++.$(SHARED_EXT_CPP) $(OPENSSL_DEP)
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+ifeq ($(SYSTEM),Darwin)
+	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -install_name $(SHARED_PREFIX)grpc++_error_details$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgrpc++_error_details$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBGRPC++_ERROR_DETAILS_OBJS) $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) -lgrpc++
+else
+	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgrpc++_error_details.so.1 -o $(LIBDIR)/$(CONFIG)/libgrpc++_error_details$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBGRPC++_ERROR_DETAILS_OBJS) $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) -lgrpc++
+	$(Q) ln -sf $(SHARED_PREFIX)grpc++_error_details$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBDIR)/$(CONFIG)/libgrpc++_error_details$(SHARED_VERSION_CPP).so.1
+	$(Q) ln -sf $(SHARED_PREFIX)grpc++_error_details$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBDIR)/$(CONFIG)/libgrpc++_error_details$(SHARED_VERSION_CPP).so
+endif
+endif
+
+endif
+
+endif
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(LIBGRPC++_ERROR_DETAILS_OBJS:.o=.dep)
+endif
+endif
+$(OBJDIR)/$(CONFIG)/src/cpp/util/error_details.o: $(GENDIR)/src/proto/grpc/status/status.pb.cc $(GENDIR)/src/proto/grpc/status/status.grpc.pb.cc
+
+
 LIBGRPC++_PROTO_REFLECTION_DESC_DB_SRC = \
     test/cpp/util/proto_reflection_descriptor_database.cc \
     $(GENDIR)/src/proto/grpc/reflection/v1alpha/reflection.pb.cc $(GENDIR)/src/proto/grpc/reflection/v1alpha/reflection.grpc.pb.cc \
@@ -4876,7 +4987,7 @@
 ifeq ($(SYSTEM),Darwin)
 	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -install_name $(SHARED_PREFIX)grpc++_reflection$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgrpc++_reflection$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBGRPC++_REFLECTION_OBJS) $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) -lgrpc++
 else
-	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgrpc++_reflection.so.3 -o $(LIBDIR)/$(CONFIG)/libgrpc++_reflection$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBGRPC++_REFLECTION_OBJS) $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) -lgrpc++
+	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgrpc++_reflection.so.1 -o $(LIBDIR)/$(CONFIG)/libgrpc++_reflection$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBGRPC++_REFLECTION_OBJS) $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) -lgrpc++
 	$(Q) ln -sf $(SHARED_PREFIX)grpc++_reflection$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBDIR)/$(CONFIG)/libgrpc++_reflection$(SHARED_VERSION_CPP).so.1
 	$(Q) ln -sf $(SHARED_PREFIX)grpc++_reflection$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBDIR)/$(CONFIG)/libgrpc++_reflection$(SHARED_VERSION_CPP).so
 endif
@@ -5103,15 +5214,10 @@
     src/core/lib/channel/channel_args.c \
     src/core/lib/channel/channel_stack.c \
     src/core/lib/channel/channel_stack_builder.c \
-    src/core/lib/channel/compress_filter.c \
     src/core/lib/channel/connected_channel.c \
-    src/core/lib/channel/deadline_filter.c \
     src/core/lib/channel/handshaker.c \
     src/core/lib/channel/handshaker_factory.c \
     src/core/lib/channel/handshaker_registry.c \
-    src/core/lib/channel/http_client_filter.c \
-    src/core/lib/channel/http_server_filter.c \
-    src/core/lib/channel/message_size_filter.c \
     src/core/lib/compression/compression.c \
     src/core/lib/compression/message_compress.c \
     src/core/lib/debug/trace.c \
@@ -5372,7 +5478,7 @@
 ifeq ($(SYSTEM),Darwin)
 	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -install_name $(SHARED_PREFIX)grpc++_unsecure$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBGRPC++_UNSECURE_OBJS) $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) -lgpr -lgrpc_unsecure
 else
-	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgrpc++_unsecure.so.3 -o $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBGRPC++_UNSECURE_OBJS) $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) -lgpr -lgrpc_unsecure
+	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgrpc++_unsecure.so.1 -o $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBGRPC++_UNSECURE_OBJS) $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) -lgpr -lgrpc_unsecure
 	$(Q) ln -sf $(SHARED_PREFIX)grpc++_unsecure$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure$(SHARED_VERSION_CPP).so.1
 	$(Q) ln -sf $(SHARED_PREFIX)grpc++_unsecure$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure$(SHARED_VERSION_CPP).so
 endif
@@ -5963,7 +6069,7 @@
 ifeq ($(SYSTEM),Darwin)
 	$(Q) $(LD) $(LDFLAGS) $(if $(subst Linux,,$(SYSTEM)),,-Wl$(comma)-wrap$(comma)memcpy) -L$(LIBDIR)/$(CONFIG) -install_name $(SHARED_PREFIX)grpc_csharp_ext$(SHARED_VERSION_CSHARP).$(SHARED_EXT_CSHARP) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgrpc_csharp_ext$(SHARED_VERSION_CSHARP).$(SHARED_EXT_CSHARP) $(LIBGRPC_CSHARP_EXT_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(LDLIBS)
 else
-	$(Q) $(LD) $(LDFLAGS) $(if $(subst Linux,,$(SYSTEM)),,-Wl$(comma)-wrap$(comma)memcpy) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgrpc_csharp_ext.so.3 -o $(LIBDIR)/$(CONFIG)/libgrpc_csharp_ext$(SHARED_VERSION_CSHARP).$(SHARED_EXT_CSHARP) $(LIBGRPC_CSHARP_EXT_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(LDLIBS)
+	$(Q) $(LD) $(LDFLAGS) $(if $(subst Linux,,$(SYSTEM)),,-Wl$(comma)-wrap$(comma)memcpy) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgrpc_csharp_ext.so.1 -o $(LIBDIR)/$(CONFIG)/libgrpc_csharp_ext$(SHARED_VERSION_CSHARP).$(SHARED_EXT_CSHARP) $(LIBGRPC_CSHARP_EXT_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(LDLIBS)
 	$(Q) ln -sf $(SHARED_PREFIX)grpc_csharp_ext$(SHARED_VERSION_CSHARP).$(SHARED_EXT_CSHARP) $(LIBDIR)/$(CONFIG)/libgrpc_csharp_ext$(SHARED_VERSION_CSHARP).so.1
 	$(Q) ln -sf $(SHARED_PREFIX)grpc_csharp_ext$(SHARED_VERSION_CSHARP).$(SHARED_EXT_CSHARP) $(LIBDIR)/$(CONFIG)/libgrpc_csharp_ext$(SHARED_VERSION_CSHARP).so
 endif
@@ -9299,6 +9405,38 @@
 endif
 
 
+FAKE_RESOLVER_TEST_SRC = \
+    test/core/client_channel/resolvers/fake_resolver_test.c \
+
+FAKE_RESOLVER_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(FAKE_RESOLVER_TEST_SRC))))
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/fake_resolver_test: openssl_dep_error
+
+else
+
+
+
+$(BINDIR)/$(CONFIG)/fake_resolver_test: $(FAKE_RESOLVER_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LD) $(LDFLAGS) $(FAKE_RESOLVER_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/fake_resolver_test
+
+endif
+
+$(OBJDIR)/$(CONFIG)/test/core/client_channel/resolvers/fake_resolver_test.o:  $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+
+deps_fake_resolver_test: $(FAKE_RESOLVER_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(FAKE_RESOLVER_TEST_OBJS:.o=.dep)
+endif
+endif
+
+
 FD_CONSERVATION_POSIX_TEST_SRC = \
     test/core/iomgr/fd_conservation_posix_test.c \
 
@@ -11507,6 +11645,38 @@
 endif
 
 
+MINIMAL_STACK_IS_MINIMAL_TEST_SRC = \
+    test/core/channel/minimal_stack_is_minimal_test.c \
+
+MINIMAL_STACK_IS_MINIMAL_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(MINIMAL_STACK_IS_MINIMAL_TEST_SRC))))
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/minimal_stack_is_minimal_test: openssl_dep_error
+
+else
+
+
+
+$(BINDIR)/$(CONFIG)/minimal_stack_is_minimal_test: $(MINIMAL_STACK_IS_MINIMAL_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LD) $(LDFLAGS) $(MINIMAL_STACK_IS_MINIMAL_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/minimal_stack_is_minimal_test
+
+endif
+
+$(OBJDIR)/$(CONFIG)/test/core/channel/minimal_stack_is_minimal_test.o:  $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+
+deps_minimal_stack_is_minimal_test: $(MINIMAL_STACK_IS_MINIMAL_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(MINIMAL_STACK_IS_MINIMAL_TEST_OBJS:.o=.dep)
+endif
+endif
+
+
 MLOG_TEST_SRC = \
     test/core/census/mlog_test.c \
 
@@ -14319,6 +14489,53 @@
 endif
 
 
+ERROR_DETAILS_TEST_SRC = \
+    $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.grpc.pb.cc \
+    test/cpp/util/error_details_test.cc \
+
+ERROR_DETAILS_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(ERROR_DETAILS_TEST_SRC))))
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/error_details_test: 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.0.0+.
+
+$(BINDIR)/$(CONFIG)/error_details_test: protobuf_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/error_details_test: $(PROTOBUF_DEP) $(ERROR_DETAILS_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++_error_details.a $(LIBDIR)/$(CONFIG)/libgrpc++.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LDXX) $(LDFLAGS) $(ERROR_DETAILS_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++_error_details.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/error_details_test
+
+endif
+
+endif
+
+$(OBJDIR)/$(CONFIG)/src/proto/grpc/testing/echo_messages.o:  $(LIBDIR)/$(CONFIG)/libgrpc++_error_details.a $(LIBDIR)/$(CONFIG)/libgrpc++.a
+
+$(OBJDIR)/$(CONFIG)/test/cpp/util/error_details_test.o:  $(LIBDIR)/$(CONFIG)/libgrpc++_error_details.a $(LIBDIR)/$(CONFIG)/libgrpc++.a
+
+deps_error_details_test: $(ERROR_DETAILS_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(ERROR_DETAILS_TEST_OBJS:.o=.dep)
+endif
+endif
+$(OBJDIR)/$(CONFIG)/test/cpp/util/error_details_test.o: $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.grpc.pb.cc
+
+
 FILTER_END2END_TEST_SRC = \
     test/cpp/end2end/filter_end2end_test.cc \
 
@@ -19273,6 +19490,7 @@
 src/cpp/ext/proto_server_reflection.cc: $(OPENSSL_DEP)
 src/cpp/ext/proto_server_reflection_plugin.cc: $(OPENSSL_DEP)
 src/cpp/server/secure_server_credentials.cc: $(OPENSSL_DEP)
+src/cpp/util/error_details.cc: $(OPENSSL_DEP)
 src/csharp/ext/grpc_csharp_ext.c: $(OPENSSL_DEP)
 test/core/bad_client/bad_client.c: $(OPENSSL_DEP)
 test/core/bad_ssl/server_common.c: $(OPENSSL_DEP)
diff --git a/binding.gyp b/binding.gyp
index 7553de1..e424d13 100644
--- a/binding.gyp
+++ b/binding.gyp
@@ -653,15 +653,10 @@
         'src/core/lib/channel/channel_args.c',
         'src/core/lib/channel/channel_stack.c',
         'src/core/lib/channel/channel_stack_builder.c',
-        'src/core/lib/channel/compress_filter.c',
         'src/core/lib/channel/connected_channel.c',
-        'src/core/lib/channel/deadline_filter.c',
         'src/core/lib/channel/handshaker.c',
         'src/core/lib/channel/handshaker_factory.c',
         'src/core/lib/channel/handshaker_registry.c',
-        'src/core/lib/channel/http_client_filter.c',
-        'src/core/lib/channel/http_server_filter.c',
-        'src/core/lib/channel/message_size_filter.c',
         'src/core/lib/compression/compression.c',
         'src/core/lib/compression/message_compress.c',
         'src/core/lib/debug/trace.c',
@@ -789,6 +784,7 @@
         'src/core/ext/transport/chttp2/transport/hpack_encoder.c',
         'src/core/ext/transport/chttp2/transport/hpack_parser.c',
         'src/core/ext/transport/chttp2/transport/hpack_table.c',
+        'src/core/ext/transport/chttp2/transport/http2_settings.c',
         'src/core/ext/transport/chttp2/transport/huffsyms.c',
         'src/core/ext/transport/chttp2/transport/incoming_metadata.c',
         'src/core/ext/transport/chttp2/transport/parsing.c',
@@ -797,6 +793,10 @@
         'src/core/ext/transport/chttp2/transport/varint.c',
         'src/core/ext/transport/chttp2/transport/writing.c',
         'src/core/ext/transport/chttp2/alpn/alpn.c',
+        'src/core/ext/filters/http/client/http_client_filter.c',
+        'src/core/ext/filters/http/http_filters_plugin.c',
+        'src/core/ext/filters/http/message_compress/message_compress_filter.c',
+        'src/core/ext/filters/http/server/http_server_filter.c',
         'src/core/lib/http/httpcli_security_connector.c',
         'src/core/lib/security/context/security_context.c',
         'src/core/lib/security/credentials/composite/composite_credentials.c',
@@ -846,6 +846,7 @@
         'src/core/ext/filters/client_channel/subchannel.c',
         'src/core/ext/filters/client_channel/subchannel_index.c',
         'src/core/ext/filters/client_channel/uri_parser.c',
+        'src/core/ext/filters/deadline/deadline_filter.c',
         'src/core/ext/transport/chttp2/client/chttp2_connector.c',
         'src/core/ext/transport/chttp2/server/insecure/server_chttp2.c',
         'src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c',
@@ -882,6 +883,7 @@
         'src/core/ext/census/trace_context.c',
         'src/core/ext/census/tracing.c',
         'src/core/ext/filters/max_age/max_age_filter.c',
+        'src/core/ext/filters/message_size/message_size_filter.c',
         'src/core/plugin_registry/grpc_plugin_registry.c',
       ],
       "conditions": [
diff --git a/build.yaml b/build.yaml
index 2dca652..f4461e4 100644
--- a/build.yaml
+++ b/build.yaml
@@ -6,15 +6,15 @@
   '#02': ===
   '#03': Please update the 'g_stands_for' field periodically with a new g word
   '#04': not listed in doc/g_stands_for.md - and update that document to list the
-  '#05': new word.
+  '#05': new word. When doing so, please also update BUILD.
   '#06': ===
   '#07': Master always has a "-dev" suffix
   '#08': Use "-preN" suffixes to identify pre-release versions
   '#09': Per-language overrides are possible with (eg) ruby_version tag here
   '#10': See the expand_version.py for all the quirks here
-  core_version: 3.0.0-dev
+  core_version: 4.0.0-dev
   g_stands_for: gentle
-  version: 1.3.0-dev
+  version: 1.4.0-dev
 filegroups:
 - name: census
   public_headers:
@@ -176,16 +176,11 @@
   - src/core/lib/channel/channel_args.h
   - src/core/lib/channel/channel_stack.h
   - src/core/lib/channel/channel_stack_builder.h
-  - src/core/lib/channel/compress_filter.h
   - src/core/lib/channel/connected_channel.h
   - src/core/lib/channel/context.h
-  - src/core/lib/channel/deadline_filter.h
   - src/core/lib/channel/handshaker.h
   - src/core/lib/channel/handshaker_factory.h
   - src/core/lib/channel/handshaker_registry.h
-  - src/core/lib/channel/http_client_filter.h
-  - src/core/lib/channel/http_server_filter.h
-  - src/core/lib/channel/message_size_filter.h
   - src/core/lib/compression/algorithm_metadata.h
   - src/core/lib/compression/message_compress.h
   - src/core/lib/debug/trace.h
@@ -288,15 +283,10 @@
   - src/core/lib/channel/channel_args.c
   - src/core/lib/channel/channel_stack.c
   - src/core/lib/channel/channel_stack_builder.c
-  - src/core/lib/channel/compress_filter.c
   - src/core/lib/channel/connected_channel.c
-  - src/core/lib/channel/deadline_filter.c
   - src/core/lib/channel/handshaker.c
   - src/core/lib/channel/handshaker_factory.c
   - src/core/lib/channel/handshaker_registry.c
-  - src/core/lib/channel/http_client_filter.c
-  - src/core/lib/channel/http_server_filter.c
-  - src/core/lib/channel/message_size_filter.c
   - src/core/lib/compression/compression.c
   - src/core/lib/compression/message_compress.c
   - src/core/lib/debug/trace.c
@@ -458,6 +448,7 @@
   plugin: grpc_client_channel
   uses:
   - grpc_base
+  - grpc_deadline_filter
 - name: grpc_codegen
   public_headers:
   - include/grpc/impl/codegen/byte_buffer_reader.h
@@ -470,6 +461,27 @@
   - include/grpc/impl/codegen/status.h
   uses:
   - gpr_codegen
+- name: grpc_deadline_filter
+  headers:
+  - src/core/ext/filters/deadline/deadline_filter.h
+  src:
+  - src/core/ext/filters/deadline/deadline_filter.c
+  plugin: grpc_deadline_filter
+  uses:
+  - grpc_base
+- name: grpc_http_filters
+  headers:
+  - src/core/ext/filters/http/client/http_client_filter.h
+  - src/core/ext/filters/http/message_compress/message_compress_filter.h
+  - src/core/ext/filters/http/server/http_server_filter.h
+  src:
+  - src/core/ext/filters/http/client/http_client_filter.c
+  - src/core/ext/filters/http/http_filters_plugin.c
+  - src/core/ext/filters/http/message_compress/message_compress_filter.c
+  - src/core/ext/filters/http/server/http_server_filter.c
+  plugin: grpc_http_filters
+  uses:
+  - grpc_base
 - name: grpc_lb_policy_grpclb
   headers:
   - src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.h
@@ -535,6 +547,14 @@
   plugin: grpc_max_age_filter
   uses:
   - grpc_base
+- name: grpc_message_size_filter
+  headers:
+  - src/core/ext/filters/message_size/message_size_filter.h
+  src:
+  - src/core/ext/filters/message_size/message_size_filter.c
+  plugin: grpc_message_size_filter
+  uses:
+  - grpc_base
 - name: grpc_resolver_dns_ares
   headers:
   - src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h
@@ -666,6 +686,7 @@
   - src/core/ext/transport/chttp2/transport/hpack_encoder.h
   - src/core/ext/transport/chttp2/transport/hpack_parser.h
   - src/core/ext/transport/chttp2/transport/hpack_table.h
+  - src/core/ext/transport/chttp2/transport/http2_settings.h
   - src/core/ext/transport/chttp2/transport/huffsyms.h
   - src/core/ext/transport/chttp2/transport/incoming_metadata.h
   - src/core/ext/transport/chttp2/transport/internal.h
@@ -685,6 +706,7 @@
   - src/core/ext/transport/chttp2/transport/hpack_encoder.c
   - src/core/ext/transport/chttp2/transport/hpack_parser.c
   - src/core/ext/transport/chttp2/transport/hpack_table.c
+  - src/core/ext/transport/chttp2/transport/http2_settings.c
   - src/core/ext/transport/chttp2/transport/huffsyms.c
   - src/core/ext/transport/chttp2/transport/incoming_metadata.c
   - src/core/ext/transport/chttp2/transport/parsing.c
@@ -696,6 +718,7 @@
   uses:
   - grpc_base
   - grpc_transport_chttp2_alpn
+  - grpc_http_filters
 - name: grpc_transport_chttp2_alpn
   headers:
   - src/core/ext/transport/chttp2/alpn/alpn.h
@@ -769,6 +792,7 @@
   filegroups:
   - grpc_base
   - grpc_transport_chttp2
+  - grpc_http_filters
 - name: nanopb
   headers:
   - third_party/nanopb/pb.h
@@ -999,6 +1023,8 @@
   - grpc_secure
   - census
   - grpc_max_age_filter
+  - grpc_message_size_filter
+  - grpc_deadline_filter
   generate_plugin_registry: true
   secure: true
   vs_packages:
@@ -1096,6 +1122,8 @@
   - grpc_lb_policy_round_robin
   - census
   - grpc_max_age_filter
+  - grpc_message_size_filter
+  - grpc_deadline_filter
   generate_plugin_registry: true
   secure: false
   vs_project_guid: '{46CEDFFF-9692-456A-AA24-38B5D6BCF4C5}'
@@ -1175,6 +1203,18 @@
   platforms:
   - linux
   secure: true
+- name: grpc++_error_details
+  build: all
+  language: c++
+  public_headers:
+  - include/grpc++/support/error_details.h
+  src:
+  - src/proto/grpc/status/status.proto
+  - src/cpp/util/error_details.cc
+  deps:
+  - grpc++
+  baselib: true
+  vs_project_guid: '{9F58AD72-49E1-4D10-B826-9E190AB0AAC0}'
 - name: grpc++_proto_reflection_desc_db
   build: private
   language: c++
@@ -1780,6 +1820,16 @@
   - uv
   platforms:
   - linux
+- name: fake_resolver_test
+  build: test
+  language: c
+  src:
+  - test/core/client_channel/resolvers/fake_resolver_test.c
+  deps:
+  - grpc_test_util
+  - grpc
+  - gpr_test_util
+  - gpr
 - name: fd_conservation_posix_test
   build: test
   language: c
@@ -2506,6 +2556,16 @@
   - grpc
   - gpr_test_util
   - gpr
+- name: minimal_stack_is_minimal_test
+  build: test
+  language: c
+  src:
+  - test/core/channel/minimal_stack_is_minimal_test.c
+  deps:
+  - grpc_test_util
+  - grpc
+  - gpr_test_util
+  - gpr
 - name: mlog_test
   flaky: true
   build: test
@@ -3567,6 +3627,16 @@
   - grpc
   - gpr_test_util
   - gpr
+- name: error_details_test
+  gtest: true
+  build: test
+  language: c++
+  src:
+  - src/proto/grpc/testing/echo_messages.proto
+  - test/cpp/util/error_details_test.cc
+  deps:
+  - grpc++_error_details
+  - grpc++
 - name: filter_end2end_test
   gtest: true
   build: test
diff --git a/build_config.rb b/build_config.rb
index b5a8c20..9a69070 100644
--- a/build_config.rb
+++ b/build_config.rb
@@ -28,5 +28,5 @@
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 module GrpcBuildConfig
-  CORE_WINDOWS_DLL = '/tmp/libs/opt/grpc-3.dll'
+  CORE_WINDOWS_DLL = '/tmp/libs/opt/grpc-4.dll'
 end
diff --git a/config.m4 b/config.m4
index 9470e43..17fdb14 100644
--- a/config.m4
+++ b/config.m4
@@ -86,15 +86,10 @@
     src/core/lib/channel/channel_args.c \
     src/core/lib/channel/channel_stack.c \
     src/core/lib/channel/channel_stack_builder.c \
-    src/core/lib/channel/compress_filter.c \
     src/core/lib/channel/connected_channel.c \
-    src/core/lib/channel/deadline_filter.c \
     src/core/lib/channel/handshaker.c \
     src/core/lib/channel/handshaker_factory.c \
     src/core/lib/channel/handshaker_registry.c \
-    src/core/lib/channel/http_client_filter.c \
-    src/core/lib/channel/http_server_filter.c \
-    src/core/lib/channel/message_size_filter.c \
     src/core/lib/compression/compression.c \
     src/core/lib/compression/message_compress.c \
     src/core/lib/debug/trace.c \
@@ -222,6 +217,7 @@
     src/core/ext/transport/chttp2/transport/hpack_encoder.c \
     src/core/ext/transport/chttp2/transport/hpack_parser.c \
     src/core/ext/transport/chttp2/transport/hpack_table.c \
+    src/core/ext/transport/chttp2/transport/http2_settings.c \
     src/core/ext/transport/chttp2/transport/huffsyms.c \
     src/core/ext/transport/chttp2/transport/incoming_metadata.c \
     src/core/ext/transport/chttp2/transport/parsing.c \
@@ -230,6 +226,10 @@
     src/core/ext/transport/chttp2/transport/varint.c \
     src/core/ext/transport/chttp2/transport/writing.c \
     src/core/ext/transport/chttp2/alpn/alpn.c \
+    src/core/ext/filters/http/client/http_client_filter.c \
+    src/core/ext/filters/http/http_filters_plugin.c \
+    src/core/ext/filters/http/message_compress/message_compress_filter.c \
+    src/core/ext/filters/http/server/http_server_filter.c \
     src/core/lib/http/httpcli_security_connector.c \
     src/core/lib/security/context/security_context.c \
     src/core/lib/security/credentials/composite/composite_credentials.c \
@@ -279,6 +279,7 @@
     src/core/ext/filters/client_channel/subchannel.c \
     src/core/ext/filters/client_channel/subchannel_index.c \
     src/core/ext/filters/client_channel/uri_parser.c \
+    src/core/ext/filters/deadline/deadline_filter.c \
     src/core/ext/transport/chttp2/client/chttp2_connector.c \
     src/core/ext/transport/chttp2/server/insecure/server_chttp2.c \
     src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c \
@@ -315,6 +316,7 @@
     src/core/ext/census/trace_context.c \
     src/core/ext/census/tracing.c \
     src/core/ext/filters/max_age/max_age_filter.c \
+    src/core/ext/filters/message_size/message_size_filter.c \
     src/core/plugin_registry/grpc_plugin_registry.c \
     src/boringssl/err_data.c \
     third_party/boringssl/crypto/aes/aes.c \
@@ -638,8 +640,14 @@
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/filters/client_channel/resolver/dns/c_ares)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/filters/client_channel/resolver/dns/native)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/filters/client_channel/resolver/sockaddr)
+  PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/filters/deadline)
+  PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/filters/http)
+  PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/filters/http/client)
+  PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/filters/http/message_compress)
+  PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/filters/http/server)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/filters/load_reporting)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/filters/max_age)
+  PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/filters/message_size)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/transport/chttp2/alpn)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/transport/chttp2/client)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/transport/chttp2/client/insecure)
diff --git a/doc/statuscodes.md b/doc/statuscodes.md
index 1cd72df..f2df9e0 100644
--- a/doc/statuscodes.md
+++ b/doc/statuscodes.md
@@ -1,9 +1,20 @@
 # Status codes and their use in gRPC
 
-gRPC uses a set of well defined status codes as part of the RPC API. All RPCs started at a client return  a `status` object composed of an integer `code` and a string `message`. The server-side can choose the status it returns for a given RPC.
+gRPC uses a set of well defined status codes as part of the RPC API. All
+RPCs started at a client return  a `status` object composed of an integer
+`code` and a string `message`. The server-side can choose the status it
+returns for a given RPC.
 
-The gRPC client and server-side implementations may also generate and return `status` on their own when errors happen.  
-Only a subset of the pre-defined status codes are generated by the gRPC libraries. The following table lists these codes and summarizes the situations in which they are generated, either by the client or the server-side library implementation.
+The gRPC client and server-side implementations may also generate and
+return `status` on their own when errors happen.  Only a subset of
+the pre-defined status codes are generated by the gRPC libraries.  This
+allows applications to be sure that any other code it sees was actually
+returned by the application (although it is also possible for the
+server-side to return one of the codes generated by the gRPC libraries).
+
+The following table lists the codes that may be returned by the gRPC
+libraries (on either the client-side or server-side) and summarizes the
+situations in which they are generated.
 
 | Case        | Code           | Generated at Client or Server  |
 | ------------- |:-------------| :-----:|
@@ -26,7 +37,7 @@
 | Response cardinality violation (method requires exactly one response but server sent some other number of responses) | UNIMPLEMENTED | Client|
 | Error parsing response proto	| INTERNAL | Client|
 | Error parsing request proto	| INTERNAL | Server|
-
+| Sent or received message was larger than configured limit | RESOURCE_EXHAUSTED | Both |
 
 The following status codes are never generated by the library:
 - INVALID_ARGUMENT
diff --git a/examples/csharp/helloworld-from-cli/global.json b/examples/csharp/helloworld-from-cli/global.json
index 32ff399..f3c33ce 100644
--- a/examples/csharp/helloworld-from-cli/global.json
+++ b/examples/csharp/helloworld-from-cli/global.json
@@ -1,5 +1,5 @@
 {
     "sdk": {
-        "version": "1.0.0-preview2-003121"
+        "version": "1.0.0-preview2-003131"
     }
 }
\ No newline at end of file
diff --git a/gRPC-Core.podspec b/gRPC-Core.podspec
index 2e26018..4bd9cd9 100644
--- a/gRPC-Core.podspec
+++ b/gRPC-Core.podspec
@@ -37,7 +37,7 @@
 
 Pod::Spec.new do |s|
   s.name     = 'gRPC-Core'
-  version = '1.3.0-dev'
+  version = '1.4.0-dev'
   s.version  = version
   s.summary  = 'Core cross-platform gRPC library, written in C'
   s.homepage = 'http://www.grpc.io'
@@ -258,16 +258,11 @@
                       'src/core/lib/channel/channel_args.h',
                       'src/core/lib/channel/channel_stack.h',
                       'src/core/lib/channel/channel_stack_builder.h',
-                      'src/core/lib/channel/compress_filter.h',
                       'src/core/lib/channel/connected_channel.h',
                       'src/core/lib/channel/context.h',
-                      'src/core/lib/channel/deadline_filter.h',
                       'src/core/lib/channel/handshaker.h',
                       'src/core/lib/channel/handshaker_factory.h',
                       'src/core/lib/channel/handshaker_registry.h',
-                      'src/core/lib/channel/http_client_filter.h',
-                      'src/core/lib/channel/http_server_filter.h',
-                      'src/core/lib/channel/message_size_filter.h',
                       'src/core/lib/compression/algorithm_metadata.h',
                       'src/core/lib/compression/message_compress.h',
                       'src/core/lib/debug/trace.h',
@@ -379,12 +374,16 @@
                       'src/core/ext/transport/chttp2/transport/hpack_encoder.h',
                       'src/core/ext/transport/chttp2/transport/hpack_parser.h',
                       'src/core/ext/transport/chttp2/transport/hpack_table.h',
+                      'src/core/ext/transport/chttp2/transport/http2_settings.h',
                       'src/core/ext/transport/chttp2/transport/huffsyms.h',
                       'src/core/ext/transport/chttp2/transport/incoming_metadata.h',
                       'src/core/ext/transport/chttp2/transport/internal.h',
                       'src/core/ext/transport/chttp2/transport/stream_map.h',
                       'src/core/ext/transport/chttp2/transport/varint.h',
                       'src/core/ext/transport/chttp2/alpn/alpn.h',
+                      'src/core/ext/filters/http/client/http_client_filter.h',
+                      'src/core/ext/filters/http/message_compress/message_compress_filter.h',
+                      'src/core/ext/filters/http/server/http_server_filter.h',
                       'src/core/lib/security/context/security_context.h',
                       'src/core/lib/security/credentials/composite/composite_credentials.h',
                       'src/core/lib/security/credentials/credentials.h',
@@ -428,6 +427,7 @@
                       'src/core/ext/filters/client_channel/subchannel.h',
                       'src/core/ext/filters/client_channel/subchannel_index.h',
                       'src/core/ext/filters/client_channel/uri_parser.h',
+                      'src/core/ext/filters/deadline/deadline_filter.h',
                       'src/core/ext/transport/chttp2/client/chttp2_connector.h',
                       'src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.h',
                       'src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h',
@@ -458,19 +458,15 @@
                       'src/core/ext/census/trace_string.h',
                       'src/core/ext/census/tracing.h',
                       'src/core/ext/filters/max_age/max_age_filter.h',
+                      'src/core/ext/filters/message_size/message_size_filter.h',
                       'src/core/lib/surface/init.c',
                       'src/core/lib/channel/channel_args.c',
                       'src/core/lib/channel/channel_stack.c',
                       'src/core/lib/channel/channel_stack_builder.c',
-                      'src/core/lib/channel/compress_filter.c',
                       'src/core/lib/channel/connected_channel.c',
-                      'src/core/lib/channel/deadline_filter.c',
                       'src/core/lib/channel/handshaker.c',
                       'src/core/lib/channel/handshaker_factory.c',
                       'src/core/lib/channel/handshaker_registry.c',
-                      'src/core/lib/channel/http_client_filter.c',
-                      'src/core/lib/channel/http_server_filter.c',
-                      'src/core/lib/channel/message_size_filter.c',
                       'src/core/lib/compression/compression.c',
                       'src/core/lib/compression/message_compress.c',
                       'src/core/lib/debug/trace.c',
@@ -598,6 +594,7 @@
                       'src/core/ext/transport/chttp2/transport/hpack_encoder.c',
                       'src/core/ext/transport/chttp2/transport/hpack_parser.c',
                       'src/core/ext/transport/chttp2/transport/hpack_table.c',
+                      'src/core/ext/transport/chttp2/transport/http2_settings.c',
                       'src/core/ext/transport/chttp2/transport/huffsyms.c',
                       'src/core/ext/transport/chttp2/transport/incoming_metadata.c',
                       'src/core/ext/transport/chttp2/transport/parsing.c',
@@ -606,6 +603,10 @@
                       'src/core/ext/transport/chttp2/transport/varint.c',
                       'src/core/ext/transport/chttp2/transport/writing.c',
                       'src/core/ext/transport/chttp2/alpn/alpn.c',
+                      'src/core/ext/filters/http/client/http_client_filter.c',
+                      'src/core/ext/filters/http/http_filters_plugin.c',
+                      'src/core/ext/filters/http/message_compress/message_compress_filter.c',
+                      'src/core/ext/filters/http/server/http_server_filter.c',
                       'src/core/lib/http/httpcli_security_connector.c',
                       'src/core/lib/security/context/security_context.c',
                       'src/core/lib/security/credentials/composite/composite_credentials.c',
@@ -655,6 +656,7 @@
                       'src/core/ext/filters/client_channel/subchannel.c',
                       'src/core/ext/filters/client_channel/subchannel_index.c',
                       'src/core/ext/filters/client_channel/uri_parser.c',
+                      'src/core/ext/filters/deadline/deadline_filter.c',
                       'src/core/ext/transport/chttp2/client/chttp2_connector.c',
                       'src/core/ext/transport/chttp2/server/insecure/server_chttp2.c',
                       'src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c',
@@ -691,6 +693,7 @@
                       'src/core/ext/census/trace_context.c',
                       'src/core/ext/census/tracing.c',
                       'src/core/ext/filters/max_age/max_age_filter.c',
+                      'src/core/ext/filters/message_size/message_size_filter.c',
                       'src/core/plugin_registry/grpc_plugin_registry.c'
 
     ss.private_header_files = 'src/core/lib/profiling/timers.h',
@@ -710,16 +713,11 @@
                               'src/core/lib/channel/channel_args.h',
                               'src/core/lib/channel/channel_stack.h',
                               'src/core/lib/channel/channel_stack_builder.h',
-                              'src/core/lib/channel/compress_filter.h',
                               'src/core/lib/channel/connected_channel.h',
                               'src/core/lib/channel/context.h',
-                              'src/core/lib/channel/deadline_filter.h',
                               'src/core/lib/channel/handshaker.h',
                               'src/core/lib/channel/handshaker_factory.h',
                               'src/core/lib/channel/handshaker_registry.h',
-                              'src/core/lib/channel/http_client_filter.h',
-                              'src/core/lib/channel/http_server_filter.h',
-                              'src/core/lib/channel/message_size_filter.h',
                               'src/core/lib/compression/algorithm_metadata.h',
                               'src/core/lib/compression/message_compress.h',
                               'src/core/lib/debug/trace.h',
@@ -831,12 +829,16 @@
                               'src/core/ext/transport/chttp2/transport/hpack_encoder.h',
                               'src/core/ext/transport/chttp2/transport/hpack_parser.h',
                               'src/core/ext/transport/chttp2/transport/hpack_table.h',
+                              'src/core/ext/transport/chttp2/transport/http2_settings.h',
                               'src/core/ext/transport/chttp2/transport/huffsyms.h',
                               'src/core/ext/transport/chttp2/transport/incoming_metadata.h',
                               'src/core/ext/transport/chttp2/transport/internal.h',
                               'src/core/ext/transport/chttp2/transport/stream_map.h',
                               'src/core/ext/transport/chttp2/transport/varint.h',
                               'src/core/ext/transport/chttp2/alpn/alpn.h',
+                              'src/core/ext/filters/http/client/http_client_filter.h',
+                              'src/core/ext/filters/http/message_compress/message_compress_filter.h',
+                              'src/core/ext/filters/http/server/http_server_filter.h',
                               'src/core/lib/security/context/security_context.h',
                               'src/core/lib/security/credentials/composite/composite_credentials.h',
                               'src/core/lib/security/credentials/credentials.h',
@@ -880,6 +882,7 @@
                               'src/core/ext/filters/client_channel/subchannel.h',
                               'src/core/ext/filters/client_channel/subchannel_index.h',
                               'src/core/ext/filters/client_channel/uri_parser.h',
+                              'src/core/ext/filters/deadline/deadline_filter.h',
                               'src/core/ext/transport/chttp2/client/chttp2_connector.h',
                               'src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.h',
                               'src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h',
@@ -909,7 +912,8 @@
                               'src/core/ext/census/trace_status.h',
                               'src/core/ext/census/trace_string.h',
                               'src/core/ext/census/tracing.h',
-                              'src/core/ext/filters/max_age/max_age_filter.h'
+                              'src/core/ext/filters/max_age/max_age_filter.h',
+                              'src/core/ext/filters/message_size/message_size_filter.h'
   end
 
   s.subspec 'Cronet-Interface' do |ss|
diff --git a/gRPC-ProtoRPC.podspec b/gRPC-ProtoRPC.podspec
index 1940015..62cb0d1 100644
--- a/gRPC-ProtoRPC.podspec
+++ b/gRPC-ProtoRPC.podspec
@@ -36,7 +36,7 @@
 
 Pod::Spec.new do |s|
   s.name     = 'gRPC-ProtoRPC'
-  version = '1.3.0-dev'
+  version = '1.4.0-dev'
   s.version  = version
   s.summary  = 'RPC library for Protocol Buffers, based on gRPC'
   s.homepage = 'http://www.grpc.io'
diff --git a/gRPC-RxLibrary.podspec b/gRPC-RxLibrary.podspec
index 841a853..77ceb22 100644
--- a/gRPC-RxLibrary.podspec
+++ b/gRPC-RxLibrary.podspec
@@ -36,7 +36,7 @@
 
 Pod::Spec.new do |s|
   s.name     = 'gRPC-RxLibrary'
-  version = '1.3.0-dev'
+  version = '1.4.0-dev'
   s.version  = version
   s.summary  = 'Reactive Extensions library for iOS/OSX.'
   s.homepage = 'http://www.grpc.io'
diff --git a/gRPC.podspec b/gRPC.podspec
index 08ea791..10520bd 100644
--- a/gRPC.podspec
+++ b/gRPC.podspec
@@ -35,7 +35,7 @@
 
 Pod::Spec.new do |s|
   s.name     = 'gRPC'
-  version = '1.3.0-dev'
+  version = '1.4.0-dev'
   s.version  = version
   s.summary  = 'gRPC client library for iOS/OSX'
   s.homepage = 'http://www.grpc.io'
diff --git a/grpc.def b/grpc.def
index 1589316..841d55f 100644
--- a/grpc.def
+++ b/grpc.def
@@ -72,7 +72,6 @@
     grpc_channel_create_registered_call
     grpc_call_start_batch
     grpc_call_get_peer
-    grpc_call_set_load_reporting_cost_context
     grpc_census_call_set_context
     grpc_census_call_get_context
     grpc_channel_get_target
diff --git a/grpc.gemspec b/grpc.gemspec
index cd4f078..e53bd29 100755
--- a/grpc.gemspec
+++ b/grpc.gemspec
@@ -174,16 +174,11 @@
   s.files += %w( src/core/lib/channel/channel_args.h )
   s.files += %w( src/core/lib/channel/channel_stack.h )
   s.files += %w( src/core/lib/channel/channel_stack_builder.h )
-  s.files += %w( src/core/lib/channel/compress_filter.h )
   s.files += %w( src/core/lib/channel/connected_channel.h )
   s.files += %w( src/core/lib/channel/context.h )
-  s.files += %w( src/core/lib/channel/deadline_filter.h )
   s.files += %w( src/core/lib/channel/handshaker.h )
   s.files += %w( src/core/lib/channel/handshaker_factory.h )
   s.files += %w( src/core/lib/channel/handshaker_registry.h )
-  s.files += %w( src/core/lib/channel/http_client_filter.h )
-  s.files += %w( src/core/lib/channel/http_server_filter.h )
-  s.files += %w( src/core/lib/channel/message_size_filter.h )
   s.files += %w( src/core/lib/compression/algorithm_metadata.h )
   s.files += %w( src/core/lib/compression/message_compress.h )
   s.files += %w( src/core/lib/debug/trace.h )
@@ -295,12 +290,16 @@
   s.files += %w( src/core/ext/transport/chttp2/transport/hpack_encoder.h )
   s.files += %w( src/core/ext/transport/chttp2/transport/hpack_parser.h )
   s.files += %w( src/core/ext/transport/chttp2/transport/hpack_table.h )
+  s.files += %w( src/core/ext/transport/chttp2/transport/http2_settings.h )
   s.files += %w( src/core/ext/transport/chttp2/transport/huffsyms.h )
   s.files += %w( src/core/ext/transport/chttp2/transport/incoming_metadata.h )
   s.files += %w( src/core/ext/transport/chttp2/transport/internal.h )
   s.files += %w( src/core/ext/transport/chttp2/transport/stream_map.h )
   s.files += %w( src/core/ext/transport/chttp2/transport/varint.h )
   s.files += %w( src/core/ext/transport/chttp2/alpn/alpn.h )
+  s.files += %w( src/core/ext/filters/http/client/http_client_filter.h )
+  s.files += %w( src/core/ext/filters/http/message_compress/message_compress_filter.h )
+  s.files += %w( src/core/ext/filters/http/server/http_server_filter.h )
   s.files += %w( src/core/lib/security/context/security_context.h )
   s.files += %w( src/core/lib/security/credentials/composite/composite_credentials.h )
   s.files += %w( src/core/lib/security/credentials/credentials.h )
@@ -344,6 +343,7 @@
   s.files += %w( src/core/ext/filters/client_channel/subchannel.h )
   s.files += %w( src/core/ext/filters/client_channel/subchannel_index.h )
   s.files += %w( src/core/ext/filters/client_channel/uri_parser.h )
+  s.files += %w( src/core/ext/filters/deadline/deadline_filter.h )
   s.files += %w( src/core/ext/transport/chttp2/client/chttp2_connector.h )
   s.files += %w( src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.h )
   s.files += %w( src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h )
@@ -374,19 +374,15 @@
   s.files += %w( src/core/ext/census/trace_string.h )
   s.files += %w( src/core/ext/census/tracing.h )
   s.files += %w( src/core/ext/filters/max_age/max_age_filter.h )
+  s.files += %w( src/core/ext/filters/message_size/message_size_filter.h )
   s.files += %w( src/core/lib/surface/init.c )
   s.files += %w( src/core/lib/channel/channel_args.c )
   s.files += %w( src/core/lib/channel/channel_stack.c )
   s.files += %w( src/core/lib/channel/channel_stack_builder.c )
-  s.files += %w( src/core/lib/channel/compress_filter.c )
   s.files += %w( src/core/lib/channel/connected_channel.c )
-  s.files += %w( src/core/lib/channel/deadline_filter.c )
   s.files += %w( src/core/lib/channel/handshaker.c )
   s.files += %w( src/core/lib/channel/handshaker_factory.c )
   s.files += %w( src/core/lib/channel/handshaker_registry.c )
-  s.files += %w( src/core/lib/channel/http_client_filter.c )
-  s.files += %w( src/core/lib/channel/http_server_filter.c )
-  s.files += %w( src/core/lib/channel/message_size_filter.c )
   s.files += %w( src/core/lib/compression/compression.c )
   s.files += %w( src/core/lib/compression/message_compress.c )
   s.files += %w( src/core/lib/debug/trace.c )
@@ -514,6 +510,7 @@
   s.files += %w( src/core/ext/transport/chttp2/transport/hpack_encoder.c )
   s.files += %w( src/core/ext/transport/chttp2/transport/hpack_parser.c )
   s.files += %w( src/core/ext/transport/chttp2/transport/hpack_table.c )
+  s.files += %w( src/core/ext/transport/chttp2/transport/http2_settings.c )
   s.files += %w( src/core/ext/transport/chttp2/transport/huffsyms.c )
   s.files += %w( src/core/ext/transport/chttp2/transport/incoming_metadata.c )
   s.files += %w( src/core/ext/transport/chttp2/transport/parsing.c )
@@ -522,6 +519,10 @@
   s.files += %w( src/core/ext/transport/chttp2/transport/varint.c )
   s.files += %w( src/core/ext/transport/chttp2/transport/writing.c )
   s.files += %w( src/core/ext/transport/chttp2/alpn/alpn.c )
+  s.files += %w( src/core/ext/filters/http/client/http_client_filter.c )
+  s.files += %w( src/core/ext/filters/http/http_filters_plugin.c )
+  s.files += %w( src/core/ext/filters/http/message_compress/message_compress_filter.c )
+  s.files += %w( src/core/ext/filters/http/server/http_server_filter.c )
   s.files += %w( src/core/lib/http/httpcli_security_connector.c )
   s.files += %w( src/core/lib/security/context/security_context.c )
   s.files += %w( src/core/lib/security/credentials/composite/composite_credentials.c )
@@ -571,6 +572,7 @@
   s.files += %w( src/core/ext/filters/client_channel/subchannel.c )
   s.files += %w( src/core/ext/filters/client_channel/subchannel_index.c )
   s.files += %w( src/core/ext/filters/client_channel/uri_parser.c )
+  s.files += %w( src/core/ext/filters/deadline/deadline_filter.c )
   s.files += %w( src/core/ext/transport/chttp2/client/chttp2_connector.c )
   s.files += %w( src/core/ext/transport/chttp2/server/insecure/server_chttp2.c )
   s.files += %w( src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c )
@@ -607,6 +609,7 @@
   s.files += %w( src/core/ext/census/trace_context.c )
   s.files += %w( src/core/ext/census/tracing.c )
   s.files += %w( src/core/ext/filters/max_age/max_age_filter.c )
+  s.files += %w( src/core/ext/filters/message_size/message_size_filter.c )
   s.files += %w( src/core/plugin_registry/grpc_plugin_registry.c )
   s.files += %w( third_party/boringssl/crypto/aes/internal.h )
   s.files += %w( third_party/boringssl/crypto/asn1/asn1_locl.h )
diff --git a/include/grpc++/impl/codegen/client_unary_call.h b/include/grpc++/impl/codegen/client_unary_call.h
index 201e52a..a5a4f3d 100644
--- a/include/grpc++/impl/codegen/client_unary_call.h
+++ b/include/grpc++/impl/codegen/client_unary_call.h
@@ -52,7 +52,7 @@
 Status BlockingUnaryCall(ChannelInterface* channel, const RpcMethod& method,
                          ClientContext* context, const InputMessage& request,
                          OutputMessage* result) {
-  CompletionQueue cq;
+  CompletionQueue cq(true);  // Pluckable completion queue
   Call call(channel->CreateCall(method, context, &cq));
   CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage,
             CallOpRecvInitialMetadata, CallOpRecvMessage<OutputMessage>,
diff --git a/include/grpc++/impl/codegen/completion_queue.h b/include/grpc++/impl/codegen/completion_queue.h
index 03cecdc..61617f2 100644
--- a/include/grpc++/impl/codegen/completion_queue.h
+++ b/include/grpc++/impl/codegen/completion_queue.h
@@ -102,10 +102,7 @@
  public:
   /// Default constructor. Implicitly creates a \a grpc_completion_queue
   /// instance.
-  CompletionQueue() {
-    cq_ = g_core_codegen_interface->grpc_completion_queue_create(nullptr);
-    InitialAvalanching();  // reserve this for the future shutdown
-  }
+  CompletionQueue() : CompletionQueue(false) {}
 
   /// Wrap \a take, taking ownership of the instance.
   ///
@@ -218,6 +215,18 @@
                                   const InputMessage& request,
                                   OutputMessage* result);
 
+  /// Private constructor of CompletionQueue only visible to friend classes
+  CompletionQueue(bool is_pluck) {
+    if (is_pluck) {
+      cq_ = g_core_codegen_interface->grpc_completion_queue_create_for_pluck(
+          nullptr);
+    } else {
+      cq_ = g_core_codegen_interface->grpc_completion_queue_create_for_next(
+          nullptr);
+    }
+    InitialAvalanching();  // reserve this for the future shutdown
+  }
+
   NextStatus AsyncNextInternal(void** tag, bool* ok, gpr_timespec deadline);
 
   /// Wraps \a grpc_completion_queue_pluck.
@@ -237,6 +246,12 @@
 
   /// Performs a single polling pluck on \a tag.
   /// \warning Must not be mixed with calls to \a Next.
+  ///
+  /// TODO: sreek - This calls tag->FinalizeResult() even if the cq_ is already
+  /// shutdown. This is most likely a bug and if it is a bug, then change this
+  /// implementation to simple call the other TryPluck function with a zero
+  /// timeout. i.e:
+  ///      TryPluck(tag, gpr_time_0(GPR_CLOCK_REALTIME))
   void TryPluck(CompletionQueueTag* tag) {
     auto deadline = g_core_codegen_interface->gpr_time_0(GPR_CLOCK_REALTIME);
     auto ev = g_core_codegen_interface->grpc_completion_queue_pluck(
@@ -248,6 +263,23 @@
     GPR_CODEGEN_ASSERT(!tag->FinalizeResult(&ignored, &ok));
   }
 
+  /// Performs a single polling pluck on \a tag. Calls tag->FinalizeResult if
+  /// the pluck() was successful and returned the tag.
+  ///
+  /// This exects tag->FinalizeResult (if called) to return 'false' i.e expects
+  /// that the tag is internal not something that is returned to the user.
+  void TryPluck(CompletionQueueTag* tag, gpr_timespec deadline) {
+    auto ev = g_core_codegen_interface->grpc_completion_queue_pluck(
+        cq_, tag, deadline, nullptr);
+    if (ev.type == GRPC_QUEUE_TIMEOUT || ev.type == GRPC_QUEUE_SHUTDOWN) {
+      return;
+    }
+
+    bool ok = ev.success != 0;
+    void* ignored = tag;
+    GPR_CODEGEN_ASSERT(!tag->FinalizeResult(&ignored, &ok));
+  }
+
   grpc_completion_queue* cq_;  // owned
 
   gpr_atm avalanches_in_flight_;
diff --git a/include/grpc++/impl/codegen/core_codegen.h b/include/grpc++/impl/codegen/core_codegen.h
index 6bf9512..6515159 100644
--- a/include/grpc++/impl/codegen/core_codegen.h
+++ b/include/grpc++/impl/codegen/core_codegen.h
@@ -38,6 +38,7 @@
 
 #include <grpc++/impl/codegen/core_codegen_interface.h>
 #include <grpc/byte_buffer.h>
+#include <grpc/grpc.h>
 #include <grpc/impl/codegen/grpc_types.h>
 
 namespace grpc {
@@ -45,7 +46,10 @@
 /// Implementation of the core codegen interface.
 class CoreCodegen : public CoreCodegenInterface {
  private:
-  grpc_completion_queue* grpc_completion_queue_create(void* reserved) override;
+  grpc_completion_queue* grpc_completion_queue_create_for_next(
+      void* reserved) override;
+  grpc_completion_queue* grpc_completion_queue_create_for_pluck(
+      void* reserved) override;
   void grpc_completion_queue_destroy(grpc_completion_queue* cq) override;
   grpc_event grpc_completion_queue_pluck(grpc_completion_queue* cq, void* tag,
                                          gpr_timespec deadline,
diff --git a/include/grpc++/impl/codegen/core_codegen_interface.h b/include/grpc++/impl/codegen/core_codegen_interface.h
index e111d59..529bef6 100644
--- a/include/grpc++/impl/codegen/core_codegen_interface.h
+++ b/include/grpc++/impl/codegen/core_codegen_interface.h
@@ -59,7 +59,9 @@
   virtual void assert_fail(const char* failed_assertion, const char* file,
                            int line) = 0;
 
-  virtual grpc_completion_queue* grpc_completion_queue_create(
+  virtual grpc_completion_queue* grpc_completion_queue_create_for_next(
+      void* reserved) = 0;
+  virtual grpc_completion_queue* grpc_completion_queue_create_for_pluck(
       void* reserved) = 0;
   virtual void grpc_completion_queue_destroy(grpc_completion_queue* cq) = 0;
   virtual grpc_event grpc_completion_queue_pluck(grpc_completion_queue* cq,
diff --git a/include/grpc++/impl/codegen/server_context.h b/include/grpc++/impl/codegen/server_context.h
index 91f0be0..ada304d 100644
--- a/include/grpc++/impl/codegen/server_context.h
+++ b/include/grpc++/impl/codegen/server_context.h
@@ -40,6 +40,7 @@
 
 #include <grpc/impl/codegen/compression_types.h>
 
+#include <grpc++/impl/codegen/completion_queue_tag.h>
 #include <grpc++/impl/codegen/config.h>
 #include <grpc++/impl/codegen/create_auth_context.h>
 #include <grpc++/impl/codegen/metadata_map.h>
@@ -211,6 +212,8 @@
   class CompletionOp;
 
   void BeginCompletionOp(Call* call);
+  // Return the tag queued by BeginCompletionOp()
+  CompletionQueueTag* GetCompletionOpTag();
 
   ServerContext(gpr_timespec deadline, grpc_metadata_array* arr);
 
diff --git a/include/grpc++/impl/codegen/server_interface.h b/include/grpc++/impl/codegen/server_interface.h
index bd1b36e..31d5552 100644
--- a/include/grpc++/impl/codegen/server_interface.h
+++ b/include/grpc++/impl/codegen/server_interface.h
@@ -122,9 +122,7 @@
   /// caller is required to keep all completion queues live until the server is
   /// destroyed.
   /// \param num_cqs How many completion queues does \a cqs hold.
-  ///
-  /// \return true on a successful shutdown.
-  virtual bool Start(ServerCompletionQueue** cqs, size_t num_cqs) = 0;
+  virtual void Start(ServerCompletionQueue** cqs, size_t num_cqs) = 0;
 
   virtual void ShutdownInternal(gpr_timespec deadline) = 0;
 
diff --git a/include/grpc++/impl/codegen/status.h b/include/grpc++/impl/codegen/status.h
index 5cce3c1..31fd6cd 100644
--- a/include/grpc++/impl/codegen/status.h
+++ b/include/grpc++/impl/codegen/status.h
@@ -53,7 +53,7 @@
 
   /// Construct an instance with \a code,  \a error_message and \a error_details
   Status(StatusCode code, const grpc::string& error_message,
-         const grpc::string error_details)
+         const grpc::string& error_details)
       : code_(code),
         error_message_(error_message),
         binary_error_details_(error_details) {}
diff --git a/include/grpc++/impl/codegen/sync_stream.h b/include/grpc++/impl/codegen/sync_stream.h
index ae3b8e4..328d5cb 100644
--- a/include/grpc++/impl/codegen/sync_stream.h
+++ b/include/grpc++/impl/codegen/sync_stream.h
@@ -155,7 +155,9 @@
   template <class W>
   ClientReader(ChannelInterface* channel, const RpcMethod& method,
                ClientContext* context, const W& request)
-      : context_(context), call_(channel->CreateCall(method, context, &cq_)) {
+      : context_(context),
+        cq_(true),  // Pluckable cq
+        call_(channel->CreateCall(method, context, &cq_)) {
     CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage,
               CallOpClientSendClose>
         ops;
@@ -227,7 +229,9 @@
   template <class R>
   ClientWriter(ChannelInterface* channel, const RpcMethod& method,
                ClientContext* context, R* response)
-      : context_(context), call_(channel->CreateCall(method, context, &cq_)) {
+      : context_(context),
+        cq_(true),  // Pluckable cq
+        call_(channel->CreateCall(method, context, &cq_)) {
     finish_ops_.RecvMessage(response);
     finish_ops_.AllowNoMessage();
 
@@ -325,7 +329,9 @@
   /// Blocking create a stream.
   ClientReaderWriter(ChannelInterface* channel, const RpcMethod& method,
                      ClientContext* context)
-      : context_(context), call_(channel->CreateCall(method, context, &cq_)) {
+      : context_(context),
+        cq_(true),  // Pluckable cq
+        call_(channel->CreateCall(method, context, &cq_)) {
     if (!context_->initial_metadata_corked_) {
       CallOpSet<CallOpSendInitialMetadata> ops;
       ops.SendInitialMetadata(context->send_initial_metadata_,
@@ -562,7 +568,7 @@
   Call* const call_;
   ServerContext* const ctx_;
 };
-}
+}  // namespace internal
 
 // class to represent the user API for a bidirectional streaming call
 template <class W, class R>
diff --git a/include/grpc++/server.h b/include/grpc++/server.h
index 4899377..2f7018e 100644
--- a/include/grpc++/server.h
+++ b/include/grpc++/server.h
@@ -89,7 +89,8 @@
     /// Called before server is started.
     virtual void PreServerStart(Server* server) {}
     /// Called after a server port is added.
-    virtual void AddPort(Server* server, int port) {}
+    virtual void AddPort(Server* server, const grpc::string& addr,
+                         ServerCredentials* creds, int port) {}
   };
   /// Set the global callback object. Can only be called once. Does not take
   /// ownership of callbacks, and expects the pointed to object to be alive
@@ -177,9 +178,7 @@
   /// caller is required to keep all completion queues live until the server is
   /// destroyed.
   /// \param num_cqs How many completion queues does \a cqs hold.
-  ///
-  /// \return true on a successful shutdown.
-  bool Start(ServerCompletionQueue** cqs, size_t num_cqs) override;
+  void Start(ServerCompletionQueue** cqs, size_t num_cqs) override;
 
   void PerformOpsOnCall(CallOpSetInterface* ops, Call* call) override;
 
diff --git a/src/core/lib/channel/http_client_filter.h b/include/grpc++/support/error_details.h
similarity index 63%
copy from src/core/lib/channel/http_client_filter.h
copy to include/grpc++/support/error_details.h
index 9e6e106..411175f 100644
--- a/src/core/lib/channel/http_client_filter.h
+++ b/include/grpc++/support/error_details.h
@@ -1,5 +1,6 @@
 /*
- * Copyright 2015, Google Inc.
+ *
+ * Copyright 2017, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -30,18 +31,31 @@
  *
  */
 
-#ifndef GRPC_CORE_LIB_CHANNEL_HTTP_CLIENT_FILTER_H
-#define GRPC_CORE_LIB_CHANNEL_HTTP_CLIENT_FILTER_H
+#ifndef GRPCXX_SUPPORT_ERROR_DETAILS_H
+#define GRPCXX_SUPPORT_ERROR_DETAILS_H
 
-#include "src/core/lib/channel/channel_stack.h"
+#include <grpc++/support/status.h>
 
-/* Processes metadata on the client side for HTTP2 transports */
-extern const grpc_channel_filter grpc_http_client_filter;
+namespace google {
+namespace rpc {
+class Status;
+}  // namespace rpc
+}  // namespace google
 
-/* Channel arg to override the http2 :scheme header */
-#define GRPC_ARG_HTTP2_SCHEME "grpc.http2_scheme"
+namespace grpc {
 
-/* Channel arg to determine maximum size of payload eligable for GET request */
-#define GRPC_ARG_MAX_PAYLOAD_SIZE_FOR_GET "grpc.max_payload_size_for_get"
+// Maps a grpc::Status to a google::rpc::Status.
+// The given \a to object will be cleared.
+// On success, returns status with OK.
+// Returns status with INVALID_ARGUMENT, if failed to deserialize.
+// Returns status with FAILED_PRECONDITION, if \a to is nullptr.
+Status ExtractErrorDetails(const Status& from, ::google::rpc::Status* to);
 
-#endif /* GRPC_CORE_LIB_CHANNEL_HTTP_CLIENT_FILTER_H */
+// Maps google::rpc::Status to a grpc::Status.
+// Returns OK on success.
+// Returns status with FAILED_PRECONDITION if \a to is nullptr.
+Status SetErrorDetails(const ::google::rpc::Status& from, Status* to);
+
+}  // namespace grpc
+
+#endif  // GRPCXX_SUPPORT_ERROR_DETAILS_H
diff --git a/include/grpc/grpc.h b/include/grpc/grpc.h
index e088435..9a65d34 100644
--- a/include/grpc/grpc.h
+++ b/include/grpc/grpc.h
@@ -95,10 +95,10 @@
 
 /** Specifies the type of APIs to use to pop events from the completion queue */
 typedef enum {
-  /* Events are popped out by calling grpc_completion_queue_next() API ONLY */
+  /** Events are popped out by calling grpc_completion_queue_next() API ONLY */
   GRPC_CQ_NEXT = 1,
 
-  /* Events are popped out by calling grpc_completion_queue_pluck() API ONLY */
+  /** Events are popped out by calling grpc_completion_queue_pluck() API ONLY*/
   GRPC_CQ_PLUCK
 } grpc_cq_completion_type;
 
@@ -116,15 +116,15 @@
       restriction on the type of file descriptors the pollset may contain */
   GRPC_CQ_DEFAULT_POLLING,
 
-  /* Similar to GRPC_CQ_DEFAULT_POLLING except that the completion queues will
-     not contain any 'listening file descriptors' (i.e file descriptors used to
-     listen to incoming channels) */
+  /** Similar to GRPC_CQ_DEFAULT_POLLING except that the completion queues will
+      not contain any 'listening file descriptors' (i.e file descriptors used to
+      listen to incoming channels) */
   GRPC_CQ_NON_LISTENING,
 
-  /* The completion queue will not have an associated pollset. Note that
-     grpc_completion_queue_next() or grpc_completion_queue_pluck() MUST still be
-     called to pop events from the completion queue; it is not required to call
-     them actively to make I/O progress */
+  /** The completion queue will not have an associated pollset. Note that
+      grpc_completion_queue_next() or grpc_completion_queue_pluck() MUST still
+      be called to pop events from the completion queue; it is not required to
+      call them actively to make I/O progress */
   GRPC_CQ_NON_POLLING
 } grpc_cq_polling_type;
 
@@ -159,7 +159,9 @@
     void *reserved);
 
 /** Create a completion queue */
-GRPCAPI grpc_completion_queue *grpc_completion_queue_create(void *reserved);
+GRPCAPI grpc_completion_queue *grpc_completion_queue_create(
+    const grpc_completion_queue_factory *factory,
+    const grpc_completion_queue_attributes *attributes, void *reserved);
 
 /** Blocks until an event is available, the completion queue is being shut down,
     or deadline is reached.
@@ -294,12 +296,6 @@
     functionality. Instead, use grpc_auth_context. */
 GRPCAPI char *grpc_call_get_peer(grpc_call *call);
 
-struct grpc_load_reporting_cost_context;
-
-/* Associate costs contained in \a cost_context to \a call. */
-GRPCAPI void grpc_call_set_load_reporting_cost_context(
-    grpc_call *call, struct grpc_load_reporting_cost_context *context);
-
 struct census_context;
 
 /** Set census context for a call; Must be called before first call to
diff --git a/include/grpc/impl/codegen/grpc_types.h b/include/grpc/impl/codegen/grpc_types.h
index fdedf0a..b5d637e 100644
--- a/include/grpc/impl/codegen/grpc_types.h
+++ b/include/grpc/impl/codegen/grpc_types.h
@@ -175,6 +175,12 @@
 /** Grace period after the chennel reaches its max age. Int valued,
    milliseconds. INT_MAX means unlimited. */
 #define GRPC_ARG_MAX_CONNECTION_AGE_GRACE_MS "grpc.max_connection_age_grace_ms"
+/** Enable/disable support for per-message compression. Defaults to 1, unless
+    GRPC_ARG_MINIMAL_STACK is enabled, in which case it defaults to 0. */
+#define GRPC_ARG_ENABLE_PER_MESSAGE_COMPRESSION "grpc.per_message_compression"
+/** Enable/disable support for deadline checking. Defaults to 1, unless
+    GRPC_ARG_MINIMAL_STACK is enabled, in which case it defaults to 0 */
+#define GRPC_ARG_ENABLE_DEADLINE_CHECKS "grpc.enable_deadline_checking"
 /** Initial sequence number for http2 transports. Int valued. */
 #define GRPC_ARG_HTTP2_INITIAL_SEQUENCE_NUMBER \
   "grpc.http2.initial_sequence_number"
@@ -199,6 +205,8 @@
 /** Minimum time (in milliseconds) between successive ping frames being sent */
 #define GRPC_ARG_HTTP2_MIN_TIME_BETWEEN_PINGS_MS \
   "grpc.http2.min_time_between_pings_ms"
+/* Channel arg to override the http2 :scheme header */
+#define GRPC_ARG_HTTP2_SCHEME "grpc.http2_scheme"
 /** How many pings can we send before needing to send a data frame or header
     frame?
     (0 indicates that an infinite number of pings can be sent without sending
@@ -217,6 +225,9 @@
 /** How much data are we willing to queue up per stream if
     GRPC_WRITE_BUFFER_HINT is set? This is an upper bound */
 #define GRPC_ARG_HTTP2_WRITE_BUFFER_SIZE "grpc.http2.write_buffer_size"
+/** Should we allow receipt of true-binary data on http2 connections?
+    Defaults to on (1) */
+#define GRPC_ARG_HTTP2_ENABLE_TRUE_BINARY "grpc.http2.true_binary"
 /** After a duration of this time the client/server pings its peer to see if the
     transport is still alive. Int valued, milliseconds. */
 #define GRPC_ARG_KEEPALIVE_TIME_MS "grpc.keepalive_time_ms"
@@ -237,6 +248,8 @@
 /** Secondary user agent: goes at the end of the user-agent metadata
     sent on each request. A string. */
 #define GRPC_ARG_SECONDARY_USER_AGENT_STRING "grpc.secondary_user_agent"
+/** The minimum time between subsequent connection attempts, in ms */
+#define GRPC_ARG_MIN_RECONNECT_BACKOFF_MS "grpc.min_reconnect_backoff_ms"
 /** The maximum time between subsequent connection attempts, in ms */
 #define GRPC_ARG_MAX_RECONNECT_BACKOFF_MS "grpc.max_reconnect_backoff_ms"
 /** The time between the first and second connection attempts, in ms */
@@ -390,8 +403,11 @@
 typedef struct grpc_event {
   /** The type of the completion. */
   grpc_completion_type type;
-  /** non-zero if the operation was successful, 0 upon failure.
-      Only GRPC_OP_COMPLETE can succeed or fail. */
+  /** If the grpc_completion_type is GRPC_OP_COMPLETE, this field indicates
+      whether the operation was successful or not; 0 in case of failure and
+      non-zero in case of success.
+      If grpc_completion_type is GRPC_QUEUE_SHUTDOWN or GRPC_QUEUE_TIMEOUT, this
+      field is guaranteed to be 0 */
   int success;
   /** The tag passed to grpc_call_start_batch etc to start this operation.
       Only GRPC_OP_COMPLETE has a tag. */
diff --git a/include/grpc/load_reporting.h b/include/grpc/load_reporting.h
index c833ce5..a334a11 100644
--- a/include/grpc/load_reporting.h
+++ b/include/grpc/load_reporting.h
@@ -35,7 +35,6 @@
 #define GRPC_LOAD_REPORTING_H
 
 #include <grpc/impl/codegen/port_platform.h>
-#include <grpc/slice.h>
 
 #ifdef __cplusplus
 extern "C" {
@@ -50,11 +49,12 @@
  * gRPC LB system. */
 #define GRPC_LB_TOKEN_MD_KEY "lb-token"
 
-/** A sequence of values for load reporting purposes */
-typedef struct grpc_load_reporting_cost_context {
-  grpc_slice *values;
-  size_t values_count;
-} grpc_load_reporting_cost_context;
+/** Metadata key for gRPC LB cost reporting.
+ *
+ * The value corresponding to this key is an opaque binary blob reported by the
+ * backend as part of its trailing metadata containing cost information for the
+ * call. */
+#define GRPC_LB_COST_MD_KEY "lb-cost-bin"
 
 #ifdef __cplusplus
 }
diff --git a/include/grpc/slice.h b/include/grpc/slice.h
index ea66e09..8c32a30 100644
--- a/include/grpc/slice.h
+++ b/include/grpc/slice.h
@@ -102,9 +102,9 @@
 /* Create a slice pointing to constant memory */
 GPRAPI grpc_slice grpc_slice_from_static_buffer(const void *source, size_t len);
 
-/* Return a result slice derived from s, which shares a ref count with s, where
-   result.data==s.data+begin, and result.length==end-begin.
-   The ref count of s is increased by one.
+/* Return a result slice derived from s, which shares a ref count with \a s,
+   where result.data==s.data+begin, and result.length==end-begin. The ref count
+   of \a s is increased by one. Do not assign result back to \a s.
    Requires s initialized, begin <= end, begin <= s.length, and
    end <= source->length. */
 GPRAPI grpc_slice grpc_slice_sub(grpc_slice s, size_t begin, size_t end);
diff --git a/include/grpc/support/alloc.h b/include/grpc/support/alloc.h
index 541433c..017d75a 100644
--- a/include/grpc/support/alloc.h
+++ b/include/grpc/support/alloc.h
@@ -68,7 +68,8 @@
 
 /** Request the family of allocation functions in \a functions be used. NOTE
  * that this request will be honored in a *best effort* basis and that no
- * guarantees are made about the default functions (eg, malloc) being called. */
+ * guarantees are made about the default functions (eg, malloc) being called.
+ * The functions.free_fn implementation must be a no-op for NULL input. */
 GPRAPI void gpr_set_allocation_functions(gpr_allocation_functions functions);
 
 /** Return the family of allocation functions currently in effect. */
diff --git a/package.json b/package.json
index 7f24232..6a01ae2 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "grpc",
-  "version": "1.3.0-dev",
+  "version": "1.4.0-dev",
   "author": "Google Inc.",
   "description": "gRPC Library for Node",
   "homepage": "http://www.grpc.io/",
diff --git a/package.xml b/package.xml
index c6b86a6..b128be6 100644
--- a/package.xml
+++ b/package.xml
@@ -13,8 +13,8 @@
  <date>2017-03-01</date>
  <time>16:06:07</time>
  <version>
-  <release>1.3.0dev</release>
-  <api>1.3.0dev</api>
+  <release>1.4.0dev</release>
+  <api>1.4.0dev</api>
  </version>
  <stability>
   <release>beta</release>
@@ -183,16 +183,11 @@
     <file baseinstalldir="/" name="src/core/lib/channel/channel_args.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/channel/channel_stack.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/channel/channel_stack_builder.h" role="src" />
-    <file baseinstalldir="/" name="src/core/lib/channel/compress_filter.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/channel/connected_channel.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/channel/context.h" role="src" />
-    <file baseinstalldir="/" name="src/core/lib/channel/deadline_filter.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/channel/handshaker.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/channel/handshaker_factory.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/channel/handshaker_registry.h" role="src" />
-    <file baseinstalldir="/" name="src/core/lib/channel/http_client_filter.h" role="src" />
-    <file baseinstalldir="/" name="src/core/lib/channel/http_server_filter.h" role="src" />
-    <file baseinstalldir="/" name="src/core/lib/channel/message_size_filter.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/compression/algorithm_metadata.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/compression/message_compress.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/debug/trace.h" role="src" />
@@ -304,12 +299,16 @@
     <file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/hpack_encoder.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/hpack_parser.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/hpack_table.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/http2_settings.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/huffsyms.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/incoming_metadata.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/internal.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/stream_map.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/varint.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/transport/chttp2/alpn/alpn.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/filters/http/client/http_client_filter.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/filters/http/message_compress/message_compress_filter.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/filters/http/server/http_server_filter.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/security/context/security_context.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/security/credentials/composite/composite_credentials.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/security/credentials/credentials.h" role="src" />
@@ -353,6 +352,7 @@
     <file baseinstalldir="/" name="src/core/ext/filters/client_channel/subchannel.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/client_channel/subchannel_index.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/client_channel/uri_parser.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/filters/deadline/deadline_filter.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/transport/chttp2/client/chttp2_connector.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h" role="src" />
@@ -383,19 +383,15 @@
     <file baseinstalldir="/" name="src/core/ext/census/trace_string.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/census/tracing.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/max_age/max_age_filter.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/filters/message_size/message_size_filter.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/surface/init.c" role="src" />
     <file baseinstalldir="/" name="src/core/lib/channel/channel_args.c" role="src" />
     <file baseinstalldir="/" name="src/core/lib/channel/channel_stack.c" role="src" />
     <file baseinstalldir="/" name="src/core/lib/channel/channel_stack_builder.c" role="src" />
-    <file baseinstalldir="/" name="src/core/lib/channel/compress_filter.c" role="src" />
     <file baseinstalldir="/" name="src/core/lib/channel/connected_channel.c" role="src" />
-    <file baseinstalldir="/" name="src/core/lib/channel/deadline_filter.c" role="src" />
     <file baseinstalldir="/" name="src/core/lib/channel/handshaker.c" role="src" />
     <file baseinstalldir="/" name="src/core/lib/channel/handshaker_factory.c" role="src" />
     <file baseinstalldir="/" name="src/core/lib/channel/handshaker_registry.c" role="src" />
-    <file baseinstalldir="/" name="src/core/lib/channel/http_client_filter.c" role="src" />
-    <file baseinstalldir="/" name="src/core/lib/channel/http_server_filter.c" role="src" />
-    <file baseinstalldir="/" name="src/core/lib/channel/message_size_filter.c" role="src" />
     <file baseinstalldir="/" name="src/core/lib/compression/compression.c" role="src" />
     <file baseinstalldir="/" name="src/core/lib/compression/message_compress.c" role="src" />
     <file baseinstalldir="/" name="src/core/lib/debug/trace.c" role="src" />
@@ -523,6 +519,7 @@
     <file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/hpack_encoder.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/hpack_parser.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/hpack_table.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/http2_settings.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/huffsyms.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/incoming_metadata.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/parsing.c" role="src" />
@@ -531,6 +528,10 @@
     <file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/varint.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/writing.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/transport/chttp2/alpn/alpn.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/filters/http/client/http_client_filter.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/filters/http/http_filters_plugin.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/filters/http/message_compress/message_compress_filter.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/filters/http/server/http_server_filter.c" role="src" />
     <file baseinstalldir="/" name="src/core/lib/http/httpcli_security_connector.c" role="src" />
     <file baseinstalldir="/" name="src/core/lib/security/context/security_context.c" role="src" />
     <file baseinstalldir="/" name="src/core/lib/security/credentials/composite/composite_credentials.c" role="src" />
@@ -580,6 +581,7 @@
     <file baseinstalldir="/" name="src/core/ext/filters/client_channel/subchannel.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/client_channel/subchannel_index.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/client_channel/uri_parser.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/filters/deadline/deadline_filter.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/transport/chttp2/client/chttp2_connector.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/transport/chttp2/server/insecure/server_chttp2.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c" role="src" />
@@ -616,6 +618,7 @@
     <file baseinstalldir="/" name="src/core/ext/census/trace_context.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/census/tracing.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/max_age/max_age_filter.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/filters/message_size/message_size_filter.c" role="src" />
     <file baseinstalldir="/" name="src/core/plugin_registry/grpc_plugin_registry.c" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl/crypto/aes/internal.h" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl/crypto/asn1/asn1_locl.h" role="src" />
diff --git a/src/core/ext/census/context.c b/src/core/ext/census/context.c
index 0dfc4ec..4195cb1 100644
--- a/src/core/ext/census/context.c
+++ b/src/core/ext/census/context.c
@@ -200,7 +200,7 @@
     // allocate new memory if needed
     tags->kvm_size += 2 * CENSUS_MAX_TAG_KV_LEN + TAG_HEADER_SIZE;
     char *new_kvm = gpr_malloc(tags->kvm_size);
-    memcpy(new_kvm, tags->kvm, tags->kvm_used);
+    if (tags->kvm_used > 0) memcpy(new_kvm, tags->kvm, tags->kvm_used);
     gpr_free(tags->kvm);
     tags->kvm = new_kvm;
   }
diff --git a/src/core/ext/census/resource.c b/src/core/ext/census/resource.c
index ed44f00..26ea1a8 100644
--- a/src/core/ext/census/resource.c
+++ b/src/core/ext/census/resource.c
@@ -223,7 +223,9 @@
   if (n_resources == n_defined_resources) {
     size_t new_n_resources = n_resources ? n_resources * 2 : 2;
     resource **new_resources = gpr_malloc(new_n_resources * sizeof(resource *));
-    memcpy(new_resources, resources, n_resources * sizeof(resource *));
+    if (n_resources != 0) {
+      memcpy(new_resources, resources, n_resources * sizeof(resource *));
+    }
     memset(new_resources + n_resources, 0,
            (new_n_resources - n_resources) * sizeof(resource *));
     gpr_free(resources);
diff --git a/src/core/ext/filters/client_channel/client_channel.c b/src/core/ext/filters/client_channel/client_channel.c
index 83e3b8f..ce9abda 100644
--- a/src/core/ext/filters/client_channel/client_channel.c
+++ b/src/core/ext/filters/client_channel/client_channel.c
@@ -49,9 +49,9 @@
 #include "src/core/ext/filters/client_channel/resolver_registry.h"
 #include "src/core/ext/filters/client_channel/retry_throttle.h"
 #include "src/core/ext/filters/client_channel/subchannel.h"
+#include "src/core/ext/filters/deadline/deadline_filter.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/channel/connected_channel.h"
-#include "src/core/lib/channel/deadline_filter.h"
 #include "src/core/lib/iomgr/combiner.h"
 #include "src/core/lib/iomgr/iomgr.h"
 #include "src/core/lib/iomgr/polling_entity.h"
@@ -183,6 +183,8 @@
   grpc_resolver *resolver;
   /** have we started resolving this channel */
   bool started_resolving;
+  /** is deadline checking enabled? */
+  bool deadline_checking_enabled;
   /** client channel factory */
   grpc_client_channel_factory *client_channel_factory;
 
@@ -236,14 +238,23 @@
                                                   grpc_connectivity_state state,
                                                   grpc_error *error,
                                                   const char *reason) {
-  if ((state == GRPC_CHANNEL_TRANSIENT_FAILURE ||
-       state == GRPC_CHANNEL_SHUTDOWN) &&
-      chand->lb_policy != NULL) {
-    /* cancel picks with wait_for_ready=false */
-    grpc_lb_policy_cancel_picks_locked(
-        exec_ctx, chand->lb_policy,
-        /* mask= */ GRPC_INITIAL_METADATA_WAIT_FOR_READY,
-        /* check= */ 0, GRPC_ERROR_REF(error));
+  /* TODO: Improve failure handling:
+   * - Make it possible for policies to return GRPC_CHANNEL_TRANSIENT_FAILURE.
+   * - Hand over pending picks from old policies during the switch that happens
+   *   when resolver provides an update. */
+  if (chand->lb_policy != NULL) {
+    if (state == GRPC_CHANNEL_TRANSIENT_FAILURE) {
+      /* cancel picks with wait_for_ready=false */
+      grpc_lb_policy_cancel_picks_locked(
+          exec_ctx, chand->lb_policy,
+          /* mask= */ GRPC_INITIAL_METADATA_WAIT_FOR_READY,
+          /* check= */ 0, GRPC_ERROR_REF(error));
+    } else if (state == GRPC_CHANNEL_SHUTDOWN) {
+      /* cancel all picks */
+      grpc_lb_policy_cancel_picks_locked(exec_ctx, chand->lb_policy,
+                                         /* mask= */ 0, /* check= */ 0,
+                                         GRPC_ERROR_REF(error));
+    }
   }
   grpc_connectivity_state_set(exec_ctx, &chand->state_tracker, state, error,
                               reason);
@@ -346,6 +357,33 @@
   }
 }
 
+// Wrap a closure associated with \a lb_policy. The associated callback (\a
+// wrapped_on_pick_closure_cb) is responsible for unref'ing \a lb_policy after
+// scheduling \a wrapped_closure.
+typedef struct wrapped_on_pick_closure_arg {
+  /* the closure instance using this struct as argument */
+  grpc_closure wrapper_closure;
+
+  /* the original closure. Usually a on_complete/notify cb for pick() and ping()
+   * calls against the internal RR instance, respectively. */
+  grpc_closure *wrapped_closure;
+
+  /* The policy instance related to the closure */
+  grpc_lb_policy *lb_policy;
+} wrapped_on_pick_closure_arg;
+
+// Invoke \a arg->wrapped_closure, unref \a arg->lb_policy and free \a arg.
+static void wrapped_on_pick_closure_cb(grpc_exec_ctx *exec_ctx, void *arg,
+                                       grpc_error *error) {
+  wrapped_on_pick_closure_arg *wc_arg = arg;
+  GPR_ASSERT(wc_arg != NULL);
+  GPR_ASSERT(wc_arg->wrapped_closure != NULL);
+  GPR_ASSERT(wc_arg->lb_policy != NULL);
+  grpc_closure_run(exec_ctx, wc_arg->wrapped_closure, GRPC_ERROR_REF(error));
+  GRPC_LB_POLICY_UNREF(exec_ctx, wc_arg->lb_policy, "pick_subchannel_wrapping");
+  gpr_free(wc_arg);
+}
+
 static void on_resolver_result_changed_locked(grpc_exec_ctx *exec_ctx,
                                               void *arg, grpc_error *error) {
   channel_data *chand = arg;
@@ -676,6 +714,8 @@
   if (chand->resolver == NULL) {
     return GRPC_ERROR_CREATE_FROM_STATIC_STRING("resolver creation failed");
   }
+  chand->deadline_checking_enabled =
+      grpc_deadline_checking_enabled(args->channel_args);
   return GRPC_ERROR_NONE;
 }
 
@@ -864,12 +904,14 @@
   /* apply service-config level configuration to the call (now that we're
    * certain it exists) */
   call_data *calld = elem->call_data;
+  channel_data *chand = elem->channel_data;
   gpr_timespec per_method_deadline;
   if (set_call_method_params_from_service_config_locked(exec_ctx, elem,
                                                         &per_method_deadline)) {
     // If the deadline from the service config is shorter than the one
     // from the client API, reset the deadline timer.
-    if (gpr_time_cmp(per_method_deadline, calld->deadline) < 0) {
+    if (chand->deadline_checking_enabled &&
+        gpr_time_cmp(per_method_deadline, calld->deadline) < 0) {
       calld->deadline = per_method_deadline;
       grpc_deadline_state_reset(exec_ctx, elem, calld->deadline);
     }
@@ -1031,11 +1073,29 @@
     const grpc_lb_policy_pick_args inputs = {
         initial_metadata, initial_metadata_flags, &calld->lb_token_mdelem,
         gpr_inf_future(GPR_CLOCK_MONOTONIC)};
-    const bool result = grpc_lb_policy_pick_locked(
-        exec_ctx, lb_policy, &inputs, connected_subchannel, NULL, on_ready);
+
+    // Wrap the user-provided callback in order to hold a strong reference to
+    // the LB policy for the duration of the pick.
+    wrapped_on_pick_closure_arg *w_on_pick_arg =
+        gpr_zalloc(sizeof(*w_on_pick_arg));
+    grpc_closure_init(&w_on_pick_arg->wrapper_closure,
+                      wrapped_on_pick_closure_cb, w_on_pick_arg,
+                      grpc_schedule_on_exec_ctx);
+    w_on_pick_arg->wrapped_closure = on_ready;
+    GRPC_LB_POLICY_REF(lb_policy, "pick_subchannel_wrapping");
+    w_on_pick_arg->lb_policy = lb_policy;
+    const bool pick_done = grpc_lb_policy_pick_locked(
+        exec_ctx, lb_policy, &inputs, connected_subchannel, NULL,
+        &w_on_pick_arg->wrapper_closure);
+    if (pick_done) {
+      /* synchronous grpc_lb_policy_pick call. Unref the LB policy. */
+      GRPC_LB_POLICY_UNREF(exec_ctx, w_on_pick_arg->lb_policy,
+                           "pick_subchannel_wrapping");
+      gpr_free(w_on_pick_arg);
+    }
     GRPC_LB_POLICY_UNREF(exec_ctx, lb_policy, "pick_subchannel");
     GPR_TIMER_END("pick_subchannel", 0);
-    return result;
+    return pick_done;
   }
   if (chand->resolver != NULL && !chand->started_resolving) {
     chand->started_resolving = true;
@@ -1227,8 +1287,10 @@
   call_data *calld = elem->call_data;
   channel_data *chand = elem->channel_data;
   GRPC_CALL_LOG_OP(GPR_INFO, elem, op);
-  grpc_deadline_state_client_start_transport_stream_op_batch(exec_ctx, elem,
-                                                             op);
+  if (chand->deadline_checking_enabled) {
+    grpc_deadline_state_client_start_transport_stream_op_batch(exec_ctx, elem,
+                                                               op);
+  }
   /* try to (atomically) get the call */
   grpc_subchannel_call *call = GET_CALL(calld);
   GPR_TIMER_BEGIN("cc_start_transport_stream_op_batch", 0);
@@ -1262,14 +1324,16 @@
                                      grpc_call_element *elem,
                                      const grpc_call_element_args *args) {
   call_data *calld = elem->call_data;
+  channel_data *chand = elem->channel_data;
   // Initialize data members.
-  grpc_deadline_state_init(exec_ctx, elem, args->call_stack);
   calld->path = grpc_slice_ref_internal(args->path);
   calld->call_start_time = args->start_time;
   calld->deadline = gpr_convert_clock_type(args->deadline, GPR_CLOCK_MONOTONIC);
   calld->owning_call = args->call_stack;
   calld->arena = args->arena;
-  grpc_deadline_state_start(exec_ctx, elem, calld->deadline);
+  if (chand->deadline_checking_enabled) {
+    grpc_deadline_state_init(exec_ctx, elem, args->call_stack, calld->deadline);
+  }
   return GRPC_ERROR_NONE;
 }
 
@@ -1279,7 +1343,10 @@
                                  const grpc_call_final_info *final_info,
                                  grpc_closure *then_schedule_closure) {
   call_data *calld = elem->call_data;
-  grpc_deadline_state_destroy(exec_ctx, elem);
+  channel_data *chand = elem->channel_data;
+  if (chand->deadline_checking_enabled) {
+    grpc_deadline_state_destroy(exec_ctx, elem);
+  }
   grpc_slice_unref_internal(exec_ctx, calld->path);
   if (calld->method_params != NULL) {
     method_parameters_unref(calld->method_params);
diff --git a/src/core/ext/filters/client_channel/client_channel_plugin.c b/src/core/ext/filters/client_channel/client_channel_plugin.c
index a68c01c..0e3eae6 100644
--- a/src/core/ext/filters/client_channel/client_channel_plugin.c
+++ b/src/core/ext/filters/client_channel/client_channel_plugin.c
@@ -91,8 +91,9 @@
   grpc_subchannel_index_init();
   grpc_channel_init_register_stage(GRPC_CLIENT_CHANNEL, INT_MIN,
                                    set_default_host_if_unset, NULL);
-  grpc_channel_init_register_stage(GRPC_CLIENT_CHANNEL, INT_MAX, append_filter,
-                                   (void *)&grpc_client_channel_filter);
+  grpc_channel_init_register_stage(
+      GRPC_CLIENT_CHANNEL, GRPC_CHANNEL_INIT_BUILTIN_PRIORITY, append_filter,
+      (void *)&grpc_client_channel_filter);
   grpc_http_connect_register_handshaker_factory();
 }
 
diff --git a/src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c b/src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c
index e9adf98..fb119c7 100644
--- a/src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c
+++ b/src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c
@@ -16,6 +16,12 @@
     PB_LAST_FIELD
 };
 
+const pb_field_t grpc_lb_v1_Timestamp_fields[3] = {
+    PB_FIELD(  1, INT64   , OPTIONAL, STATIC  , FIRST, grpc_lb_v1_Timestamp, seconds, seconds, 0),
+    PB_FIELD(  2, INT32   , OPTIONAL, STATIC  , OTHER, grpc_lb_v1_Timestamp, nanos, seconds, 0),
+    PB_LAST_FIELD
+};
+
 const pb_field_t grpc_lb_v1_LoadBalanceRequest_fields[3] = {
     PB_FIELD(  1, MESSAGE , OPTIONAL, STATIC  , FIRST, grpc_lb_v1_LoadBalanceRequest, initial_request, initial_request, &grpc_lb_v1_InitialLoadBalanceRequest_fields),
     PB_FIELD(  2, MESSAGE , OPTIONAL, STATIC  , OTHER, grpc_lb_v1_LoadBalanceRequest, client_stats, initial_request, &grpc_lb_v1_ClientStats_fields),
@@ -27,10 +33,14 @@
     PB_LAST_FIELD
 };
 
-const pb_field_t grpc_lb_v1_ClientStats_fields[4] = {
-    PB_FIELD(  1, INT64   , OPTIONAL, STATIC  , FIRST, grpc_lb_v1_ClientStats, total_requests, total_requests, 0),
-    PB_FIELD(  2, INT64   , OPTIONAL, STATIC  , OTHER, grpc_lb_v1_ClientStats, client_rpc_errors, total_requests, 0),
-    PB_FIELD(  3, INT64   , OPTIONAL, STATIC  , OTHER, grpc_lb_v1_ClientStats, dropped_requests, client_rpc_errors, 0),
+const pb_field_t grpc_lb_v1_ClientStats_fields[8] = {
+    PB_FIELD(  1, MESSAGE , OPTIONAL, STATIC  , FIRST, grpc_lb_v1_ClientStats, timestamp, timestamp, &grpc_lb_v1_Timestamp_fields),
+    PB_FIELD(  2, INT64   , OPTIONAL, STATIC  , OTHER, grpc_lb_v1_ClientStats, num_calls_started, timestamp, 0),
+    PB_FIELD(  3, INT64   , OPTIONAL, STATIC  , OTHER, grpc_lb_v1_ClientStats, num_calls_finished, num_calls_started, 0),
+    PB_FIELD(  4, INT64   , OPTIONAL, STATIC  , OTHER, grpc_lb_v1_ClientStats, num_calls_finished_with_drop_for_rate_limiting, num_calls_finished, 0),
+    PB_FIELD(  5, INT64   , OPTIONAL, STATIC  , OTHER, grpc_lb_v1_ClientStats, num_calls_finished_with_drop_for_load_balancing, num_calls_finished_with_drop_for_rate_limiting, 0),
+    PB_FIELD(  6, INT64   , OPTIONAL, STATIC  , OTHER, grpc_lb_v1_ClientStats, num_calls_finished_with_client_failed_to_send, num_calls_finished_with_drop_for_load_balancing, 0),
+    PB_FIELD(  7, INT64   , OPTIONAL, STATIC  , OTHER, grpc_lb_v1_ClientStats, num_calls_finished_known_received, num_calls_finished_with_client_failed_to_send, 0),
     PB_LAST_FIELD
 };
 
@@ -52,11 +62,12 @@
     PB_LAST_FIELD
 };
 
-const pb_field_t grpc_lb_v1_Server_fields[5] = {
+const pb_field_t grpc_lb_v1_Server_fields[6] = {
     PB_FIELD(  1, BYTES   , OPTIONAL, STATIC  , FIRST, grpc_lb_v1_Server, ip_address, ip_address, 0),
     PB_FIELD(  2, INT32   , OPTIONAL, STATIC  , OTHER, grpc_lb_v1_Server, port, ip_address, 0),
     PB_FIELD(  3, STRING  , OPTIONAL, STATIC  , OTHER, grpc_lb_v1_Server, load_balance_token, port, 0),
-    PB_FIELD(  4, BOOL    , OPTIONAL, STATIC  , OTHER, grpc_lb_v1_Server, drop_request, load_balance_token, 0),
+    PB_FIELD(  4, BOOL    , OPTIONAL, STATIC  , OTHER, grpc_lb_v1_Server, drop_for_rate_limiting, load_balance_token, 0),
+    PB_FIELD(  5, BOOL    , OPTIONAL, STATIC  , OTHER, grpc_lb_v1_Server, drop_for_load_balancing, drop_for_rate_limiting, 0),
     PB_LAST_FIELD
 };
 
@@ -70,7 +81,7 @@
  * numbers or field sizes that are larger than what can fit in 8 or 16 bit
  * field descriptors.
  */
-PB_STATIC_ASSERT((pb_membersize(grpc_lb_v1_LoadBalanceRequest, initial_request) < 65536 && pb_membersize(grpc_lb_v1_LoadBalanceRequest, client_stats) < 65536 && pb_membersize(grpc_lb_v1_LoadBalanceResponse, initial_response) < 65536 && pb_membersize(grpc_lb_v1_LoadBalanceResponse, server_list) < 65536 && pb_membersize(grpc_lb_v1_InitialLoadBalanceResponse, client_stats_report_interval) < 65536 && pb_membersize(grpc_lb_v1_ServerList, servers) < 65536 && pb_membersize(grpc_lb_v1_ServerList, expiration_interval) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_grpc_lb_v1_Duration_grpc_lb_v1_LoadBalanceRequest_grpc_lb_v1_InitialLoadBalanceRequest_grpc_lb_v1_ClientStats_grpc_lb_v1_LoadBalanceResponse_grpc_lb_v1_InitialLoadBalanceResponse_grpc_lb_v1_ServerList_grpc_lb_v1_Server)
+PB_STATIC_ASSERT((pb_membersize(grpc_lb_v1_LoadBalanceRequest, initial_request) < 65536 && pb_membersize(grpc_lb_v1_LoadBalanceRequest, client_stats) < 65536 && pb_membersize(grpc_lb_v1_ClientStats, timestamp) < 65536 && pb_membersize(grpc_lb_v1_LoadBalanceResponse, initial_response) < 65536 && pb_membersize(grpc_lb_v1_LoadBalanceResponse, server_list) < 65536 && pb_membersize(grpc_lb_v1_InitialLoadBalanceResponse, client_stats_report_interval) < 65536 && pb_membersize(grpc_lb_v1_ServerList, servers) < 65536 && pb_membersize(grpc_lb_v1_ServerList, expiration_interval) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_grpc_lb_v1_Duration_grpc_lb_v1_Timestamp_grpc_lb_v1_LoadBalanceRequest_grpc_lb_v1_InitialLoadBalanceRequest_grpc_lb_v1_ClientStats_grpc_lb_v1_LoadBalanceResponse_grpc_lb_v1_InitialLoadBalanceResponse_grpc_lb_v1_ServerList_grpc_lb_v1_Server)
 #endif
 
 #if !defined(PB_FIELD_16BIT) && !defined(PB_FIELD_32BIT)
@@ -81,7 +92,7 @@
  * numbers or field sizes that are larger than what can fit in the default
  * 8 bit descriptors.
  */
-PB_STATIC_ASSERT((pb_membersize(grpc_lb_v1_LoadBalanceRequest, initial_request) < 256 && pb_membersize(grpc_lb_v1_LoadBalanceRequest, client_stats) < 256 && pb_membersize(grpc_lb_v1_LoadBalanceResponse, initial_response) < 256 && pb_membersize(grpc_lb_v1_LoadBalanceResponse, server_list) < 256 && pb_membersize(grpc_lb_v1_InitialLoadBalanceResponse, client_stats_report_interval) < 256 && pb_membersize(grpc_lb_v1_ServerList, servers) < 256 && pb_membersize(grpc_lb_v1_ServerList, expiration_interval) < 256), YOU_MUST_DEFINE_PB_FIELD_16BIT_FOR_MESSAGES_grpc_lb_v1_Duration_grpc_lb_v1_LoadBalanceRequest_grpc_lb_v1_InitialLoadBalanceRequest_grpc_lb_v1_ClientStats_grpc_lb_v1_LoadBalanceResponse_grpc_lb_v1_InitialLoadBalanceResponse_grpc_lb_v1_ServerList_grpc_lb_v1_Server)
+PB_STATIC_ASSERT((pb_membersize(grpc_lb_v1_LoadBalanceRequest, initial_request) < 256 && pb_membersize(grpc_lb_v1_LoadBalanceRequest, client_stats) < 256 && pb_membersize(grpc_lb_v1_ClientStats, timestamp) < 256 && pb_membersize(grpc_lb_v1_LoadBalanceResponse, initial_response) < 256 && pb_membersize(grpc_lb_v1_LoadBalanceResponse, server_list) < 256 && pb_membersize(grpc_lb_v1_InitialLoadBalanceResponse, client_stats_report_interval) < 256 && pb_membersize(grpc_lb_v1_ServerList, servers) < 256 && pb_membersize(grpc_lb_v1_ServerList, expiration_interval) < 256), YOU_MUST_DEFINE_PB_FIELD_16BIT_FOR_MESSAGES_grpc_lb_v1_Duration_grpc_lb_v1_Timestamp_grpc_lb_v1_LoadBalanceRequest_grpc_lb_v1_InitialLoadBalanceRequest_grpc_lb_v1_ClientStats_grpc_lb_v1_LoadBalanceResponse_grpc_lb_v1_InitialLoadBalanceResponse_grpc_lb_v1_ServerList_grpc_lb_v1_Server)
 #endif
 
 
diff --git a/src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h b/src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h
index 725aa7e..d3ae919 100644
--- a/src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h
+++ b/src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h
@@ -14,16 +14,6 @@
 #endif
 
 /* Struct definitions */
-typedef struct _grpc_lb_v1_ClientStats {
-    bool has_total_requests;
-    int64_t total_requests;
-    bool has_client_rpc_errors;
-    int64_t client_rpc_errors;
-    bool has_dropped_requests;
-    int64_t dropped_requests;
-/* @@protoc_insertion_point(struct:grpc_lb_v1_ClientStats) */
-} grpc_lb_v1_ClientStats;
-
 typedef struct _grpc_lb_v1_Duration {
     bool has_seconds;
     int64_t seconds;
@@ -46,11 +36,39 @@
     int32_t port;
     bool has_load_balance_token;
     char load_balance_token[50];
-    bool has_drop_request;
-    bool drop_request;
+    bool has_drop_for_rate_limiting;
+    bool drop_for_rate_limiting;
+    bool has_drop_for_load_balancing;
+    bool drop_for_load_balancing;
 /* @@protoc_insertion_point(struct:grpc_lb_v1_Server) */
 } grpc_lb_v1_Server;
 
+typedef struct _grpc_lb_v1_Timestamp {
+    bool has_seconds;
+    int64_t seconds;
+    bool has_nanos;
+    int32_t nanos;
+/* @@protoc_insertion_point(struct:grpc_lb_v1_Timestamp) */
+} grpc_lb_v1_Timestamp;
+
+typedef struct _grpc_lb_v1_ClientStats {
+    bool has_timestamp;
+    grpc_lb_v1_Timestamp timestamp;
+    bool has_num_calls_started;
+    int64_t num_calls_started;
+    bool has_num_calls_finished;
+    int64_t num_calls_finished;
+    bool has_num_calls_finished_with_drop_for_rate_limiting;
+    int64_t num_calls_finished_with_drop_for_rate_limiting;
+    bool has_num_calls_finished_with_drop_for_load_balancing;
+    int64_t num_calls_finished_with_drop_for_load_balancing;
+    bool has_num_calls_finished_with_client_failed_to_send;
+    int64_t num_calls_finished_with_client_failed_to_send;
+    bool has_num_calls_finished_known_received;
+    int64_t num_calls_finished_known_received;
+/* @@protoc_insertion_point(struct:grpc_lb_v1_ClientStats) */
+} grpc_lb_v1_ClientStats;
+
 typedef struct _grpc_lb_v1_InitialLoadBalanceResponse {
     bool has_load_balancer_delegate;
     char load_balancer_delegate[64];
@@ -59,6 +77,13 @@
 /* @@protoc_insertion_point(struct:grpc_lb_v1_InitialLoadBalanceResponse) */
 } grpc_lb_v1_InitialLoadBalanceResponse;
 
+typedef struct _grpc_lb_v1_ServerList {
+    pb_callback_t servers;
+    bool has_expiration_interval;
+    grpc_lb_v1_Duration expiration_interval;
+/* @@protoc_insertion_point(struct:grpc_lb_v1_ServerList) */
+} grpc_lb_v1_ServerList;
+
 typedef struct _grpc_lb_v1_LoadBalanceRequest {
     bool has_initial_request;
     grpc_lb_v1_InitialLoadBalanceRequest initial_request;
@@ -67,13 +92,6 @@
 /* @@protoc_insertion_point(struct:grpc_lb_v1_LoadBalanceRequest) */
 } grpc_lb_v1_LoadBalanceRequest;
 
-typedef struct _grpc_lb_v1_ServerList {
-    pb_callback_t servers;
-    bool has_expiration_interval;
-    grpc_lb_v1_Duration expiration_interval;
-/* @@protoc_insertion_point(struct:grpc_lb_v1_ServerList) */
-} grpc_lb_v1_ServerList;
-
 typedef struct _grpc_lb_v1_LoadBalanceResponse {
     bool has_initial_response;
     grpc_lb_v1_InitialLoadBalanceResponse initial_response;
@@ -86,61 +104,72 @@
 
 /* Initializer values for message structs */
 #define grpc_lb_v1_Duration_init_default         {false, 0, false, 0}
+#define grpc_lb_v1_Timestamp_init_default        {false, 0, false, 0}
 #define grpc_lb_v1_LoadBalanceRequest_init_default {false, grpc_lb_v1_InitialLoadBalanceRequest_init_default, false, grpc_lb_v1_ClientStats_init_default}
 #define grpc_lb_v1_InitialLoadBalanceRequest_init_default {false, ""}
-#define grpc_lb_v1_ClientStats_init_default      {false, 0, false, 0, false, 0}
+#define grpc_lb_v1_ClientStats_init_default      {false, grpc_lb_v1_Timestamp_init_default, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0}
 #define grpc_lb_v1_LoadBalanceResponse_init_default {false, grpc_lb_v1_InitialLoadBalanceResponse_init_default, false, grpc_lb_v1_ServerList_init_default}
 #define grpc_lb_v1_InitialLoadBalanceResponse_init_default {false, "", false, grpc_lb_v1_Duration_init_default}
 #define grpc_lb_v1_ServerList_init_default       {{{NULL}, NULL}, false, grpc_lb_v1_Duration_init_default}
-#define grpc_lb_v1_Server_init_default           {false, {0, {0}}, false, 0, false, "", false, 0}
+#define grpc_lb_v1_Server_init_default           {false, {0, {0}}, false, 0, false, "", false, 0, false, 0}
 #define grpc_lb_v1_Duration_init_zero            {false, 0, false, 0}
+#define grpc_lb_v1_Timestamp_init_zero           {false, 0, false, 0}
 #define grpc_lb_v1_LoadBalanceRequest_init_zero  {false, grpc_lb_v1_InitialLoadBalanceRequest_init_zero, false, grpc_lb_v1_ClientStats_init_zero}
 #define grpc_lb_v1_InitialLoadBalanceRequest_init_zero {false, ""}
-#define grpc_lb_v1_ClientStats_init_zero         {false, 0, false, 0, false, 0}
+#define grpc_lb_v1_ClientStats_init_zero         {false, grpc_lb_v1_Timestamp_init_zero, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0}
 #define grpc_lb_v1_LoadBalanceResponse_init_zero {false, grpc_lb_v1_InitialLoadBalanceResponse_init_zero, false, grpc_lb_v1_ServerList_init_zero}
 #define grpc_lb_v1_InitialLoadBalanceResponse_init_zero {false, "", false, grpc_lb_v1_Duration_init_zero}
 #define grpc_lb_v1_ServerList_init_zero          {{{NULL}, NULL}, false, grpc_lb_v1_Duration_init_zero}
-#define grpc_lb_v1_Server_init_zero              {false, {0, {0}}, false, 0, false, "", false, 0}
+#define grpc_lb_v1_Server_init_zero              {false, {0, {0}}, false, 0, false, "", false, 0, false, 0}
 
 /* Field tags (for use in manual encoding/decoding) */
-#define grpc_lb_v1_ClientStats_total_requests_tag 1
-#define grpc_lb_v1_ClientStats_client_rpc_errors_tag 2
-#define grpc_lb_v1_ClientStats_dropped_requests_tag 3
 #define grpc_lb_v1_Duration_seconds_tag          1
 #define grpc_lb_v1_Duration_nanos_tag            2
 #define grpc_lb_v1_InitialLoadBalanceRequest_name_tag 1
 #define grpc_lb_v1_Server_ip_address_tag         1
 #define grpc_lb_v1_Server_port_tag               2
 #define grpc_lb_v1_Server_load_balance_token_tag 3
-#define grpc_lb_v1_Server_drop_request_tag       4
+#define grpc_lb_v1_Server_drop_for_rate_limiting_tag 4
+#define grpc_lb_v1_Server_drop_for_load_balancing_tag 5
+#define grpc_lb_v1_Timestamp_seconds_tag         1
+#define grpc_lb_v1_Timestamp_nanos_tag           2
+#define grpc_lb_v1_ClientStats_timestamp_tag     1
+#define grpc_lb_v1_ClientStats_num_calls_started_tag 2
+#define grpc_lb_v1_ClientStats_num_calls_finished_tag 3
+#define grpc_lb_v1_ClientStats_num_calls_finished_with_drop_for_rate_limiting_tag 4
+#define grpc_lb_v1_ClientStats_num_calls_finished_with_drop_for_load_balancing_tag 5
+#define grpc_lb_v1_ClientStats_num_calls_finished_with_client_failed_to_send_tag 6
+#define grpc_lb_v1_ClientStats_num_calls_finished_known_received_tag 7
 #define grpc_lb_v1_InitialLoadBalanceResponse_load_balancer_delegate_tag 1
 #define grpc_lb_v1_InitialLoadBalanceResponse_client_stats_report_interval_tag 2
-#define grpc_lb_v1_LoadBalanceRequest_initial_request_tag 1
-#define grpc_lb_v1_LoadBalanceRequest_client_stats_tag 2
 #define grpc_lb_v1_ServerList_servers_tag        1
 #define grpc_lb_v1_ServerList_expiration_interval_tag 3
+#define grpc_lb_v1_LoadBalanceRequest_initial_request_tag 1
+#define grpc_lb_v1_LoadBalanceRequest_client_stats_tag 2
 #define grpc_lb_v1_LoadBalanceResponse_initial_response_tag 1
 #define grpc_lb_v1_LoadBalanceResponse_server_list_tag 2
 
 /* Struct field encoding specification for nanopb */
 extern const pb_field_t grpc_lb_v1_Duration_fields[3];
+extern const pb_field_t grpc_lb_v1_Timestamp_fields[3];
 extern const pb_field_t grpc_lb_v1_LoadBalanceRequest_fields[3];
 extern const pb_field_t grpc_lb_v1_InitialLoadBalanceRequest_fields[2];
-extern const pb_field_t grpc_lb_v1_ClientStats_fields[4];
+extern const pb_field_t grpc_lb_v1_ClientStats_fields[8];
 extern const pb_field_t grpc_lb_v1_LoadBalanceResponse_fields[3];
 extern const pb_field_t grpc_lb_v1_InitialLoadBalanceResponse_fields[3];
 extern const pb_field_t grpc_lb_v1_ServerList_fields[3];
-extern const pb_field_t grpc_lb_v1_Server_fields[5];
+extern const pb_field_t grpc_lb_v1_Server_fields[6];
 
 /* Maximum encoded size of messages (where known) */
 #define grpc_lb_v1_Duration_size                 22
-#define grpc_lb_v1_LoadBalanceRequest_size       169
+#define grpc_lb_v1_Timestamp_size                22
+#define grpc_lb_v1_LoadBalanceRequest_size       226
 #define grpc_lb_v1_InitialLoadBalanceRequest_size 131
-#define grpc_lb_v1_ClientStats_size              33
+#define grpc_lb_v1_ClientStats_size              90
 #define grpc_lb_v1_LoadBalanceResponse_size      (98 + grpc_lb_v1_ServerList_size)
 #define grpc_lb_v1_InitialLoadBalanceResponse_size 90
 /* grpc_lb_v1_ServerList_size depends on runtime parameters */
-#define grpc_lb_v1_Server_size                   83
+#define grpc_lb_v1_Server_size                   85
 
 /* Message IDs (where set with "msgid" option) */
 #ifdef PB_MSGID
diff --git a/src/core/ext/filters/client_channel/lb_policy_factory.c b/src/core/ext/filters/client_channel/lb_policy_factory.c
index e2af216..89b8bf8 100644
--- a/src/core/ext/filters/client_channel/lb_policy_factory.c
+++ b/src/core/ext/filters/client_channel/lb_policy_factory.c
@@ -36,16 +36,18 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/string_util.h>
 
+#include "src/core/lib/channel/channel_args.h"
+
 #include "src/core/ext/filters/client_channel/lb_policy_factory.h"
+#include "src/core/ext/filters/client_channel/parse_address.h"
 
 grpc_lb_addresses* grpc_lb_addresses_create(
     size_t num_addresses, const grpc_lb_user_data_vtable* user_data_vtable) {
-  grpc_lb_addresses* addresses = gpr_malloc(sizeof(grpc_lb_addresses));
+  grpc_lb_addresses* addresses = gpr_zalloc(sizeof(grpc_lb_addresses));
   addresses->num_addresses = num_addresses;
   addresses->user_data_vtable = user_data_vtable;
   const size_t addresses_size = sizeof(grpc_lb_address) * num_addresses;
-  addresses->addresses = gpr_malloc(addresses_size);
-  memset(addresses->addresses, 0, addresses_size);
+  addresses->addresses = gpr_zalloc(addresses_size);
   return addresses;
 }
 
@@ -69,7 +71,7 @@
 
 void grpc_lb_addresses_set_address(grpc_lb_addresses* addresses, size_t index,
                                    void* address, size_t address_len,
-                                   bool is_balancer, char* balancer_name,
+                                   bool is_balancer, const char* balancer_name,
                                    void* user_data) {
   GPR_ASSERT(index < addresses->num_addresses);
   if (user_data != NULL) GPR_ASSERT(addresses->user_data_vtable != NULL);
@@ -77,10 +79,22 @@
   memcpy(target->address.addr, address, address_len);
   target->address.len = address_len;
   target->is_balancer = is_balancer;
-  target->balancer_name = balancer_name;
+  target->balancer_name = gpr_strdup(balancer_name);
   target->user_data = user_data;
 }
 
+bool grpc_lb_addresses_set_address_from_uri(grpc_lb_addresses* addresses,
+                                            size_t index, const grpc_uri* uri,
+                                            bool is_balancer,
+                                            const char* balancer_name,
+                                            void* user_data) {
+  grpc_resolved_address address;
+  if (!grpc_parse_uri(uri, &address)) return false;
+  grpc_lb_addresses_set_address(addresses, index, address.addr, address.len,
+                                is_balancer, balancer_name, user_data);
+  return true;
+}
+
 int grpc_lb_addresses_cmp(const grpc_lb_addresses* addresses1,
                           const grpc_lb_addresses* addresses2) {
   if (addresses1->num_addresses > addresses2->num_addresses) return 1;
@@ -147,6 +161,15 @@
   return arg;
 }
 
+grpc_lb_addresses* grpc_lb_addresses_find_channel_arg(
+    const grpc_channel_args* channel_args) {
+  const grpc_arg* lb_addresses_arg =
+      grpc_channel_args_find(channel_args, GRPC_ARG_LB_ADDRESSES);
+  if (lb_addresses_arg == NULL || lb_addresses_arg->type != GRPC_ARG_POINTER)
+    return NULL;
+  return lb_addresses_arg->value.pointer.p;
+}
+
 void grpc_lb_policy_factory_ref(grpc_lb_policy_factory* factory) {
   factory->vtable->ref(factory);
 }
diff --git a/src/core/ext/filters/client_channel/lb_policy_factory.h b/src/core/ext/filters/client_channel/lb_policy_factory.h
index 81ab12e..9d6c0fc 100644
--- a/src/core/ext/filters/client_channel/lb_policy_factory.h
+++ b/src/core/ext/filters/client_channel/lb_policy_factory.h
@@ -34,12 +34,13 @@
 #ifndef GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_FACTORY_H
 #define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_FACTORY_H
 
-#include "src/core/ext/filters/client_channel/client_channel_factory.h"
-#include "src/core/ext/filters/client_channel/lb_policy.h"
-
 #include "src/core/lib/iomgr/exec_ctx.h"
 #include "src/core/lib/iomgr/resolve_address.h"
 
+#include "src/core/ext/filters/client_channel/client_channel_factory.h"
+#include "src/core/ext/filters/client_channel/lb_policy.h"
+#include "src/core/ext/filters/client_channel/uri_parser.h"
+
 // Channel arg key for grpc_lb_addresses.
 #define GRPC_ARG_LB_ADDRESSES "grpc.lb_addresses"
 
@@ -88,9 +89,18 @@
  * Takes ownership of \a balancer_name. */
 void grpc_lb_addresses_set_address(grpc_lb_addresses *addresses, size_t index,
                                    void *address, size_t address_len,
-                                   bool is_balancer, char *balancer_name,
+                                   bool is_balancer, const char *balancer_name,
                                    void *user_data);
 
+/** Sets the value of the address at index \a index of \a addresses from \a uri.
+ * Returns true upon success, false otherwise. Takes ownership of \a
+ * balancer_name. */
+bool grpc_lb_addresses_set_address_from_uri(grpc_lb_addresses *addresses,
+                                            size_t index, const grpc_uri *uri,
+                                            bool is_balancer,
+                                            const char *balancer_name,
+                                            void *user_data);
+
 /** Compares \a addresses1 and \a addresses2. */
 int grpc_lb_addresses_cmp(const grpc_lb_addresses *addresses1,
                           const grpc_lb_addresses *addresses2);
@@ -103,6 +113,10 @@
 grpc_arg grpc_lb_addresses_create_channel_arg(
     const grpc_lb_addresses *addresses);
 
+/** Returns the \a grpc_lb_addresses instance in \a channel_args or NULL */
+grpc_lb_addresses *grpc_lb_addresses_find_channel_arg(
+    const grpc_channel_args *channel_args);
+
 /** Arguments passed to LB policies. */
 typedef struct grpc_lb_policy_args {
   grpc_client_channel_factory *client_channel_factory;
diff --git a/src/core/ext/filters/client_channel/parse_address.c b/src/core/ext/filters/client_channel/parse_address.c
index 0c97062..edc6ce6 100644
--- a/src/core/ext/filters/client_channel/parse_address.c
+++ b/src/core/ext/filters/client_channel/parse_address.c
@@ -48,7 +48,12 @@
 
 #ifdef GRPC_HAVE_UNIX_SOCKET
 
-int parse_unix(grpc_uri *uri, grpc_resolved_address *resolved_addr) {
+bool grpc_parse_unix(const grpc_uri *uri,
+                     grpc_resolved_address *resolved_addr) {
+  if (strcmp("unix", uri->scheme) != 0) {
+    gpr_log(GPR_ERROR, "Expected 'unix' scheme, got '%s'", uri->scheme);
+    return false;
+  }
   struct sockaddr_un *un = (struct sockaddr_un *)resolved_addr->addr;
   const size_t maxlen = sizeof(un->sun_path);
   const size_t path_len = strnlen(uri->path, maxlen);
@@ -61,21 +66,29 @@
 
 #else /* GRPC_HAVE_UNIX_SOCKET */
 
-int parse_unix(grpc_uri *uri, grpc_resolved_address *resolved_addr) { abort(); }
+bool grpc_parse_unix(const grpc_uri *uri,
+                     grpc_resolved_address *resolved_addr) {
+  abort();
+}
 
 #endif /* GRPC_HAVE_UNIX_SOCKET */
 
-int parse_ipv4(grpc_uri *uri, grpc_resolved_address *resolved_addr) {
+bool grpc_parse_ipv4(const grpc_uri *uri,
+                     grpc_resolved_address *resolved_addr) {
+  if (strcmp("ipv4", uri->scheme) != 0) {
+    gpr_log(GPR_ERROR, "Expected 'ipv4' scheme, got '%s'", uri->scheme);
+    return false;
+  }
   const char *host_port = uri->path;
   char *host;
   char *port;
   int port_num;
-  int result = 0;
+  bool result = false;
   struct sockaddr_in *in = (struct sockaddr_in *)resolved_addr->addr;
 
   if (*host_port == '/') ++host_port;
   if (!gpr_split_host_port(host_port, &host, &port)) {
-    return 0;
+    return false;
   }
 
   memset(resolved_addr, 0, sizeof(grpc_resolved_address));
@@ -98,14 +111,19 @@
     goto done;
   }
 
-  result = 1;
+  result = true;
 done:
   gpr_free(host);
   gpr_free(port);
   return result;
 }
 
-int parse_ipv6(grpc_uri *uri, grpc_resolved_address *resolved_addr) {
+bool grpc_parse_ipv6(const grpc_uri *uri,
+                     grpc_resolved_address *resolved_addr) {
+  if (strcmp("ipv6", uri->scheme) != 0) {
+    gpr_log(GPR_ERROR, "Expected 'ipv6' scheme, got '%s'", uri->scheme);
+    return false;
+  }
   const char *host_port = uri->path;
   char *host;
   char *port;
@@ -168,3 +186,15 @@
   gpr_free(port);
   return result;
 }
+
+bool grpc_parse_uri(const grpc_uri *uri, grpc_resolved_address *resolved_addr) {
+  if (strcmp("unix", uri->scheme) == 0) {
+    return grpc_parse_unix(uri, resolved_addr);
+  } else if (strcmp("ipv4", uri->scheme) == 0) {
+    return grpc_parse_ipv4(uri, resolved_addr);
+  } else if (strcmp("ipv6", uri->scheme) == 0) {
+    return grpc_parse_ipv6(uri, resolved_addr);
+  }
+  gpr_log(GPR_ERROR, "Can't parse scheme '%s'", uri->scheme);
+  return false;
+}
diff --git a/src/core/ext/filters/client_channel/parse_address.h b/src/core/ext/filters/client_channel/parse_address.h
index c8d77ba..fa7ea33 100644
--- a/src/core/ext/filters/client_channel/parse_address.h
+++ b/src/core/ext/filters/client_channel/parse_address.h
@@ -39,16 +39,19 @@
 #include "src/core/ext/filters/client_channel/uri_parser.h"
 #include "src/core/lib/iomgr/resolve_address.h"
 
-/** Populate \a addr and \a len from \a uri, whose path is expected to contain a
+/** Populate \a resolved_addr from \a uri, whose path is expected to contain a
  * unix socket path. Returns true upon success. */
-int parse_unix(grpc_uri *uri, grpc_resolved_address *resolved_addr);
+bool grpc_parse_unix(const grpc_uri *uri, grpc_resolved_address *resolved_addr);
 
-/** Populate /a addr and \a len from \a uri, whose path is expected to contain a
- * host:port pair. Returns true upon success. */
-int parse_ipv4(grpc_uri *uri, grpc_resolved_address *resolved_addr);
+/** Populate \a resolved_addr from \a uri, whose path is expected to contain an
+ * IPv4 host:port pair. Returns true upon success. */
+bool grpc_parse_ipv4(const grpc_uri *uri, grpc_resolved_address *resolved_addr);
 
-/** Populate /a addr and \a len from \a uri, whose path is expected to contain a
- * host:port pair. Returns true upon success. */
-int parse_ipv6(grpc_uri *uri, grpc_resolved_address *resolved_addr);
+/** Populate \a resolved_addr from \a uri, whose path is expected to contain an
+ * IPv6 host:port pair. Returns true upon success. */
+bool grpc_parse_ipv6(const grpc_uri *uri, grpc_resolved_address *resolved_addr);
+
+/** Populate \a resolved_addr from \a uri. Returns true upon success. */
+bool grpc_parse_uri(const grpc_uri *uri, grpc_resolved_address *resolved_addr);
 
 #endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_PARSE_ADDRESS_H */
diff --git a/src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.c b/src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.c
index 54f020d..4d7d878 100644
--- a/src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.c
+++ b/src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.c
@@ -157,8 +157,8 @@
 
 static grpc_resolver *sockaddr_create(grpc_exec_ctx *exec_ctx,
                                       grpc_resolver_args *args,
-                                      int parse(grpc_uri *uri,
-                                                grpc_resolved_address *dst)) {
+                                      bool parse(const grpc_uri *uri,
+                                                 grpc_resolved_address *dst)) {
   if (0 != strcmp(args->uri->authority, "")) {
     gpr_log(GPR_ERROR, "authority based uri's not supported by the %s scheme",
             args->uri->scheme);
@@ -209,7 +209,7 @@
   static grpc_resolver *name##_factory_create_resolver(                     \
       grpc_exec_ctx *exec_ctx, grpc_resolver_factory *factory,              \
       grpc_resolver_args *args) {                                           \
-    return sockaddr_create(exec_ctx, args, parse_##name);                   \
+    return sockaddr_create(exec_ctx, args, grpc_parse_##name);              \
   }                                                                         \
   static const grpc_resolver_factory_vtable name##_factory_vtable = {       \
       sockaddr_factory_ref, sockaddr_factory_unref,                         \
diff --git a/src/core/ext/filters/client_channel/subchannel.c b/src/core/ext/filters/client_channel/subchannel.c
index 9a7a7a0..967e571 100644
--- a/src/core/ext/filters/client_channel/subchannel.c
+++ b/src/core/ext/filters/client_channel/subchannel.c
@@ -59,9 +59,9 @@
 #define INTERNAL_REF_BITS 16
 #define STRONG_REF_MASK (~(gpr_atm)((1 << INTERNAL_REF_BITS) - 1))
 
-#define GRPC_SUBCHANNEL_MIN_CONNECT_TIMEOUT_SECONDS 20
 #define GRPC_SUBCHANNEL_INITIAL_CONNECT_BACKOFF_SECONDS 1
 #define GRPC_SUBCHANNEL_RECONNECT_BACKOFF_MULTIPLIER 1.6
+#define GRPC_SUBCHANNEL_RECONNECT_MIN_BACKOFF_SECONDS 20
 #define GRPC_SUBCHANNEL_RECONNECT_MAX_BACKOFF_SECONDS 120
 #define GRPC_SUBCHANNEL_RECONNECT_JITTER 0.2
 
@@ -353,8 +353,8 @@
                                "subchannel");
   int initial_backoff_ms =
       GRPC_SUBCHANNEL_INITIAL_CONNECT_BACKOFF_SECONDS * 1000;
+  int min_backoff_ms = GRPC_SUBCHANNEL_RECONNECT_MIN_BACKOFF_SECONDS * 1000;
   int max_backoff_ms = GRPC_SUBCHANNEL_RECONNECT_MAX_BACKOFF_SECONDS * 1000;
-  int min_backoff_ms = GRPC_SUBCHANNEL_MIN_CONNECT_TIMEOUT_SECONDS * 1000;
   bool fixed_reconnect_backoff = false;
   if (c->args) {
     for (size_t i = 0; i < c->args->num_args; i++) {
@@ -366,6 +366,12 @@
                 &c->args->args[i],
                 (grpc_integer_options){initial_backoff_ms, 100, INT_MAX});
       } else if (0 == strcmp(c->args->args[i].key,
+                             GRPC_ARG_MIN_RECONNECT_BACKOFF_MS)) {
+        fixed_reconnect_backoff = false;
+        min_backoff_ms = grpc_channel_arg_get_integer(
+            &c->args->args[i],
+            (grpc_integer_options){min_backoff_ms, 100, INT_MAX});
+      } else if (0 == strcmp(c->args->args[i].key,
                              GRPC_ARG_MAX_RECONNECT_BACKOFF_MS)) {
         fixed_reconnect_backoff = false;
         max_backoff_ms = grpc_channel_arg_get_integer(
@@ -797,13 +803,7 @@
                                  grpc_resolved_address *addr) {
   grpc_uri *uri = grpc_uri_parse(exec_ctx, uri_str, 0 /* suppress_errors */);
   GPR_ASSERT(uri != NULL);
-  if (strcmp(uri->scheme, "ipv4") == 0) {
-    GPR_ASSERT(parse_ipv4(uri, addr));
-  } else if (strcmp(uri->scheme, "ipv6") == 0) {
-    GPR_ASSERT(parse_ipv6(uri, addr));
-  } else {
-    GPR_ASSERT(parse_unix(uri, addr));
-  }
+  if (!grpc_parse_uri(uri, addr)) memset(addr, 0, sizeof(*addr));
   grpc_uri_destroy(uri);
 }
 
diff --git a/src/core/ext/filters/client_channel/uri_parser.c b/src/core/ext/filters/client_channel/uri_parser.c
index 01b9991..b233d83 100644
--- a/src/core/ext/filters/client_channel/uri_parser.c
+++ b/src/core/ext/filters/client_channel/uri_parser.c
@@ -50,7 +50,7 @@
 #define NOT_SET (~(size_t)0)
 
 static grpc_uri *bad_uri(const char *uri_text, size_t pos, const char *section,
-                         int suppress_errors) {
+                         bool suppress_errors) {
   char *line_prefix;
   size_t pfx_len;
 
@@ -83,6 +83,11 @@
   return out;
 }
 
+static bool valid_hex(char c) {
+  return ((c >= 'a') && (c <= 'f')) || ((c >= 'A') && (c <= 'F')) ||
+         ((c >= '0') && (c <= '9'));
+}
+
 /** Returns how many chars to advance if \a uri_text[i] begins a valid \a pchar
  * production. If \a uri_text[i] introduces an invalid \a pchar (such as percent
  * sign not followed by two hex digits), NOT_SET is returned. */
@@ -93,27 +98,36 @@
    * sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
    / "*" / "+" / "," / ";" / "=" */
   char c = uri_text[i];
-  if (((c >= 'A') && (c <= 'Z')) || ((c >= 'a') && (c <= 'z')) ||
-      ((c >= '0') && (c <= '9')) ||
-      (c == '-' || c == '.' || c == '_' || c == '~') || /* unreserved */
-      (c == '!' || c == '$' || c == '&' || c == '\'' || c == '$' || c == '&' ||
-       c == '(' || c == ')' || c == '*' || c == '+' || c == ',' || c == ';' ||
-       c == '=') /* sub-delims */) {
-    return 1;
-  }
-  if (c == '%') { /* pct-encoded */
-    size_t j;
-    if (uri_text[i + 1] == 0 || uri_text[i + 2] == 0) {
-      return NOT_SET;
-    }
-    for (j = i + 1; j < 2; j++) {
-      c = uri_text[j];
-      if (!(((c >= '0') && (c <= '9')) || ((c >= 'a') && (c <= 'f')) ||
-            ((c >= 'A') && (c <= 'F')))) {
-        return NOT_SET;
+  switch (c) {
+    default:
+      if (((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z')) ||
+          ((c >= '0') && (c <= '9'))) {
+        return 1;
       }
-    }
-    return 2;
+      break;
+    case ':':
+    case '@':
+    case '-':
+    case '.':
+    case '_':
+    case '~':
+    case '!':
+    case '$':
+    case '&':
+    case '\'':
+    case '(':
+    case ')':
+    case '*':
+    case '+':
+    case ',':
+    case ';':
+    case '=':
+      return 1;
+    case '%': /* pct-encoded */
+      if (valid_hex(uri_text[i + 1]) && valid_hex(uri_text[i + 2])) {
+        return 2;
+      }
+      return NOT_SET;
   }
   return 0;
 }
@@ -183,7 +197,7 @@
 }
 
 grpc_uri *grpc_uri_parse(grpc_exec_ctx *exec_ctx, const char *uri_text,
-                         int suppress_errors) {
+                         bool suppress_errors) {
   grpc_uri *uri;
   size_t scheme_begin = 0;
   size_t scheme_end = NOT_SET;
diff --git a/src/core/ext/filters/client_channel/uri_parser.h b/src/core/ext/filters/client_channel/uri_parser.h
index 2698d44..b889040 100644
--- a/src/core/ext/filters/client_channel/uri_parser.h
+++ b/src/core/ext/filters/client_channel/uri_parser.h
@@ -53,7 +53,7 @@
 
 /** parse a uri, return NULL on failure */
 grpc_uri *grpc_uri_parse(grpc_exec_ctx *exec_ctx, const char *uri_text,
-                         int suppress_errors);
+                         bool suppress_errors);
 
 /** return the part of a query string after the '=' in "?key=xxx&...", or NULL
  * if key is not present */
diff --git a/src/core/lib/channel/deadline_filter.c b/src/core/ext/filters/deadline/deadline_filter.c
similarity index 89%
rename from src/core/lib/channel/deadline_filter.c
rename to src/core/ext/filters/deadline/deadline_filter.c
index fda099b..2e03d16 100644
--- a/src/core/lib/channel/deadline_filter.c
+++ b/src/core/ext/filters/deadline/deadline_filter.c
@@ -29,7 +29,7 @@
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 //
 
-#include "src/core/lib/channel/deadline_filter.h"
+#include "src/core/ext/filters/deadline/deadline_filter.h"
 
 #include <stdbool.h>
 #include <string.h>
@@ -39,9 +39,11 @@
 #include <grpc/support/sync.h>
 #include <grpc/support/time.h>
 
+#include "src/core/lib/channel/channel_stack_builder.h"
 #include "src/core/lib/iomgr/exec_ctx.h"
 #include "src/core/lib/iomgr/timer.h"
 #include "src/core/lib/slice/slice_internal.h"
+#include "src/core/lib/surface/channel_init.h"
 
 //
 // grpc_deadline_state
@@ -141,18 +143,6 @@
   op->on_complete = &deadline_state->on_complete;
 }
 
-void grpc_deadline_state_init(grpc_exec_ctx* exec_ctx, grpc_call_element* elem,
-                              grpc_call_stack* call_stack) {
-  grpc_deadline_state* deadline_state = elem->call_data;
-  deadline_state->call_stack = call_stack;
-}
-
-void grpc_deadline_state_destroy(grpc_exec_ctx* exec_ctx,
-                                 grpc_call_element* elem) {
-  grpc_deadline_state* deadline_state = elem->call_data;
-  cancel_timer_if_needed(exec_ctx, deadline_state);
-}
-
 // Callback and associated state for starting the timer after call stack
 // initialization has been completed.
 struct start_timer_after_init_state {
@@ -167,8 +157,11 @@
   gpr_free(state);
 }
 
-void grpc_deadline_state_start(grpc_exec_ctx* exec_ctx, grpc_call_element* elem,
-                               gpr_timespec deadline) {
+void grpc_deadline_state_init(grpc_exec_ctx* exec_ctx, grpc_call_element* elem,
+                              grpc_call_stack* call_stack,
+                              gpr_timespec deadline) {
+  grpc_deadline_state* deadline_state = elem->call_data;
+  deadline_state->call_stack = call_stack;
   // Deadline will always be infinite on servers, so the timer will only be
   // set on clients with a finite deadline.
   deadline = gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC);
@@ -189,6 +182,12 @@
   }
 }
 
+void grpc_deadline_state_destroy(grpc_exec_ctx* exec_ctx,
+                                 grpc_call_element* elem) {
+  grpc_deadline_state* deadline_state = elem->call_data;
+  cancel_timer_if_needed(exec_ctx, deadline_state);
+}
+
 void grpc_deadline_state_reset(grpc_exec_ctx* exec_ctx, grpc_call_element* elem,
                                gpr_timespec new_deadline) {
   grpc_deadline_state* deadline_state = elem->call_data;
@@ -248,8 +247,7 @@
 static grpc_error* init_call_elem(grpc_exec_ctx* exec_ctx,
                                   grpc_call_element* elem,
                                   const grpc_call_element_args* args) {
-  grpc_deadline_state_init(exec_ctx, elem, args->call_stack);
-  grpc_deadline_state_start(exec_ctx, elem, args->deadline);
+  grpc_deadline_state_init(exec_ctx, elem, args->call_stack, args->deadline);
   return GRPC_ERROR_NONE;
 }
 
@@ -346,3 +344,30 @@
     grpc_channel_next_get_info,
     "deadline",
 };
+
+bool grpc_deadline_checking_enabled(const grpc_channel_args* channel_args) {
+  return grpc_channel_arg_get_bool(
+      grpc_channel_args_find(channel_args, GRPC_ARG_ENABLE_DEADLINE_CHECKS),
+      !grpc_channel_args_want_minimal_stack(channel_args));
+}
+
+static bool maybe_add_deadline_filter(grpc_exec_ctx* exec_ctx,
+                                      grpc_channel_stack_builder* builder,
+                                      void* arg) {
+  return grpc_deadline_checking_enabled(
+             grpc_channel_stack_builder_get_channel_arguments(builder))
+             ? grpc_channel_stack_builder_prepend_filter(builder, arg, NULL,
+                                                         NULL)
+             : true;
+}
+
+void grpc_deadline_filter_init(void) {
+  grpc_channel_init_register_stage(
+      GRPC_CLIENT_DIRECT_CHANNEL, GRPC_CHANNEL_INIT_BUILTIN_PRIORITY,
+      maybe_add_deadline_filter, (void*)&grpc_client_deadline_filter);
+  grpc_channel_init_register_stage(
+      GRPC_SERVER_CHANNEL, GRPC_CHANNEL_INIT_BUILTIN_PRIORITY,
+      maybe_add_deadline_filter, (void*)&grpc_server_deadline_filter);
+}
+
+void grpc_deadline_filter_shutdown(void) {}
diff --git a/src/core/lib/channel/deadline_filter.h b/src/core/ext/filters/deadline/deadline_filter.h
similarity index 89%
rename from src/core/lib/channel/deadline_filter.h
rename to src/core/ext/filters/deadline/deadline_filter.h
index d8db9a9..5050453 100644
--- a/src/core/lib/channel/deadline_filter.h
+++ b/src/core/ext/filters/deadline/deadline_filter.h
@@ -29,8 +29,8 @@
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 //
 
-#ifndef GRPC_CORE_LIB_CHANNEL_DEADLINE_FILTER_H
-#define GRPC_CORE_LIB_CHANNEL_DEADLINE_FILTER_H
+#ifndef GRPC_CORE_EXT_FILTERS_DEADLINE_DEADLINE_FILTER_H
+#define GRPC_CORE_EXT_FILTERS_DEADLINE_DEADLINE_FILTER_H
 
 #include "src/core/lib/channel/channel_stack.h"
 #include "src/core/lib/iomgr/timer.h"
@@ -64,15 +64,11 @@
 
 // assumes elem->call_data is zero'd
 void grpc_deadline_state_init(grpc_exec_ctx* exec_ctx, grpc_call_element* elem,
-                              grpc_call_stack* call_stack);
+                              grpc_call_stack* call_stack,
+                              gpr_timespec deadline);
 void grpc_deadline_state_destroy(grpc_exec_ctx* exec_ctx,
                                  grpc_call_element* elem);
 
-// Starts the timer with the specified deadline.
-// Should be called from the filter's init_call_elem() method.
-void grpc_deadline_state_start(grpc_exec_ctx* exec_ctx, grpc_call_element* elem,
-                               gpr_timespec deadline);
-
 // Cancels the existing timer and starts a new one with new_deadline.
 //
 // Note: It is generally safe to call this with an earlier deadline
@@ -93,10 +89,13 @@
     grpc_exec_ctx* exec_ctx, grpc_call_element* elem,
     grpc_transport_stream_op_batch* op);
 
+// Should deadline checking be performed (according to channel args)
+bool grpc_deadline_checking_enabled(const grpc_channel_args* args);
+
 // Deadline filters for direct client channels and server channels.
 // Note: Deadlines for non-direct client channels are handled by the
 // client_channel filter.
 extern const grpc_channel_filter grpc_client_deadline_filter;
 extern const grpc_channel_filter grpc_server_deadline_filter;
 
-#endif /* GRPC_CORE_LIB_CHANNEL_DEADLINE_FILTER_H */
+#endif /* GRPC_CORE_EXT_FILTERS_DEADLINE_DEADLINE_FILTER_H */
diff --git a/src/core/lib/channel/http_client_filter.c b/src/core/ext/filters/http/client/http_client_filter.c
similarity index 96%
rename from src/core/lib/channel/http_client_filter.c
rename to src/core/ext/filters/http/client/http_client_filter.c
index 4e47c5c..bf5fbc7 100644
--- a/src/core/lib/channel/http_client_filter.c
+++ b/src/core/ext/filters/http/client/http_client_filter.c
@@ -30,7 +30,7 @@
  *
  */
 
-#include "src/core/lib/channel/http_client_filter.h"
+#include "src/core/ext/filters/http/client/http_client_filter.h"
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
@@ -220,10 +220,15 @@
   call_data *calld = elem->call_data;
   uint8_t *wrptr = calld->payload_bytes;
   while (grpc_byte_stream_next(
-      exec_ctx, calld->send_op->payload->send_message.send_message,
-      &calld->incoming_slice, ~(size_t)0, &calld->got_slice)) {
-    memcpy(wrptr, GRPC_SLICE_START_PTR(calld->incoming_slice),
-           GRPC_SLICE_LENGTH(calld->incoming_slice));
+      exec_ctx, calld->send_op->payload->send_message.send_message, ~(size_t)0,
+      &calld->got_slice)) {
+    grpc_byte_stream_pull(exec_ctx,
+                          calld->send_op->payload->send_message.send_message,
+                          &calld->incoming_slice);
+    if (GRPC_SLICE_LENGTH(calld->incoming_slice) > 0) {
+      memcpy(wrptr, GRPC_SLICE_START_PTR(calld->incoming_slice),
+             GRPC_SLICE_LENGTH(calld->incoming_slice));
+    }
     wrptr += GRPC_SLICE_LENGTH(calld->incoming_slice);
     grpc_slice_buffer_add(&calld->slices, calld->incoming_slice);
     if (calld->send_length == calld->slices.length) {
@@ -237,6 +242,13 @@
   grpc_call_element *elem = elemp;
   call_data *calld = elem->call_data;
   calld->send_message_blocked = false;
+  if (GRPC_ERROR_NONE !=
+      grpc_byte_stream_pull(exec_ctx,
+                            calld->send_op->payload->send_message.send_message,
+                            &calld->incoming_slice)) {
+    /* Should never reach here */
+    abort();
+  }
   grpc_slice_buffer_add(&calld->slices, calld->incoming_slice);
   if (calld->send_length == calld->slices.length) {
     /* Pass down the original send_message op that was blocked.*/
@@ -311,7 +323,6 @@
         estimated_len += grpc_base64_estimate_encoded_size(
             op->payload->send_message.send_message->length, k_url_safe,
             k_multi_line);
-        estimated_len += 1; /* for the trailing 0 */
         grpc_slice path_with_query_slice = grpc_slice_malloc(estimated_len);
 
         /* memcopy individual pieces into this slice */
@@ -332,10 +343,8 @@
          */
         char *t = (char *)GRPC_SLICE_START_PTR(path_with_query_slice);
         /* safe to use strlen since base64_encode will always add '\0' */
-        size_t path_length = strlen(t) + 1;
-        *(t + path_length) = '\0';
         path_with_query_slice =
-            grpc_slice_sub(path_with_query_slice, 0, path_length);
+            grpc_slice_sub_no_ref(path_with_query_slice, 0, strlen(t));
 
         /* substitute previous path with the new path+query */
         grpc_mdelem mdelem_path_and_query = grpc_mdelem_from_slices(
@@ -349,7 +358,6 @@
         calld->on_complete = op->on_complete;
         op->on_complete = &calld->hc_on_complete;
         op->send_message = false;
-        grpc_slice_unref_internal(exec_ctx, path_with_query_slice);
       } else {
         /* Not all data is available. Fall back to POST. */
         gpr_log(GPR_DEBUG,
diff --git a/src/core/lib/channel/http_client_filter.h b/src/core/ext/filters/http/client/http_client_filter.h
similarity index 87%
rename from src/core/lib/channel/http_client_filter.h
rename to src/core/ext/filters/http/client/http_client_filter.h
index 9e6e106..6e1eb39 100644
--- a/src/core/lib/channel/http_client_filter.h
+++ b/src/core/ext/filters/http/client/http_client_filter.h
@@ -30,18 +30,15 @@
  *
  */
 
-#ifndef GRPC_CORE_LIB_CHANNEL_HTTP_CLIENT_FILTER_H
-#define GRPC_CORE_LIB_CHANNEL_HTTP_CLIENT_FILTER_H
+#ifndef GRPC_CORE_EXT_FILTERS_HTTP_CLIENT_HTTP_CLIENT_FILTER_H
+#define GRPC_CORE_EXT_FILTERS_HTTP_CLIENT_HTTP_CLIENT_FILTER_H
 
 #include "src/core/lib/channel/channel_stack.h"
 
 /* Processes metadata on the client side for HTTP2 transports */
 extern const grpc_channel_filter grpc_http_client_filter;
 
-/* Channel arg to override the http2 :scheme header */
-#define GRPC_ARG_HTTP2_SCHEME "grpc.http2_scheme"
-
 /* Channel arg to determine maximum size of payload eligable for GET request */
 #define GRPC_ARG_MAX_PAYLOAD_SIZE_FOR_GET "grpc.max_payload_size_for_get"
 
-#endif /* GRPC_CORE_LIB_CHANNEL_HTTP_CLIENT_FILTER_H */
+#endif /* GRPC_CORE_EXT_FILTERS_HTTP_CLIENT_HTTP_CLIENT_FILTER_H */
diff --git a/src/core/ext/filters/http/http_filters_plugin.c b/src/core/ext/filters/http/http_filters_plugin.c
new file mode 100644
index 0000000..195a1a8
--- /dev/null
+++ b/src/core/ext/filters/http/http_filters_plugin.c
@@ -0,0 +1,103 @@
+/*
+ *
+ * Copyright 2017, 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 "src/core/ext/filters/http/client/http_client_filter.h"
+#include "src/core/ext/filters/http/message_compress/message_compress_filter.h"
+#include "src/core/ext/filters/http/server/http_server_filter.h"
+#include "src/core/lib/channel/channel_stack_builder.h"
+#include "src/core/lib/surface/channel_init.h"
+#include "src/core/lib/transport/transport_impl.h"
+
+typedef struct {
+  const grpc_channel_filter *filter;
+  const char *control_channel_arg;
+} optional_filter;
+
+static optional_filter compress_filter = {
+    &grpc_message_compress_filter, GRPC_ARG_ENABLE_PER_MESSAGE_COMPRESSION};
+
+static bool is_building_http_like_transport(
+    grpc_channel_stack_builder *builder) {
+  grpc_transport *t = grpc_channel_stack_builder_get_transport(builder);
+  return t != NULL && strstr(t->vtable->name, "http");
+}
+
+static bool maybe_add_optional_filter(grpc_exec_ctx *exec_ctx,
+                                      grpc_channel_stack_builder *builder,
+                                      void *arg) {
+  if (!is_building_http_like_transport(builder)) return true;
+  optional_filter *filtarg = arg;
+  const grpc_channel_args *channel_args =
+      grpc_channel_stack_builder_get_channel_arguments(builder);
+  bool enable = grpc_channel_arg_get_bool(
+      grpc_channel_args_find(channel_args, filtarg->control_channel_arg),
+      !grpc_channel_args_want_minimal_stack(channel_args));
+  return enable ? grpc_channel_stack_builder_prepend_filter(
+                      builder, filtarg->filter, NULL, NULL)
+                : true;
+}
+
+static bool maybe_add_required_filter(grpc_exec_ctx *exec_ctx,
+                                      grpc_channel_stack_builder *builder,
+                                      void *arg) {
+  return is_building_http_like_transport(builder)
+             ? grpc_channel_stack_builder_prepend_filter(
+                   builder, (const grpc_channel_filter *)arg, NULL, NULL)
+             : true;
+}
+
+void grpc_http_filters_init(void) {
+  grpc_register_tracer("compression", &grpc_compression_trace);
+  grpc_channel_init_register_stage(GRPC_CLIENT_SUBCHANNEL,
+                                   GRPC_CHANNEL_INIT_BUILTIN_PRIORITY,
+                                   maybe_add_optional_filter, &compress_filter);
+  grpc_channel_init_register_stage(GRPC_CLIENT_DIRECT_CHANNEL,
+                                   GRPC_CHANNEL_INIT_BUILTIN_PRIORITY,
+                                   maybe_add_optional_filter, &compress_filter);
+  grpc_channel_init_register_stage(GRPC_SERVER_CHANNEL,
+                                   GRPC_CHANNEL_INIT_BUILTIN_PRIORITY,
+                                   maybe_add_optional_filter, &compress_filter);
+  grpc_channel_init_register_stage(
+      GRPC_CLIENT_SUBCHANNEL, GRPC_CHANNEL_INIT_BUILTIN_PRIORITY,
+      maybe_add_required_filter, (void *)&grpc_http_client_filter);
+  grpc_channel_init_register_stage(
+      GRPC_CLIENT_DIRECT_CHANNEL, GRPC_CHANNEL_INIT_BUILTIN_PRIORITY,
+      maybe_add_required_filter, (void *)&grpc_http_client_filter);
+  grpc_channel_init_register_stage(
+      GRPC_SERVER_CHANNEL, GRPC_CHANNEL_INIT_BUILTIN_PRIORITY,
+      maybe_add_required_filter, (void *)&grpc_http_server_filter);
+}
+
+void grpc_http_filters_shutdown(void) {}
diff --git a/src/core/lib/channel/compress_filter.c b/src/core/ext/filters/http/message_compress/message_compress_filter.c
similarity index 72%
rename from src/core/lib/channel/compress_filter.c
rename to src/core/ext/filters/http/message_compress/message_compress_filter.c
index 4625cba..f414a60 100644
--- a/src/core/lib/channel/compress_filter.c
+++ b/src/core/ext/filters/http/message_compress/message_compress_filter.c
@@ -39,8 +39,8 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 
+#include "src/core/ext/filters/http/message_compress/message_compress_filter.h"
 #include "src/core/lib/channel/channel_args.h"
-#include "src/core/lib/channel/compress_filter.h"
 #include "src/core/lib/compression/algorithm_metadata.h"
 #include "src/core/lib/compression/message_compress.h"
 #include "src/core/lib/profiling/timers.h"
@@ -51,6 +51,12 @@
 
 int grpc_compression_trace = 0;
 
+#define INITIAL_METADATA_UNSEEN 0
+#define HAS_COMPRESSION_ALGORITHM 2
+#define NO_COMPRESSION_ALGORITHM 4
+
+#define CANCELLED_BIT ((gpr_atm)1)
+
 typedef struct call_data {
   grpc_slice_buffer slices; /**< Buffers up input slices to be compressed */
   grpc_linked_mdelem compression_algorithm_storage;
@@ -59,8 +65,17 @@
   /** Compression algorithm we'll try to use. It may be given by incoming
    * metadata, or by the channel's default compression settings. */
   grpc_compression_algorithm compression_algorithm;
-  /** If true, contents of \a compression_algorithm are authoritative */
-  int has_compression_algorithm;
+
+  /* Atomic recording the state of initial metadata; allowed values:
+     INITIAL_METADATA_UNSEEN - initial metadata op not seen
+     HAS_COMPRESSION_ALGORITHM - initial metadata seen; compression algorithm
+                                 set
+     NO_COMPRESSION_ALGORITHM - initial metadata seen; no compression algorithm
+                                set
+     pointer - a stalled op containing a send_message that's waiting on initial
+               metadata
+     pointer | CANCELLED_BIT - request was cancelled with error pointed to */
+  gpr_atm send_initial_metadata_state;
 
   grpc_transport_stream_op_batch *send_op;
   uint32_t send_length;
@@ -81,14 +96,15 @@
   uint32_t supported_compression_algorithms;
 } channel_data;
 
-static int skip_compression(grpc_call_element *elem, uint32_t flags) {
+static bool skip_compression(grpc_call_element *elem, uint32_t flags,
+                             bool has_compression_algorithm) {
   call_data *calld = elem->call_data;
   channel_data *channeld = elem->channel_data;
 
   if (flags & (GRPC_WRITE_NO_COMPRESS | GRPC_WRITE_INTERNAL_COMPRESS)) {
     return 1;
   }
-  if (calld->has_compression_algorithm) {
+  if (has_compression_algorithm) {
     if (calld->compression_algorithm == GRPC_COMPRESS_NONE) {
       return 1;
     }
@@ -101,12 +117,14 @@
 /** Filter initial metadata */
 static grpc_error *process_send_initial_metadata(
     grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
-    grpc_metadata_batch *initial_metadata) GRPC_MUST_USE_RESULT;
+    grpc_metadata_batch *initial_metadata,
+    bool *has_compression_algorithm) GRPC_MUST_USE_RESULT;
 static grpc_error *process_send_initial_metadata(
     grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
-    grpc_metadata_batch *initial_metadata) {
+    grpc_metadata_batch *initial_metadata, bool *has_compression_algorithm) {
   call_data *calld = elem->call_data;
   channel_data *channeld = elem->channel_data;
+  *has_compression_algorithm = false;
   /* Parse incoming request for compression. If any, it'll be available
    * at calld->compression_algorithm */
   if (initial_metadata->idx.named.grpc_internal_encoding_request != NULL) {
@@ -130,7 +148,7 @@
       gpr_free(val);
       calld->compression_algorithm = GRPC_COMPRESS_NONE;
     }
-    calld->has_compression_algorithm = 1;
+    *has_compression_algorithm = true;
 
     grpc_metadata_batch_remove(
         exec_ctx, initial_metadata,
@@ -140,7 +158,7 @@
      * exceptionally skipping compression, fall back to the channel
      * default */
     calld->compression_algorithm = channeld->default_compression_algorithm;
-    calld->has_compression_algorithm = 1; /* GPR_TRUE */
+    *has_compression_algorithm = true;
   }
 
   grpc_error *error = GRPC_ERROR_NONE;
@@ -221,6 +239,13 @@
 static void got_slice(grpc_exec_ctx *exec_ctx, void *elemp, grpc_error *error) {
   grpc_call_element *elem = elemp;
   call_data *calld = elem->call_data;
+  if (GRPC_ERROR_NONE !=
+      grpc_byte_stream_pull(exec_ctx,
+                            calld->send_op->payload->send_message.send_message,
+                            &calld->incoming_slice)) {
+    /* Should never reach here */
+    abort();
+  }
   grpc_slice_buffer_add(&calld->slices, calld->incoming_slice);
   if (calld->send_length == calld->slices.length) {
     finish_send_message(exec_ctx, elem);
@@ -233,8 +258,11 @@
                                   grpc_call_element *elem) {
   call_data *calld = elem->call_data;
   while (grpc_byte_stream_next(
-      exec_ctx, calld->send_op->payload->send_message.send_message,
-      &calld->incoming_slice, ~(size_t)0, &calld->got_slice)) {
+      exec_ctx, calld->send_op->payload->send_message.send_message, ~(size_t)0,
+      &calld->got_slice)) {
+    grpc_byte_stream_pull(exec_ctx,
+                          calld->send_op->payload->send_message.send_message,
+                          &calld->incoming_slice);
     grpc_slice_buffer_add(&calld->slices, calld->incoming_slice);
     if (calld->send_length == calld->slices.length) {
       finish_send_message(exec_ctx, elem);
@@ -250,21 +278,89 @@
 
   GPR_TIMER_BEGIN("compress_start_transport_stream_op_batch", 0);
 
+  if (op->cancel_stream) {
+    gpr_atm cur;
+    GRPC_ERROR_REF(op->payload->cancel_stream.cancel_error);
+    do {
+      cur = gpr_atm_acq_load(&calld->send_initial_metadata_state);
+    } while (!gpr_atm_rel_cas(
+        &calld->send_initial_metadata_state, cur,
+        CANCELLED_BIT | (gpr_atm)op->payload->cancel_stream.cancel_error));
+    switch (cur) {
+      case HAS_COMPRESSION_ALGORITHM:
+      case NO_COMPRESSION_ALGORITHM:
+      case INITIAL_METADATA_UNSEEN:
+        break;
+      default:
+        if ((cur & CANCELLED_BIT) == 0) {
+          grpc_transport_stream_op_batch_finish_with_failure(
+              exec_ctx, (grpc_transport_stream_op_batch *)cur,
+              GRPC_ERROR_REF(op->payload->cancel_stream.cancel_error));
+        } else {
+          GRPC_ERROR_UNREF((grpc_error *)(cur & ~CANCELLED_BIT));
+        }
+        break;
+    }
+  }
+
   if (op->send_initial_metadata) {
+    bool has_compression_algorithm;
     grpc_error *error = process_send_initial_metadata(
         exec_ctx, elem,
-        op->payload->send_initial_metadata.send_initial_metadata);
+        op->payload->send_initial_metadata.send_initial_metadata,
+        &has_compression_algorithm);
     if (error != GRPC_ERROR_NONE) {
       grpc_transport_stream_op_batch_finish_with_failure(exec_ctx, op, error);
       return;
     }
+    gpr_atm cur = gpr_atm_acq_load(&calld->send_initial_metadata_state);
+    GPR_ASSERT(cur != HAS_COMPRESSION_ALGORITHM &&
+               cur != NO_COMPRESSION_ALGORITHM);
+    if ((cur & CANCELLED_BIT) == 0) {
+      gpr_atm_rel_store(&calld->send_initial_metadata_state,
+                        has_compression_algorithm ? HAS_COMPRESSION_ALGORITHM
+                                                  : NO_COMPRESSION_ALGORITHM);
+      if (cur != INITIAL_METADATA_UNSEEN) {
+        grpc_call_next_op(exec_ctx, elem,
+                          (grpc_transport_stream_op_batch *)cur);
+      }
+    }
   }
-  if (op->send_message &&
-      !skip_compression(elem, op->payload->send_message.send_message->flags)) {
-    calld->send_op = op;
-    calld->send_length = op->payload->send_message.send_message->length;
-    calld->send_flags = op->payload->send_message.send_message->flags;
-    continue_send_message(exec_ctx, elem);
+  if (op->send_message) {
+    gpr_atm cur;
+  retry_send:
+    cur = gpr_atm_acq_load(&calld->send_initial_metadata_state);
+    switch (cur) {
+      case INITIAL_METADATA_UNSEEN:
+        if (!gpr_atm_rel_cas(&calld->send_initial_metadata_state, cur,
+                             (gpr_atm)op)) {
+          goto retry_send;
+        }
+        break;
+      case HAS_COMPRESSION_ALGORITHM:
+      case NO_COMPRESSION_ALGORITHM:
+        if (!skip_compression(elem,
+                              op->payload->send_message.send_message->flags,
+                              cur == HAS_COMPRESSION_ALGORITHM)) {
+          calld->send_op = op;
+          calld->send_length = op->payload->send_message.send_message->length;
+          calld->send_flags = op->payload->send_message.send_message->flags;
+          continue_send_message(exec_ctx, elem);
+        } else {
+          /* pass control down the stack */
+          grpc_call_next_op(exec_ctx, elem, op);
+        }
+        break;
+      default:
+        if (cur & CANCELLED_BIT) {
+          grpc_transport_stream_op_batch_finish_with_failure(
+              exec_ctx, op,
+              GRPC_ERROR_REF((grpc_error *)(cur & ~CANCELLED_BIT)));
+        } else {
+          /* >1 send_message concurrently */
+          GPR_UNREACHABLE_CODE(break);
+        }
+    }
   } else {
     /* pass control down the stack */
     grpc_call_next_op(exec_ctx, elem, op);
@@ -282,7 +378,6 @@
 
   /* initialize members */
   grpc_slice_buffer_init(&calld->slices);
-  calld->has_compression_algorithm = 0;
   grpc_closure_init(&calld->got_slice, got_slice, elem,
                     grpc_schedule_on_exec_ctx);
   grpc_closure_init(&calld->send_done, send_done, elem,
@@ -298,6 +393,11 @@
   /* grab pointers to our data from the call element */
   call_data *calld = elem->call_data;
   grpc_slice_buffer_destroy_internal(exec_ctx, &calld->slices);
+  gpr_atm imstate =
+      gpr_atm_no_barrier_load(&calld->send_initial_metadata_state);
+  if (imstate & CANCELLED_BIT) {
+    GRPC_ERROR_UNREF((grpc_error *)(imstate & ~CANCELLED_BIT));
+  }
 }
 
 /* Constructor for channel_data */
@@ -338,7 +438,7 @@
 static void destroy_channel_elem(grpc_exec_ctx *exec_ctx,
                                  grpc_channel_element *elem) {}
 
-const grpc_channel_filter grpc_compress_filter = {
+const grpc_channel_filter grpc_message_compress_filter = {
     compress_start_transport_stream_op_batch,
     grpc_channel_next_op,
     sizeof(call_data),
diff --git a/src/core/lib/channel/compress_filter.h b/src/core/ext/filters/http/message_compress/message_compress_filter.h
similarity index 89%
rename from src/core/lib/channel/compress_filter.h
rename to src/core/ext/filters/http/message_compress/message_compress_filter.h
index e4a2a82..75bfa17 100644
--- a/src/core/lib/channel/compress_filter.h
+++ b/src/core/ext/filters/http/message_compress/message_compress_filter.h
@@ -31,8 +31,8 @@
  *
  */
 
-#ifndef GRPC_CORE_LIB_CHANNEL_COMPRESS_FILTER_H
-#define GRPC_CORE_LIB_CHANNEL_COMPRESS_FILTER_H
+#ifndef GRPC_CORE_EXT_FILTERS_HTTP_MESSAGE_COMPRESS_MESSAGE_COMPRESS_FILTER_H
+#define GRPC_CORE_EXT_FILTERS_HTTP_MESSAGE_COMPRESS_MESSAGE_COMPRESS_FILTER_H
 
 #include <grpc/impl/codegen/compression_types.h>
 
@@ -62,6 +62,7 @@
  * aforementioned 'grpc-encoding' metadata value, data will pass through
  * uncompressed. */
 
-extern const grpc_channel_filter grpc_compress_filter;
+extern const grpc_channel_filter grpc_message_compress_filter;
 
-#endif /* GRPC_CORE_LIB_CHANNEL_COMPRESS_FILTER_H */
+#endif /* GRPC_CORE_EXT_FILTERS_HTTP_MESSAGE_COMPRESS_MESSAGE_COMPRESS_FILTER_H \
+          */
diff --git a/src/core/lib/channel/http_server_filter.c b/src/core/ext/filters/http/server/http_server_filter.c
similarity index 98%
rename from src/core/lib/channel/http_server_filter.c
rename to src/core/ext/filters/http/server/http_server_filter.c
index c1e49ff..ff85787 100644
--- a/src/core/lib/channel/http_server_filter.c
+++ b/src/core/ext/filters/http/server/http_server_filter.c
@@ -31,7 +31,7 @@
  *
  */
 
-#include "src/core/lib/channel/http_server_filter.h"
+#include "src/core/ext/filters/http/server/http_server_filter.h"
 
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
@@ -240,9 +240,9 @@
       const int k_url_safe = 1;
       grpc_slice_buffer_add(
           &calld->read_slice_buffer,
-          grpc_base64_decode(exec_ctx,
-                             (const char *)GRPC_SLICE_START_PTR(query_slice),
-                             k_url_safe));
+          grpc_base64_decode_with_len(
+              exec_ctx, (const char *)GRPC_SLICE_START_PTR(query_slice),
+              GRPC_SLICE_LENGTH(query_slice), k_url_safe));
       grpc_slice_buffer_stream_init(&calld->read_stream,
                                     &calld->read_slice_buffer, 0);
       calld->seen_path_with_query = true;
diff --git a/src/core/lib/channel/http_server_filter.h b/src/core/ext/filters/http/server/http_server_filter.h
similarity index 89%
rename from src/core/lib/channel/http_server_filter.h
rename to src/core/ext/filters/http/server/http_server_filter.h
index 77ba2d2..8a2b219 100644
--- a/src/core/lib/channel/http_server_filter.h
+++ b/src/core/ext/filters/http/server/http_server_filter.h
@@ -31,12 +31,12 @@
  *
  */
 
-#ifndef GRPC_CORE_LIB_CHANNEL_HTTP_SERVER_FILTER_H
-#define GRPC_CORE_LIB_CHANNEL_HTTP_SERVER_FILTER_H
+#ifndef GRPC_CORE_EXT_FILTERS_HTTP_SERVER_HTTP_SERVER_FILTER_H
+#define GRPC_CORE_EXT_FILTERS_HTTP_SERVER_HTTP_SERVER_FILTER_H
 
 #include "src/core/lib/channel/channel_stack.h"
 
 /* Processes metadata on the client side for HTTP2 transports */
 extern const grpc_channel_filter grpc_http_server_filter;
 
-#endif /* GRPC_CORE_LIB_CHANNEL_HTTP_SERVER_FILTER_H */
+#endif /* GRPC_CORE_EXT_FILTERS_HTTP_SERVER_HTTP_SERVER_FILTER_H */
diff --git a/src/core/ext/filters/load_reporting/load_reporting.c b/src/core/ext/filters/load_reporting/load_reporting.c
index f4dac15..4e9d093 100644
--- a/src/core/ext/filters/load_reporting/load_reporting.c
+++ b/src/core/ext/filters/load_reporting/load_reporting.c
@@ -47,32 +47,9 @@
 #include "src/core/lib/surface/call.h"
 #include "src/core/lib/surface/channel_init.h"
 
-static void destroy_lr_cost_context(void *c) {
-  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-  grpc_load_reporting_cost_context *cost_ctx = c;
-  for (size_t i = 0; i < cost_ctx->values_count; ++i) {
-    grpc_slice_unref_internal(&exec_ctx, cost_ctx->values[i]);
-  }
-  grpc_exec_ctx_finish(&exec_ctx);
-  gpr_free(cost_ctx->values);
-  gpr_free(cost_ctx);
-}
-
-void grpc_call_set_load_reporting_cost_context(
-    grpc_call *call, grpc_load_reporting_cost_context *ctx) {
-  grpc_call_context_set(call, GRPC_CONTEXT_LR_COST, ctx,
-                        destroy_lr_cost_context);
-}
-
 static bool is_load_reporting_enabled(const grpc_channel_args *a) {
-  if (a == NULL) return false;
-  for (size_t i = 0; i < a->num_args; i++) {
-    if (0 == strcmp(a->args[i].key, GRPC_ARG_ENABLE_LOAD_REPORTING)) {
-      return a->args[i].type == GRPC_ARG_INTEGER &&
-             a->args[i].value.integer != 0;
-    }
-  }
-  return false;
+  return grpc_channel_arg_get_bool(
+      grpc_channel_args_find(a, GRPC_ARG_ENABLE_LOAD_REPORTING), false);
 }
 
 static bool maybe_add_load_reporting_filter(grpc_exec_ctx *exec_ctx,
diff --git a/src/core/ext/filters/load_reporting/load_reporting_filter.c b/src/core/ext/filters/load_reporting/load_reporting_filter.c
index 57b25d0..75a9a56 100644
--- a/src/core/ext/filters/load_reporting/load_reporting_filter.c
+++ b/src/core/ext/filters/load_reporting/load_reporting_filter.c
@@ -48,6 +48,8 @@
 
 typedef struct call_data {
   intptr_t id; /**< an id unique to the call */
+  bool have_trailing_md_string;
+  grpc_slice trailing_md_string;
   bool have_initial_md_string;
   grpc_slice initial_md_string;
   bool have_service_method;
@@ -140,6 +142,9 @@
   if (calld->have_initial_md_string) {
     grpc_slice_unref_internal(exec_ctx, calld->initial_md_string);
   }
+  if (calld->have_trailing_md_string) {
+    grpc_slice_unref_internal(exec_ctx, calld->trailing_md_string);
+  }
   if (calld->have_service_method) {
     grpc_slice_unref_internal(exec_ctx, calld->service_method);
   }
@@ -183,6 +188,18 @@
   */
 }
 
+static grpc_filtered_mdelem lr_trailing_md_filter(grpc_exec_ctx *exec_ctx,
+                                                  void *user_data,
+                                                  grpc_mdelem md) {
+  grpc_call_element *elem = user_data;
+  call_data *calld = elem->call_data;
+  if (grpc_slice_eq(GRPC_MDKEY(md), GRPC_MDSTR_LB_COST_BIN)) {
+    calld->trailing_md_string = GRPC_MDVALUE(md);
+    return GRPC_FILTERED_REMOVE();
+  }
+  return GRPC_FILTERED_MDELEM(md);
+}
+
 static void lr_start_transport_stream_op_batch(
     grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
     grpc_transport_stream_op_batch *op) {
@@ -190,13 +207,21 @@
   call_data *calld = elem->call_data;
 
   if (op->recv_initial_metadata) {
+    /* substitute our callback for the higher callback */
     calld->recv_initial_metadata =
         op->payload->recv_initial_metadata.recv_initial_metadata;
-    /* substitute our callback for the higher callback */
     calld->ops_recv_initial_metadata_ready =
         op->payload->recv_initial_metadata.recv_initial_metadata_ready;
     op->payload->recv_initial_metadata.recv_initial_metadata_ready =
         &calld->on_initial_md_ready;
+  } else if (op->send_trailing_metadata) {
+    GRPC_LOG_IF_ERROR(
+        "grpc_metadata_batch_filter",
+        grpc_metadata_batch_filter(
+            exec_ctx,
+            op->payload->send_trailing_metadata.send_trailing_metadata,
+            lr_trailing_md_filter, elem,
+            "LR trailing metadata filtering error"));
   }
   grpc_call_next_op(exec_ctx, elem, op);
 
diff --git a/src/core/ext/filters/max_age/max_age_filter.c b/src/core/ext/filters/max_age/max_age_filter.c
index b9fde36..a9d91e2 100644
--- a/src/core/ext/filters/max_age/max_age_filter.c
+++ b/src/core/ext/filters/max_age/max_age_filter.c
@@ -47,6 +47,11 @@
 #define DEFAULT_MAX_CONNECTION_IDLE_MS INT_MAX
 #define MAX_CONNECTION_AGE_JITTER 0.1
 
+#define MAX_CONNECTION_AGE_INTEGER_OPTIONS \
+  (grpc_integer_options) { DEFAULT_MAX_CONNECTION_AGE_MS, 1, INT_MAX }
+#define MAX_CONNECTION_IDLE_INTEGER_OPTIONS \
+  (grpc_integer_options) { DEFAULT_MAX_CONNECTION_IDLE_MS, 1, INT_MAX }
+
 typedef struct channel_data {
   /* We take a reference to the channel stack for the timer callback */
   grpc_channel_stack* channel_stack;
@@ -315,8 +320,7 @@
     if (0 == strcmp(args->channel_args->args[i].key,
                     GRPC_ARG_MAX_CONNECTION_AGE_MS)) {
       const int value = grpc_channel_arg_get_integer(
-          &args->channel_args->args[i],
-          (grpc_integer_options){DEFAULT_MAX_CONNECTION_AGE_MS, 1, INT_MAX});
+          &args->channel_args->args[i], MAX_CONNECTION_AGE_INTEGER_OPTIONS);
       chand->max_connection_age =
           value == INT_MAX
               ? gpr_inf_future(GPR_TIMESPAN)
@@ -334,8 +338,7 @@
     } else if (0 == strcmp(args->channel_args->args[i].key,
                            GRPC_ARG_MAX_CONNECTION_IDLE_MS)) {
       const int value = grpc_channel_arg_get_integer(
-          &args->channel_args->args[i],
-          (grpc_integer_options){DEFAULT_MAX_CONNECTION_IDLE_MS, 1, INT_MAX});
+          &args->channel_args->args[i], MAX_CONNECTION_IDLE_INTEGER_OPTIONS);
       chand->max_connection_idle =
           value == INT_MAX ? gpr_inf_future(GPR_TIMESPAN)
                            : gpr_time_from_millis(value, GPR_TIMESPAN);
@@ -412,16 +415,13 @@
                                      void* arg) {
   const grpc_channel_args* channel_args =
       grpc_channel_stack_builder_get_channel_arguments(builder);
-  const grpc_arg* a =
-      grpc_channel_args_find(channel_args, GRPC_ARG_MAX_CONNECTION_AGE_MS);
-  bool enable = false;
-  if (a != NULL && a->type == GRPC_ARG_INTEGER && a->value.integer != INT_MAX) {
-    enable = true;
-  }
-  a = grpc_channel_args_find(channel_args, GRPC_ARG_MAX_CONNECTION_IDLE_MS);
-  if (a != NULL && a->type == GRPC_ARG_INTEGER && a->value.integer != INT_MAX) {
-    enable = true;
-  }
+  bool enable =
+      grpc_channel_arg_get_integer(
+          grpc_channel_args_find(channel_args, GRPC_ARG_MAX_CONNECTION_AGE_MS),
+          MAX_CONNECTION_AGE_INTEGER_OPTIONS) != INT_MAX &&
+      grpc_channel_arg_get_integer(
+          grpc_channel_args_find(channel_args, GRPC_ARG_MAX_CONNECTION_IDLE_MS),
+          MAX_CONNECTION_IDLE_INTEGER_OPTIONS) != INT_MAX;
   if (enable) {
     return grpc_channel_stack_builder_prepend_filter(
         builder, &grpc_max_age_filter, NULL, NULL);
diff --git a/src/core/lib/channel/message_size_filter.c b/src/core/ext/filters/message_size/message_size_filter.c
similarity index 70%
rename from src/core/lib/channel/message_size_filter.c
rename to src/core/ext/filters/message_size/message_size_filter.c
index 57726c8..db0f011 100644
--- a/src/core/lib/channel/message_size_filter.c
+++ b/src/core/ext/filters/message_size/message_size_filter.c
@@ -29,7 +29,7 @@
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 //
 
-#include "src/core/lib/channel/message_size_filter.h"
+#include "src/core/ext/filters/message_size/message_size_filter.h"
 
 #include <limits.h>
 #include <string.h>
@@ -40,7 +40,9 @@
 #include <grpc/support/string_util.h>
 
 #include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/channel/channel_stack_builder.h"
 #include "src/core/lib/support/string.h"
+#include "src/core/lib/surface/channel_init.h"
 #include "src/core/lib/transport/service_config.h"
 
 typedef struct message_size_limits {
@@ -89,8 +91,7 @@
 }
 
 typedef struct call_data {
-  int max_send_size;
-  int max_recv_size;
+  message_size_limits limits;
   // Receive closures are chained: we inject this closure as the
   // recv_message_ready up-call on transport_stream_op, and remember to
   // call our next_recv_message_ready member after handling it.
@@ -102,8 +103,7 @@
 } call_data;
 
 typedef struct channel_data {
-  int max_send_size;
-  int max_recv_size;
+  message_size_limits limits;
   // Maps path names to message_size_limits structs.
   grpc_slice_hash_table* method_limit_table;
 } channel_data;
@@ -114,15 +114,15 @@
                                grpc_error* error) {
   grpc_call_element* elem = user_data;
   call_data* calld = elem->call_data;
-  if (*calld->recv_message != NULL && calld->max_recv_size >= 0 &&
-      (*calld->recv_message)->length > (size_t)calld->max_recv_size) {
+  if (*calld->recv_message != NULL && calld->limits.max_recv_size >= 0 &&
+      (*calld->recv_message)->length > (size_t)calld->limits.max_recv_size) {
     char* message_string;
     gpr_asprintf(&message_string,
                  "Received message larger than max (%u vs. %d)",
-                 (*calld->recv_message)->length, calld->max_recv_size);
+                 (*calld->recv_message)->length, calld->limits.max_recv_size);
     grpc_error* new_error = grpc_error_set_int(
         GRPC_ERROR_CREATE_FROM_COPIED_STRING(message_string),
-        GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_INVALID_ARGUMENT);
+        GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_RESOURCE_EXHAUSTED);
     if (error == GRPC_ERROR_NONE) {
       error = new_error;
     } else {
@@ -141,18 +141,18 @@
     grpc_transport_stream_op_batch* op) {
   call_data* calld = elem->call_data;
   // Check max send message size.
-  if (op->send_message && calld->max_send_size >= 0 &&
+  if (op->send_message && calld->limits.max_send_size >= 0 &&
       op->payload->send_message.send_message->length >
-          (size_t)calld->max_send_size) {
+          (size_t)calld->limits.max_send_size) {
     char* message_string;
     gpr_asprintf(&message_string, "Sent message larger than max (%u vs. %d)",
                  op->payload->send_message.send_message->length,
-                 calld->max_send_size);
+                 calld->limits.max_send_size);
     grpc_transport_stream_op_batch_finish_with_failure(
         exec_ctx, op,
         grpc_error_set_int(GRPC_ERROR_CREATE_FROM_COPIED_STRING(message_string),
                            GRPC_ERROR_INT_GRPC_STATUS,
-                           GRPC_STATUS_INVALID_ARGUMENT));
+                           GRPC_STATUS_RESOURCE_EXHAUSTED));
     gpr_free(message_string);
     return;
   }
@@ -180,21 +180,20 @@
   // Note: Per-method config is only available on the client, so we
   // apply the max request size to the send limit and the max response
   // size to the receive limit.
-  calld->max_send_size = chand->max_send_size;
-  calld->max_recv_size = chand->max_recv_size;
+  calld->limits = chand->limits;
   if (chand->method_limit_table != NULL) {
     message_size_limits* limits = grpc_method_config_table_get(
         exec_ctx, chand->method_limit_table, args->path);
     if (limits != NULL) {
       if (limits->max_send_size >= 0 &&
-          (limits->max_send_size < calld->max_send_size ||
-           calld->max_send_size < 0)) {
-        calld->max_send_size = limits->max_send_size;
+          (limits->max_send_size < calld->limits.max_send_size ||
+           calld->limits.max_send_size < 0)) {
+        calld->limits.max_send_size = limits->max_send_size;
       }
       if (limits->max_recv_size >= 0 &&
-          (limits->max_recv_size < calld->max_recv_size ||
-           calld->max_recv_size < 0)) {
-        calld->max_recv_size = limits->max_recv_size;
+          (limits->max_recv_size < calld->limits.max_recv_size ||
+           calld->limits.max_recv_size < 0)) {
+        calld->limits.max_recv_size = limits->max_recv_size;
       }
     }
   }
@@ -206,30 +205,45 @@
                               const grpc_call_final_info* final_info,
                               grpc_closure* ignored) {}
 
+static int default_size(const grpc_channel_args* args,
+                        int without_minimal_stack) {
+  if (grpc_channel_args_want_minimal_stack(args)) {
+    return -1;
+  }
+  return without_minimal_stack;
+}
+
+message_size_limits get_message_size_limits(
+    const grpc_channel_args* channel_args) {
+  message_size_limits lim;
+  lim.max_send_size =
+      default_size(channel_args, GRPC_DEFAULT_MAX_SEND_MESSAGE_LENGTH);
+  lim.max_recv_size =
+      default_size(channel_args, GRPC_DEFAULT_MAX_RECV_MESSAGE_LENGTH);
+  for (size_t i = 0; i < channel_args->num_args; ++i) {
+    if (strcmp(channel_args->args[i].key, GRPC_ARG_MAX_SEND_MESSAGE_LENGTH) ==
+        0) {
+      const grpc_integer_options options = {lim.max_send_size, -1, INT_MAX};
+      lim.max_send_size =
+          grpc_channel_arg_get_integer(&channel_args->args[i], options);
+    }
+    if (strcmp(channel_args->args[i].key,
+               GRPC_ARG_MAX_RECEIVE_MESSAGE_LENGTH) == 0) {
+      const grpc_integer_options options = {lim.max_recv_size, -1, INT_MAX};
+      lim.max_recv_size =
+          grpc_channel_arg_get_integer(&channel_args->args[i], options);
+    }
+  }
+  return lim;
+}
+
 // Constructor for channel_data.
 static grpc_error* init_channel_elem(grpc_exec_ctx* exec_ctx,
                                      grpc_channel_element* elem,
                                      grpc_channel_element_args* args) {
   GPR_ASSERT(!args->is_last);
   channel_data* chand = elem->channel_data;
-  chand->max_send_size = GRPC_DEFAULT_MAX_SEND_MESSAGE_LENGTH;
-  chand->max_recv_size = GRPC_DEFAULT_MAX_RECV_MESSAGE_LENGTH;
-  for (size_t i = 0; i < args->channel_args->num_args; ++i) {
-    if (strcmp(args->channel_args->args[i].key,
-               GRPC_ARG_MAX_SEND_MESSAGE_LENGTH) == 0) {
-      const grpc_integer_options options = {
-          GRPC_DEFAULT_MAX_SEND_MESSAGE_LENGTH, 0, INT_MAX};
-      chand->max_send_size =
-          grpc_channel_arg_get_integer(&args->channel_args->args[i], options);
-    }
-    if (strcmp(args->channel_args->args[i].key,
-               GRPC_ARG_MAX_RECEIVE_MESSAGE_LENGTH) == 0) {
-      const grpc_integer_options options = {
-          GRPC_DEFAULT_MAX_RECV_MESSAGE_LENGTH, 0, INT_MAX};
-      chand->max_recv_size =
-          grpc_channel_arg_get_integer(&args->channel_args->args[i], options);
-    }
-  }
+  chand->limits = get_message_size_limits(args->channel_args);
   // Get method config table from channel args.
   const grpc_arg* channel_arg =
       grpc_channel_args_find(args->channel_args, GRPC_ARG_SERVICE_CONFIG);
@@ -268,3 +282,40 @@
     grpc_call_next_get_peer,
     grpc_channel_next_get_info,
     "message_size"};
+
+static bool maybe_add_message_size_filter(grpc_exec_ctx* exec_ctx,
+                                          grpc_channel_stack_builder* builder,
+                                          void* arg) {
+  const grpc_channel_args* channel_args =
+      grpc_channel_stack_builder_get_channel_arguments(builder);
+  bool enable = false;
+  message_size_limits lim = get_message_size_limits(channel_args);
+  if (lim.max_send_size != -1 || lim.max_recv_size != -1) {
+    enable = true;
+  }
+  const grpc_arg* a =
+      grpc_channel_args_find(channel_args, GRPC_ARG_SERVICE_CONFIG);
+  if (a != NULL) {
+    enable = true;
+  }
+  if (enable) {
+    return grpc_channel_stack_builder_prepend_filter(
+        builder, &grpc_message_size_filter, NULL, NULL);
+  } else {
+    return true;
+  }
+}
+
+void grpc_message_size_filter_init(void) {
+  grpc_channel_init_register_stage(GRPC_CLIENT_SUBCHANNEL,
+                                   GRPC_CHANNEL_INIT_BUILTIN_PRIORITY,
+                                   maybe_add_message_size_filter, NULL);
+  grpc_channel_init_register_stage(GRPC_CLIENT_DIRECT_CHANNEL,
+                                   GRPC_CHANNEL_INIT_BUILTIN_PRIORITY,
+                                   maybe_add_message_size_filter, NULL);
+  grpc_channel_init_register_stage(GRPC_SERVER_CHANNEL,
+                                   GRPC_CHANNEL_INIT_BUILTIN_PRIORITY,
+                                   maybe_add_message_size_filter, NULL);
+}
+
+void grpc_message_size_filter_shutdown(void) {}
diff --git a/src/core/lib/channel/message_size_filter.h b/src/core/ext/filters/message_size/message_size_filter.h
similarity index 88%
rename from src/core/lib/channel/message_size_filter.h
rename to src/core/ext/filters/message_size/message_size_filter.h
index a88ff7f..83980e7 100644
--- a/src/core/lib/channel/message_size_filter.h
+++ b/src/core/ext/filters/message_size/message_size_filter.h
@@ -29,11 +29,11 @@
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 //
 
-#ifndef GRPC_CORE_LIB_CHANNEL_MESSAGE_SIZE_FILTER_H
-#define GRPC_CORE_LIB_CHANNEL_MESSAGE_SIZE_FILTER_H
+#ifndef GRPC_CORE_EXT_FILTERS_MESSAGE_SIZE_MESSAGE_SIZE_FILTER_H
+#define GRPC_CORE_EXT_FILTERS_MESSAGE_SIZE_MESSAGE_SIZE_FILTER_H
 
 #include "src/core/lib/channel/channel_stack.h"
 
 extern const grpc_channel_filter grpc_message_size_filter;
 
-#endif /* GRPC_CORE_LIB_CHANNEL_MESSAGE_SIZE_FILTER_H */
+#endif /* GRPC_CORE_EXT_FILTERS_MESSAGE_SIZE_MESSAGE_SIZE_FILTER_H */
diff --git a/src/core/ext/transport/chttp2/server/chttp2_server.c b/src/core/ext/transport/chttp2/server/chttp2_server.c
index 6433968..b463506 100644
--- a/src/core/ext/transport/chttp2/server/chttp2_server.c
+++ b/src/core/ext/transport/chttp2/server/chttp2_server.c
@@ -43,11 +43,11 @@
 #include <grpc/support/sync.h>
 #include <grpc/support/useful.h>
 
+#include "src/core/ext/filters/http/server/http_server_filter.h"
 #include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/channel/handshaker.h"
 #include "src/core/lib/channel/handshaker_registry.h"
-#include "src/core/lib/channel/http_server_filter.h"
 #include "src/core/lib/iomgr/endpoint.h"
 #include "src/core/lib/iomgr/resolve_address.h"
 #include "src/core/lib/iomgr/tcp_server.h"
diff --git a/src/core/ext/transport/chttp2/transport/chttp2_transport.c b/src/core/ext/transport/chttp2/transport/chttp2_transport.c
index e2816b0..9269611 100644
--- a/src/core/ext/transport/chttp2/transport/chttp2_transport.c
+++ b/src/core/ext/transport/chttp2/transport/chttp2_transport.c
@@ -44,6 +44,7 @@
 #include <grpc/support/string_util.h>
 #include <grpc/support/useful.h>
 
+#include "src/core/ext/transport/chttp2/transport/frame_data.h"
 #include "src/core/ext/transport/chttp2/transport/internal.h"
 #include "src/core/ext/transport/chttp2/transport/varint.h"
 #include "src/core/lib/channel/channel_args.h"
@@ -129,6 +130,11 @@
 static void incoming_byte_stream_destroy_locked(grpc_exec_ctx *exec_ctx,
                                                 void *byte_stream,
                                                 grpc_error *error_ignored);
+static void incoming_byte_stream_publish_error(
+    grpc_exec_ctx *exec_ctx, grpc_chttp2_incoming_byte_stream *bs,
+    grpc_error *error);
+static void incoming_byte_stream_unref(grpc_exec_ctx *exec_ctx,
+                                       grpc_chttp2_incoming_byte_stream *bs);
 
 static void benign_reclaimer_locked(grpc_exec_ctx *exec_ctx, void *t,
                                     grpc_error *error);
@@ -174,6 +180,9 @@
 static void keepalive_watchdog_fired_locked(grpc_exec_ctx *exec_ctx, void *arg,
                                             grpc_error *error);
 
+static void reset_byte_stream(grpc_exec_ctx *exec_ctx, void *arg,
+                              grpc_error *error);
+
 /*******************************************************************************
  * CONSTRUCTION/DESTRUCTION/REFCOUNTING
  */
@@ -356,6 +365,8 @@
                DEFAULT_WINDOW);
   push_setting(exec_ctx, t, GRPC_CHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE,
                DEFAULT_MAX_HEADER_LIST_SIZE);
+  push_setting(exec_ctx, t,
+               GRPC_CHTTP2_SETTINGS_GRPC_ALLOW_TRUE_BINARY_METADATA, 1);
 
   t->ping_policy = (grpc_chttp2_repeated_ping_policy){
       .max_pings_without_data = DEFAULT_MAX_PINGS_BETWEEN_DATA,
@@ -486,26 +497,31 @@
           grpc_chttp2_setting_id setting_id;
           grpc_integer_options integer_options;
           bool availability[2] /* server, client */;
-        } settings_map[] = {{GRPC_ARG_MAX_CONCURRENT_STREAMS,
-                             GRPC_CHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS,
-                             {-1, 0, INT32_MAX},
-                             {true, false}},
-                            {GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_DECODER,
-                             GRPC_CHTTP2_SETTINGS_HEADER_TABLE_SIZE,
-                             {-1, 0, INT32_MAX},
-                             {true, true}},
-                            {GRPC_ARG_MAX_METADATA_SIZE,
-                             GRPC_CHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE,
-                             {-1, 0, INT32_MAX},
-                             {true, true}},
-                            {GRPC_ARG_HTTP2_MAX_FRAME_SIZE,
-                             GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE,
-                             {-1, 16384, 16777215},
-                             {true, true}},
-                            {GRPC_ARG_HTTP2_STREAM_LOOKAHEAD_BYTES,
-                             GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE,
-                             {-1, 5, INT32_MAX},
-                             {true, true}}};
+        } settings_map[] = {
+            {GRPC_ARG_MAX_CONCURRENT_STREAMS,
+             GRPC_CHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS,
+             {-1, 0, INT32_MAX},
+             {true, false}},
+            {GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_DECODER,
+             GRPC_CHTTP2_SETTINGS_HEADER_TABLE_SIZE,
+             {-1, 0, INT32_MAX},
+             {true, true}},
+            {GRPC_ARG_MAX_METADATA_SIZE,
+             GRPC_CHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE,
+             {-1, 0, INT32_MAX},
+             {true, true}},
+            {GRPC_ARG_HTTP2_MAX_FRAME_SIZE,
+             GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE,
+             {-1, 16384, 16777215},
+             {true, true}},
+            {GRPC_ARG_HTTP2_ENABLE_TRUE_BINARY,
+             GRPC_CHTTP2_SETTINGS_GRPC_ALLOW_TRUE_BINARY_METADATA,
+             {1, 0, 1},
+             {true, true}},
+            {GRPC_ARG_HTTP2_STREAM_LOOKAHEAD_BYTES,
+             GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE,
+             {-1, 5, INT32_MAX},
+             {true, true}}};
         for (j = 0; j < (int)GPR_ARRAY_SIZE(settings_map); j++) {
           if (0 == strcmp(channel_args->args[i].key,
                           settings_map[j].channel_arg_name)) {
@@ -543,6 +559,10 @@
         exec_ctx, &t->keepalive_ping_timer,
         gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC), t->keepalive_time),
         &t->init_keepalive_ping_locked, gpr_now(GPR_CLOCK_MONOTONIC));
+  } else {
+    /* Use GRPC_CHTTP2_KEEPALIVE_STATE_DISABLED to indicate there are no
+       inflight keeaplive timers */
+    t->keepalive_state = GRPC_CHTTP2_KEEPALIVE_STATE_DISABLED;
   }
 
   grpc_chttp2_initiate_write(exec_ctx, t, false, "init");
@@ -591,21 +611,18 @@
     connectivity_state_set(exec_ctx, t, GRPC_CHANNEL_SHUTDOWN,
                            GRPC_ERROR_REF(error), "close_transport");
     grpc_endpoint_shutdown(exec_ctx, t->ep, GRPC_ERROR_REF(error));
-    if (t->is_client) {
-      switch (t->keepalive_state) {
-        case GRPC_CHTTP2_KEEPALIVE_STATE_WAITING: {
-          grpc_timer_cancel(exec_ctx, &t->keepalive_ping_timer);
-          break;
-        }
-        case GRPC_CHTTP2_KEEPALIVE_STATE_PINGING: {
-          grpc_timer_cancel(exec_ctx, &t->keepalive_ping_timer);
-          grpc_timer_cancel(exec_ctx, &t->keepalive_watchdog_timer);
-          break;
-        }
-        case GRPC_CHTTP2_KEEPALIVE_STATE_DYING: {
-          break;
-        }
-      }
+    switch (t->keepalive_state) {
+      case GRPC_CHTTP2_KEEPALIVE_STATE_WAITING:
+        grpc_timer_cancel(exec_ctx, &t->keepalive_ping_timer);
+        break;
+      case GRPC_CHTTP2_KEEPALIVE_STATE_PINGING:
+        grpc_timer_cancel(exec_ctx, &t->keepalive_ping_timer);
+        grpc_timer_cancel(exec_ctx, &t->keepalive_watchdog_timer);
+        break;
+      case GRPC_CHTTP2_KEEPALIVE_STATE_DYING:
+      case GRPC_CHTTP2_KEEPALIVE_STATE_DISABLED:
+        /* keepalive timers are not set in these two states */
+        break;
     }
 
     /* flush writable stream list to avoid dangling references */
@@ -648,7 +665,6 @@
   /* We reserve one 'active stream' that's dropped when the stream is
      read-closed. The others are for incoming_byte_streams that are actively
      reading */
-  gpr_ref_init(&s->active_streams, 1);
   GRPC_CHTTP2_STREAM_REF(s, "chttp2");
 
   grpc_chttp2_incoming_metadata_buffer_init(&s->metadata_buffer[0], arena);
@@ -658,6 +674,11 @@
   s->deadline = gpr_inf_future(GPR_CLOCK_MONOTONIC);
   grpc_closure_init(&s->complete_fetch_locked, complete_fetch_locked, s,
                     grpc_schedule_on_exec_ctx);
+  grpc_slice_buffer_init(&s->unprocessed_incoming_frames_buffer);
+  grpc_slice_buffer_init(&s->frame_storage);
+  s->pending_byte_stream = false;
+  grpc_closure_init(&s->reset_byte_stream, reset_byte_stream, s,
+                    grpc_combiner_scheduler(t->combiner, false));
 
   GRPC_CHTTP2_REF_TRANSPORT(t, "stream");
 
@@ -675,7 +696,6 @@
 
 static void destroy_stream_locked(grpc_exec_ctx *exec_ctx, void *sp,
                                   grpc_error *error) {
-  grpc_byte_stream *bs;
   grpc_chttp2_stream *s = sp;
   grpc_chttp2_transport *t = s->t;
 
@@ -686,9 +706,9 @@
     GPR_ASSERT(grpc_chttp2_stream_map_find(&t->stream_map, s->id) == NULL);
   }
 
-  while ((bs = grpc_chttp2_incoming_frame_queue_pop(&s->incoming_frames))) {
-    incoming_byte_stream_destroy_locked(exec_ctx, bs, GRPC_ERROR_NONE);
-  }
+  grpc_slice_buffer_destroy_internal(exec_ctx,
+                                     &s->unprocessed_incoming_frames_buffer);
+  grpc_slice_buffer_destroy_internal(exec_ctx, &s->frame_storage);
 
   grpc_chttp2_list_remove_stalled_by_transport(t, s);
   grpc_chttp2_list_remove_stalled_by_stream(t, s);
@@ -715,6 +735,7 @@
   grpc_slice_buffer_destroy_internal(exec_ctx, &s->flow_controlled_buffer);
   GRPC_ERROR_UNREF(s->read_closed_error);
   GRPC_ERROR_UNREF(s->write_closed_error);
+  GRPC_ERROR_UNREF(s->byte_stream_error);
 
   if (s->incoming_window_delta > 0) {
     GRPC_CHTTP2_FLOW_DEBIT_STREAM_INCOMING_WINDOW_DELTA(
@@ -1168,8 +1189,9 @@
       s->fetching_send_message = NULL;
       return; /* early out */
     } else if (grpc_byte_stream_next(exec_ctx, s->fetching_send_message,
-                                     &s->fetching_slice, UINT32_MAX,
-                                     &s->complete_fetch_locked)) {
+                                     UINT32_MAX, &s->complete_fetch_locked)) {
+      grpc_byte_stream_pull(exec_ctx, s->fetching_send_message,
+                            &s->fetching_slice);
       add_fetched_slice_locked(exec_ctx, t, s);
     }
   }
@@ -1180,9 +1202,15 @@
   grpc_chttp2_stream *s = gs;
   grpc_chttp2_transport *t = s->t;
   if (error == GRPC_ERROR_NONE) {
-    add_fetched_slice_locked(exec_ctx, t, s);
-    continue_fetching_send_locked(exec_ctx, t, s);
-  } else {
+    error = grpc_byte_stream_pull(exec_ctx, s->fetching_send_message,
+                                  &s->fetching_slice);
+    if (error == GRPC_ERROR_NONE) {
+      add_fetched_slice_locked(exec_ctx, t, s);
+      continue_fetching_send_locked(exec_ctx, t, s);
+    }
+  }
+
+  if (error != GRPC_ERROR_NONE) {
     /* TODO(ctiller): what to do here */
     abort();
   }
@@ -1414,12 +1442,20 @@
   }
 
   if (op->recv_message) {
+    size_t already_received;
     GPR_ASSERT(s->recv_message_ready == NULL);
+    GPR_ASSERT(!s->pending_byte_stream);
     s->recv_message_ready = op_payload->recv_message.recv_message_ready;
     s->recv_message = op_payload->recv_message.recv_message;
-    if (s->id != 0 &&
-        (s->incoming_frames.head == NULL || s->incoming_frames.head->is_tail)) {
-      incoming_byte_stream_update_flow_control(exec_ctx, t, s, 5, 0);
+    if (s->id != 0) {
+      if (s->pending_byte_stream) {
+        already_received = s->frame_storage.length;
+      } else {
+        already_received = s->frame_storage.length +
+                           s->unprocessed_incoming_frames_buffer.length;
+      }
+      incoming_byte_stream_update_flow_control(exec_ctx, t, s, 5,
+                                               already_received);
     }
     grpc_chttp2_maybe_complete_recv_message(exec_ctx, t, s);
   }
@@ -1607,13 +1643,13 @@
 void grpc_chttp2_maybe_complete_recv_initial_metadata(grpc_exec_ctx *exec_ctx,
                                                       grpc_chttp2_transport *t,
                                                       grpc_chttp2_stream *s) {
-  grpc_byte_stream *bs;
   if (s->recv_initial_metadata_ready != NULL &&
       s->published_metadata[0] != GRPC_METADATA_NOT_PUBLISHED) {
     if (s->seen_error) {
-      while ((bs = grpc_chttp2_incoming_frame_queue_pop(&s->incoming_frames)) !=
-             NULL) {
-        incoming_byte_stream_destroy_locked(exec_ctx, bs, GRPC_ERROR_NONE);
+      grpc_slice_buffer_reset_and_unref_internal(exec_ctx, &s->frame_storage);
+      if (!s->pending_byte_stream) {
+        grpc_slice_buffer_reset_and_unref_internal(
+            exec_ctx, &s->unprocessed_incoming_frames_buffer);
       }
     }
     grpc_chttp2_incoming_metadata_buffer_publish(
@@ -1626,39 +1662,65 @@
 void grpc_chttp2_maybe_complete_recv_message(grpc_exec_ctx *exec_ctx,
                                              grpc_chttp2_transport *t,
                                              grpc_chttp2_stream *s) {
-  grpc_byte_stream *bs;
+  grpc_error *error = GRPC_ERROR_NONE;
   if (s->recv_message_ready != NULL) {
-    while (s->final_metadata_requested && s->seen_error &&
-           (bs = grpc_chttp2_incoming_frame_queue_pop(&s->incoming_frames)) !=
-               NULL) {
-      incoming_byte_stream_destroy_locked(exec_ctx, bs, GRPC_ERROR_NONE);
+    *s->recv_message = NULL;
+    if (s->final_metadata_requested && s->seen_error) {
+      grpc_slice_buffer_reset_and_unref_internal(exec_ctx, &s->frame_storage);
+      if (!s->pending_byte_stream) {
+        grpc_slice_buffer_reset_and_unref_internal(
+            exec_ctx, &s->unprocessed_incoming_frames_buffer);
+      }
     }
-    if (s->incoming_frames.head != NULL) {
-      *s->recv_message =
-          grpc_chttp2_incoming_frame_queue_pop(&s->incoming_frames);
-      GPR_ASSERT(*s->recv_message != NULL);
+    if (!s->pending_byte_stream) {
+      while (s->unprocessed_incoming_frames_buffer.length > 0 ||
+             s->frame_storage.length > 0) {
+        if (s->unprocessed_incoming_frames_buffer.length == 0) {
+          grpc_slice_buffer_swap(&s->unprocessed_incoming_frames_buffer,
+                                 &s->frame_storage);
+        }
+        error = deframe_unprocessed_incoming_frames(
+            exec_ctx, &s->data_parser, s,
+            &s->unprocessed_incoming_frames_buffer, NULL, s->recv_message);
+        if (error != GRPC_ERROR_NONE) {
+          s->seen_error = true;
+          grpc_slice_buffer_reset_and_unref_internal(exec_ctx,
+                                                     &s->frame_storage);
+          grpc_slice_buffer_reset_and_unref_internal(
+              exec_ctx, &s->unprocessed_incoming_frames_buffer);
+          break;
+        } else if (*s->recv_message != NULL) {
+          break;
+        }
+      }
+    }
+    if (error == GRPC_ERROR_NONE && *s->recv_message != NULL) {
       null_then_run_closure(exec_ctx, &s->recv_message_ready, GRPC_ERROR_NONE);
     } else if (s->published_metadata[1] != GRPC_METADATA_NOT_PUBLISHED) {
       *s->recv_message = NULL;
       null_then_run_closure(exec_ctx, &s->recv_message_ready, GRPC_ERROR_NONE);
     }
+    GRPC_ERROR_UNREF(error);
   }
 }
 
 void grpc_chttp2_maybe_complete_recv_trailing_metadata(grpc_exec_ctx *exec_ctx,
                                                        grpc_chttp2_transport *t,
                                                        grpc_chttp2_stream *s) {
-  grpc_byte_stream *bs;
   grpc_chttp2_maybe_complete_recv_message(exec_ctx, t, s);
   if (s->recv_trailing_metadata_finished != NULL && s->read_closed &&
       s->write_closed) {
     if (s->seen_error) {
-      while ((bs = grpc_chttp2_incoming_frame_queue_pop(&s->incoming_frames)) !=
-             NULL) {
-        incoming_byte_stream_destroy_locked(exec_ctx, bs, GRPC_ERROR_NONE);
+      grpc_slice_buffer_reset_and_unref_internal(exec_ctx, &s->frame_storage);
+      if (!s->pending_byte_stream) {
+        grpc_slice_buffer_reset_and_unref_internal(
+            exec_ctx, &s->unprocessed_incoming_frames_buffer);
       }
     }
-    if (s->all_incoming_byte_streams_finished &&
+    bool pending_data = s->pending_byte_stream ||
+                        s->unprocessed_incoming_frames_buffer.length > 0;
+    if (s->read_closed && s->frame_storage.length == 0 &&
+        (!pending_data || s->seen_error) &&
         s->recv_trailing_metadata_finished != NULL) {
       grpc_chttp2_incoming_metadata_buffer_publish(
           exec_ctx, &s->metadata_buffer[1], s->recv_trailing_metadata);
@@ -1669,14 +1731,6 @@
   }
 }
 
-static void decrement_active_streams_locked(grpc_exec_ctx *exec_ctx,
-                                            grpc_chttp2_transport *t,
-                                            grpc_chttp2_stream *s) {
-  if ((s->all_incoming_byte_streams_finished = gpr_unref(&s->active_streams))) {
-    grpc_chttp2_maybe_complete_recv_trailing_metadata(exec_ctx, t, s);
-  }
-}
-
 static void remove_stream(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
                           uint32_t id, grpc_error *error) {
   grpc_chttp2_stream *s = grpc_chttp2_stream_map_delete(&t->stream_map, id);
@@ -1685,10 +1739,19 @@
     t->incoming_stream = NULL;
     grpc_chttp2_parsing_become_skip_parser(exec_ctx, t);
   }
-  if (s->data_parser.parsing_frame != NULL) {
-    grpc_chttp2_incoming_byte_stream_finished(
-        exec_ctx, s->data_parser.parsing_frame, GRPC_ERROR_REF(error));
-    s->data_parser.parsing_frame = NULL;
+  if (s->pending_byte_stream) {
+    if (s->on_next != NULL) {
+      grpc_chttp2_incoming_byte_stream *bs = s->data_parser.parsing_frame;
+      if (error == GRPC_ERROR_NONE) {
+        error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Truncated message");
+      }
+      incoming_byte_stream_publish_error(exec_ctx, bs, error);
+      incoming_byte_stream_unref(exec_ctx, bs);
+      s->data_parser.parsing_frame = NULL;
+    } else {
+      GRPC_ERROR_UNREF(s->byte_stream_error);
+      s->byte_stream_error = GRPC_ERROR_REF(error);
+    }
   }
 
   if (grpc_chttp2_stream_map_size(&t->stream_map) == 0) {
@@ -1874,7 +1937,6 @@
         s->published_metadata[i] = GPRC_METADATA_PUBLISHED_AT_CLOSE;
       }
     }
-    decrement_active_streams_locked(exec_ctx, t, s);
     grpc_chttp2_maybe_complete_recv_initial_metadata(exec_ctx, t, s);
     grpc_chttp2_maybe_complete_recv_message(exec_ctx, t, s);
   }
@@ -1890,6 +1952,7 @@
   grpc_slice hdr;
   grpc_slice status_hdr;
   grpc_slice http_status_hdr;
+  grpc_slice content_type_hdr;
   grpc_slice message_pfx;
   uint8_t *p;
   uint32_t len = 0;
@@ -1923,6 +1986,42 @@
     *p++ = '0';
     GPR_ASSERT(p == GRPC_SLICE_END_PTR(http_status_hdr));
     len += (uint32_t)GRPC_SLICE_LENGTH(http_status_hdr);
+
+    content_type_hdr = grpc_slice_malloc(31);
+    p = GRPC_SLICE_START_PTR(content_type_hdr);
+    *p++ = 0x00;
+    *p++ = 12;
+    *p++ = 'c';
+    *p++ = 'o';
+    *p++ = 'n';
+    *p++ = 't';
+    *p++ = 'e';
+    *p++ = 'n';
+    *p++ = 't';
+    *p++ = '-';
+    *p++ = 't';
+    *p++ = 'y';
+    *p++ = 'p';
+    *p++ = 'e';
+    *p++ = 16;
+    *p++ = 'a';
+    *p++ = 'p';
+    *p++ = 'p';
+    *p++ = 'l';
+    *p++ = 'i';
+    *p++ = 'c';
+    *p++ = 'a';
+    *p++ = 't';
+    *p++ = 'i';
+    *p++ = 'o';
+    *p++ = 'n';
+    *p++ = '/';
+    *p++ = 'g';
+    *p++ = 'r';
+    *p++ = 'p';
+    *p++ = 'c';
+    GPR_ASSERT(p == GRPC_SLICE_END_PTR(content_type_hdr));
+    len += (uint32_t)GRPC_SLICE_LENGTH(content_type_hdr);
   }
 
   status_hdr = grpc_slice_malloc(15 + (grpc_status >= 10));
@@ -1992,6 +2091,7 @@
   grpc_slice_buffer_add(&t->qbuf, hdr);
   if (!s->sent_initial_metadata) {
     grpc_slice_buffer_add(&t->qbuf, http_status_hdr);
+    grpc_slice_buffer_add(&t->qbuf, content_type_hdr);
   }
   grpc_slice_buffer_add(&t->qbuf, status_hdr);
   grpc_slice_buffer_add(&t->qbuf, message_pfx);
@@ -2267,7 +2367,9 @@
                                        grpc_error *error) {
   grpc_chttp2_transport *t = arg;
   GPR_ASSERT(t->keepalive_state == GRPC_CHTTP2_KEEPALIVE_STATE_WAITING);
-  if (error == GRPC_ERROR_NONE && !(t->destroying || t->closed)) {
+  if (t->destroying || t->closed) {
+    t->keepalive_state = GRPC_CHTTP2_KEEPALIVE_STATE_DYING;
+  } else if (error == GRPC_ERROR_NONE) {
     if (t->keepalive_permit_without_calls ||
         grpc_chttp2_stream_map_size(&t->stream_map) > 0) {
       t->keepalive_state = GRPC_CHTTP2_KEEPALIVE_STATE_PINGING;
@@ -2282,7 +2384,7 @@
           gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC), t->keepalive_time),
           &t->init_keepalive_ping_locked, gpr_now(GPR_CLOCK_MONOTONIC));
     }
-  } else if (error == GRPC_ERROR_CANCELLED && !(t->destroying || t->closed)) {
+  } else if (error == GRPC_ERROR_CANCELLED) {
     /* The keepalive ping timer may be cancelled by bdp */
     GRPC_CHTTP2_REF_TRANSPORT(t, "init keepalive ping");
     grpc_timer_init(
@@ -2374,12 +2476,28 @@
  * BYTE STREAM
  */
 
+static void reset_byte_stream(grpc_exec_ctx *exec_ctx, void *arg,
+                              grpc_error *error) {
+  grpc_chttp2_stream *s = (grpc_chttp2_stream *)arg;
+
+  s->pending_byte_stream = false;
+  if (error == GRPC_ERROR_NONE) {
+    grpc_chttp2_maybe_complete_recv_message(exec_ctx, s->t, s);
+    grpc_chttp2_maybe_complete_recv_trailing_metadata(exec_ctx, s->t, s);
+  } else {
+    GPR_ASSERT(error != GRPC_ERROR_NONE);
+    grpc_closure_sched(exec_ctx, s->on_next, GRPC_ERROR_REF(error));
+    s->on_next = NULL;
+    GRPC_ERROR_UNREF(s->byte_stream_error);
+    s->byte_stream_error = GRPC_ERROR_NONE;
+    grpc_chttp2_cancel_stream(exec_ctx, s->t, s, GRPC_ERROR_REF(error));
+    s->byte_stream_error = error;
+  }
+}
+
 static void incoming_byte_stream_unref(grpc_exec_ctx *exec_ctx,
                                        grpc_chttp2_incoming_byte_stream *bs) {
   if (gpr_unref(&bs->refs)) {
-    GRPC_ERROR_UNREF(bs->error);
-    grpc_slice_buffer_destroy_internal(exec_ctx, &bs->slices);
-    gpr_mu_destroy(&bs->slice_mu);
     gpr_free(bs);
   }
 }
@@ -2439,47 +2557,90 @@
   grpc_chttp2_transport *t = bs->transport;
   grpc_chttp2_stream *s = bs->stream;
 
-  if (bs->is_tail) {
-    gpr_mu_lock(&bs->slice_mu);
-    size_t cur_length = bs->slices.length;
-    gpr_mu_unlock(&bs->slice_mu);
-    incoming_byte_stream_update_flow_control(
-        exec_ctx, t, s, bs->next_action.max_size_hint, cur_length);
-  }
-  gpr_mu_lock(&bs->slice_mu);
-  if (bs->slices.count > 0) {
-    *bs->next_action.slice = grpc_slice_buffer_take_first(&bs->slices);
-    grpc_closure_run(exec_ctx, bs->next_action.on_complete, GRPC_ERROR_NONE);
-  } else if (bs->error != GRPC_ERROR_NONE) {
-    grpc_closure_run(exec_ctx, bs->next_action.on_complete,
-                     GRPC_ERROR_REF(bs->error));
+  size_t cur_length = s->frame_storage.length;
+  incoming_byte_stream_update_flow_control(
+      exec_ctx, t, s, bs->next_action.max_size_hint, cur_length);
+
+  GPR_ASSERT(s->unprocessed_incoming_frames_buffer.length == 0);
+  if (s->frame_storage.length > 0) {
+    grpc_slice_buffer_swap(&s->frame_storage,
+                           &s->unprocessed_incoming_frames_buffer);
+    grpc_closure_sched(exec_ctx, bs->next_action.on_complete, GRPC_ERROR_NONE);
+  } else if (s->byte_stream_error != GRPC_ERROR_NONE) {
+    grpc_closure_sched(exec_ctx, bs->next_action.on_complete,
+                       GRPC_ERROR_REF(s->byte_stream_error));
+    if (s->data_parser.parsing_frame != NULL) {
+      incoming_byte_stream_unref(exec_ctx, s->data_parser.parsing_frame);
+      s->data_parser.parsing_frame = NULL;
+    }
+  } else if (s->read_closed) {
+    if (bs->remaining_bytes != 0) {
+      s->byte_stream_error =
+          GRPC_ERROR_CREATE_FROM_STATIC_STRING("Truncated message");
+      grpc_closure_sched(exec_ctx, bs->next_action.on_complete,
+                         GRPC_ERROR_REF(s->byte_stream_error));
+      if (s->data_parser.parsing_frame != NULL) {
+        incoming_byte_stream_unref(exec_ctx, s->data_parser.parsing_frame);
+        s->data_parser.parsing_frame = NULL;
+      }
+    } else {
+      /* Should never reach here. */
+      GPR_ASSERT(false);
+    }
   } else {
-    bs->on_next = bs->next_action.on_complete;
-    bs->next = bs->next_action.slice;
+    s->on_next = bs->next_action.on_complete;
   }
-  gpr_mu_unlock(&bs->slice_mu);
   incoming_byte_stream_unref(exec_ctx, bs);
 }
 
-static int incoming_byte_stream_next(grpc_exec_ctx *exec_ctx,
-                                     grpc_byte_stream *byte_stream,
-                                     grpc_slice *slice, size_t max_size_hint,
-                                     grpc_closure *on_complete) {
+static bool incoming_byte_stream_next(grpc_exec_ctx *exec_ctx,
+                                      grpc_byte_stream *byte_stream,
+                                      size_t max_size_hint,
+                                      grpc_closure *on_complete) {
   GPR_TIMER_BEGIN("incoming_byte_stream_next", 0);
   grpc_chttp2_incoming_byte_stream *bs =
       (grpc_chttp2_incoming_byte_stream *)byte_stream;
-  gpr_ref(&bs->refs);
-  bs->next_action.slice = slice;
-  bs->next_action.max_size_hint = max_size_hint;
-  bs->next_action.on_complete = on_complete;
-  grpc_closure_sched(
-      exec_ctx,
-      grpc_closure_init(
-          &bs->next_action.closure, incoming_byte_stream_next_locked, bs,
-          grpc_combiner_scheduler(bs->transport->combiner, false)),
-      GRPC_ERROR_NONE);
-  GPR_TIMER_END("incoming_byte_stream_next", 0);
-  return 0;
+  grpc_chttp2_stream *s = bs->stream;
+  if (s->unprocessed_incoming_frames_buffer.length > 0) {
+    return true;
+  } else {
+    gpr_ref(&bs->refs);
+    bs->next_action.max_size_hint = max_size_hint;
+    bs->next_action.on_complete = on_complete;
+    grpc_closure_sched(
+        exec_ctx,
+        grpc_closure_init(
+            &bs->next_action.closure, incoming_byte_stream_next_locked, bs,
+            grpc_combiner_scheduler(bs->transport->combiner, false)),
+        GRPC_ERROR_NONE);
+    GPR_TIMER_END("incoming_byte_stream_next", 0);
+    return false;
+  }
+}
+
+static grpc_error *incoming_byte_stream_pull(grpc_exec_ctx *exec_ctx,
+                                             grpc_byte_stream *byte_stream,
+                                             grpc_slice *slice) {
+  GPR_TIMER_BEGIN("incoming_byte_stream_pull", 0);
+  grpc_chttp2_incoming_byte_stream *bs =
+      (grpc_chttp2_incoming_byte_stream *)byte_stream;
+  grpc_chttp2_stream *s = bs->stream;
+
+  if (s->unprocessed_incoming_frames_buffer.length > 0) {
+    grpc_error *error = deframe_unprocessed_incoming_frames(
+        exec_ctx, &s->data_parser, s, &s->unprocessed_incoming_frames_buffer,
+        slice, NULL);
+    if (error != GRPC_ERROR_NONE) {
+      return error;
+    }
+  } else {
+    grpc_error *error =
+        GRPC_ERROR_CREATE_FROM_STATIC_STRING("Truncated message");
+    grpc_closure_sched(exec_ctx, &s->reset_byte_stream, GRPC_ERROR_REF(error));
+    return error;
+  }
+  GPR_TIMER_END("incoming_byte_stream_pull", 0);
+  return GRPC_ERROR_NONE;
 }
 
 static void incoming_byte_stream_destroy(grpc_exec_ctx *exec_ctx,
@@ -2489,9 +2650,14 @@
                                                 void *byte_stream,
                                                 grpc_error *error_ignored) {
   grpc_chttp2_incoming_byte_stream *bs = byte_stream;
+  grpc_chttp2_stream *s = bs->stream;
+  grpc_chttp2_transport *t = s->t;
+
   GPR_ASSERT(bs->base.destroy == incoming_byte_stream_destroy);
-  decrement_active_streams_locked(exec_ctx, bs->transport, bs->stream);
   incoming_byte_stream_unref(exec_ctx, bs);
+  s->pending_byte_stream = false;
+  grpc_chttp2_maybe_complete_recv_message(exec_ctx, t, s);
+  grpc_chttp2_maybe_complete_recv_trailing_metadata(exec_ctx, t, s);
 }
 
 static void incoming_byte_stream_destroy(grpc_exec_ctx *exec_ctx,
@@ -2511,50 +2677,53 @@
 static void incoming_byte_stream_publish_error(
     grpc_exec_ctx *exec_ctx, grpc_chttp2_incoming_byte_stream *bs,
     grpc_error *error) {
+  grpc_chttp2_stream *s = bs->stream;
+
   GPR_ASSERT(error != GRPC_ERROR_NONE);
-  grpc_closure_sched(exec_ctx, bs->on_next, GRPC_ERROR_REF(error));
-  bs->on_next = NULL;
-  GRPC_ERROR_UNREF(bs->error);
+  grpc_closure_sched(exec_ctx, s->on_next, GRPC_ERROR_REF(error));
+  s->on_next = NULL;
+  GRPC_ERROR_UNREF(s->byte_stream_error);
+  s->byte_stream_error = GRPC_ERROR_REF(error);
   grpc_chttp2_cancel_stream(exec_ctx, bs->transport, bs->stream,
                             GRPC_ERROR_REF(error));
-  bs->error = error;
 }
 
-void grpc_chttp2_incoming_byte_stream_push(grpc_exec_ctx *exec_ctx,
-                                           grpc_chttp2_incoming_byte_stream *bs,
-                                           grpc_slice slice) {
-  gpr_mu_lock(&bs->slice_mu);
+grpc_error *grpc_chttp2_incoming_byte_stream_push(
+    grpc_exec_ctx *exec_ctx, grpc_chttp2_incoming_byte_stream *bs,
+    grpc_slice slice, grpc_slice *slice_out) {
+  grpc_chttp2_stream *s = bs->stream;
+
   if (bs->remaining_bytes < GRPC_SLICE_LENGTH(slice)) {
-    incoming_byte_stream_publish_error(
-        exec_ctx, bs,
-        GRPC_ERROR_CREATE_FROM_STATIC_STRING("Too many bytes in stream"));
+    grpc_error *error =
+        GRPC_ERROR_CREATE_FROM_STATIC_STRING("Too many bytes in stream");
+
+    grpc_closure_sched(exec_ctx, &s->reset_byte_stream, GRPC_ERROR_REF(error));
+    grpc_slice_unref_internal(exec_ctx, slice);
+    return error;
   } else {
     bs->remaining_bytes -= (uint32_t)GRPC_SLICE_LENGTH(slice);
-    if (bs->on_next != NULL) {
-      *bs->next = slice;
-      grpc_closure_sched(exec_ctx, bs->on_next, GRPC_ERROR_NONE);
-      bs->on_next = NULL;
-    } else {
-      grpc_slice_buffer_add(&bs->slices, slice);
+    if (slice_out != NULL) {
+      *slice_out = slice;
     }
+    return GRPC_ERROR_NONE;
   }
-  gpr_mu_unlock(&bs->slice_mu);
 }
 
-void grpc_chttp2_incoming_byte_stream_finished(
+grpc_error *grpc_chttp2_incoming_byte_stream_finished(
     grpc_exec_ctx *exec_ctx, grpc_chttp2_incoming_byte_stream *bs,
-    grpc_error *error) {
+    grpc_error *error, bool reset_on_error) {
+  grpc_chttp2_stream *s = bs->stream;
+
   if (error == GRPC_ERROR_NONE) {
-    gpr_mu_lock(&bs->slice_mu);
     if (bs->remaining_bytes != 0) {
       error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Truncated message");
     }
-    gpr_mu_unlock(&bs->slice_mu);
   }
-  if (error != GRPC_ERROR_NONE) {
-    incoming_byte_stream_publish_error(exec_ctx, bs, error);
+  if (error != GRPC_ERROR_NONE && reset_on_error) {
+    grpc_closure_sched(exec_ctx, &s->reset_byte_stream, GRPC_ERROR_REF(error));
   }
   incoming_byte_stream_unref(exec_ctx, bs);
+  return error;
 }
 
 grpc_chttp2_incoming_byte_stream *grpc_chttp2_incoming_byte_stream_create(
@@ -2566,26 +2735,12 @@
   incoming_byte_stream->remaining_bytes = frame_size;
   incoming_byte_stream->base.flags = flags;
   incoming_byte_stream->base.next = incoming_byte_stream_next;
+  incoming_byte_stream->base.pull = incoming_byte_stream_pull;
   incoming_byte_stream->base.destroy = incoming_byte_stream_destroy;
-  gpr_mu_init(&incoming_byte_stream->slice_mu);
   gpr_ref_init(&incoming_byte_stream->refs, 2);
-  incoming_byte_stream->next_message = NULL;
   incoming_byte_stream->transport = t;
   incoming_byte_stream->stream = s;
-  gpr_ref(&incoming_byte_stream->stream->active_streams);
-  grpc_slice_buffer_init(&incoming_byte_stream->slices);
-  incoming_byte_stream->on_next = NULL;
-  incoming_byte_stream->is_tail = 1;
-  incoming_byte_stream->error = GRPC_ERROR_NONE;
-  grpc_chttp2_incoming_frame_queue *q = &s->incoming_frames;
-  if (q->head == NULL) {
-    q->head = incoming_byte_stream;
-  } else {
-    q->tail->is_tail = 0;
-    q->tail->next_message = incoming_byte_stream;
-  }
-  q->tail = incoming_byte_stream;
-  grpc_chttp2_maybe_complete_recv_message(exec_ctx, t, s);
+  s->byte_stream_error = GRPC_ERROR_NONE;
   return incoming_byte_stream;
 }
 
diff --git a/src/core/ext/transport/chttp2/transport/frame_data.c b/src/core/ext/transport/chttp2/transport/frame_data.c
index 6e9258e..5d382d8 100644
--- a/src/core/ext/transport/chttp2/transport/frame_data.c
+++ b/src/core/ext/transport/chttp2/transport/frame_data.c
@@ -40,6 +40,7 @@
 #include <grpc/support/string_util.h>
 #include <grpc/support/useful.h>
 #include "src/core/ext/transport/chttp2/transport/internal.h"
+#include "src/core/lib/slice/slice_internal.h"
 #include "src/core/lib/slice/slice_string_helpers.h"
 #include "src/core/lib/support/string.h"
 #include "src/core/lib/transport/transport.h"
@@ -53,16 +54,17 @@
 void grpc_chttp2_data_parser_destroy(grpc_exec_ctx *exec_ctx,
                                      grpc_chttp2_data_parser *parser) {
   if (parser->parsing_frame != NULL) {
-    grpc_chttp2_incoming_byte_stream_finished(
+    GRPC_ERROR_UNREF(grpc_chttp2_incoming_byte_stream_finished(
         exec_ctx, parser->parsing_frame,
-        GRPC_ERROR_CREATE_FROM_STATIC_STRING("Parser destroyed"));
+        GRPC_ERROR_CREATE_FROM_STATIC_STRING("Parser destroyed"), false));
   }
   GRPC_ERROR_UNREF(parser->error);
 }
 
 grpc_error *grpc_chttp2_data_parser_begin_frame(grpc_chttp2_data_parser *parser,
                                                 uint8_t flags,
-                                                uint32_t stream_id) {
+                                                uint32_t stream_id,
+                                                grpc_chttp2_stream *s) {
   if (flags & ~GRPC_CHTTP2_DATA_FLAG_END_STREAM) {
     char *msg;
     gpr_asprintf(&msg, "unsupported data flags: 0x%02x", flags);
@@ -74,47 +76,14 @@
   }
 
   if (flags & GRPC_CHTTP2_DATA_FLAG_END_STREAM) {
-    parser->is_last_frame = 1;
+    s->received_last_frame = true;
   } else {
-    parser->is_last_frame = 0;
+    s->received_last_frame = false;
   }
 
   return GRPC_ERROR_NONE;
 }
 
-void grpc_chttp2_incoming_frame_queue_merge(
-    grpc_chttp2_incoming_frame_queue *head_dst,
-    grpc_chttp2_incoming_frame_queue *tail_src) {
-  if (tail_src->head == NULL) {
-    return;
-  }
-
-  if (head_dst->head == NULL) {
-    *head_dst = *tail_src;
-    memset(tail_src, 0, sizeof(*tail_src));
-    return;
-  }
-
-  head_dst->tail->next_message = tail_src->head;
-  head_dst->tail = tail_src->tail;
-  memset(tail_src, 0, sizeof(*tail_src));
-}
-
-grpc_byte_stream *grpc_chttp2_incoming_frame_queue_pop(
-    grpc_chttp2_incoming_frame_queue *q) {
-  grpc_byte_stream *out;
-  if (q->head == NULL) {
-    return NULL;
-  }
-  out = &q->head->base;
-  if (q->head == q->tail) {
-    memset(q, 0, sizeof(*q));
-  } else {
-    q->head = q->head->next_message;
-  }
-  return out;
-}
-
 void grpc_chttp2_encode_data(uint32_t id, grpc_slice_buffer *inbuf,
                              uint32_t write_bytes, int is_eof,
                              grpc_transport_one_way_stats *stats,
@@ -143,145 +112,217 @@
   stats->data_bytes += write_bytes;
 }
 
-static grpc_error *parse_inner(grpc_exec_ctx *exec_ctx,
-                               grpc_chttp2_data_parser *p,
-                               grpc_chttp2_transport *t, grpc_chttp2_stream *s,
-                               grpc_slice slice) {
-  uint8_t *const beg = GRPC_SLICE_START_PTR(slice);
-  uint8_t *const end = GRPC_SLICE_END_PTR(slice);
-  uint8_t *cur = beg;
-  uint32_t message_flags;
-  grpc_chttp2_incoming_byte_stream *incoming_byte_stream;
-  char *msg;
+grpc_error *deframe_unprocessed_incoming_frames(grpc_exec_ctx *exec_ctx,
+                                                grpc_chttp2_data_parser *p,
+                                                grpc_chttp2_stream *s,
+                                                grpc_slice_buffer *slices,
+                                                grpc_slice *slice_out,
+                                                grpc_byte_stream **stream_out) {
+  grpc_error *error = GRPC_ERROR_NONE;
+  grpc_chttp2_transport *t = s->t;
 
-  if (cur == end) {
-    return GRPC_ERROR_NONE;
+  while (slices->count > 0) {
+    uint8_t *beg = NULL;
+    uint8_t *end = NULL;
+    uint8_t *cur = NULL;
+
+    grpc_slice slice = grpc_slice_buffer_take_first(slices);
+
+    beg = GRPC_SLICE_START_PTR(slice);
+    end = GRPC_SLICE_END_PTR(slice);
+    cur = beg;
+    uint32_t message_flags;
+    char *msg;
+
+    if (cur == end) {
+      grpc_slice_unref_internal(exec_ctx, slice);
+      continue;
+    }
+
+    switch (p->state) {
+      case GRPC_CHTTP2_DATA_ERROR:
+        p->state = GRPC_CHTTP2_DATA_ERROR;
+        grpc_slice_unref_internal(exec_ctx, slice);
+        return GRPC_ERROR_REF(p->error);
+      case GRPC_CHTTP2_DATA_FH_0:
+        p->frame_type = *cur;
+        switch (p->frame_type) {
+          case 0:
+            p->is_frame_compressed = false; /* GPR_FALSE */
+            break;
+          case 1:
+            p->is_frame_compressed = true; /* GPR_TRUE */
+            break;
+          default:
+            gpr_asprintf(&msg, "Bad GRPC frame type 0x%02x", p->frame_type);
+            p->error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg);
+            p->error = grpc_error_set_int(p->error, GRPC_ERROR_INT_STREAM_ID,
+                                          (intptr_t)s->id);
+            gpr_free(msg);
+            msg = grpc_dump_slice(slice, GPR_DUMP_HEX | GPR_DUMP_ASCII);
+            p->error = grpc_error_set_str(p->error, GRPC_ERROR_STR_RAW_BYTES,
+                                          grpc_slice_from_copied_string(msg));
+            gpr_free(msg);
+            p->error =
+                grpc_error_set_int(p->error, GRPC_ERROR_INT_OFFSET, cur - beg);
+            p->state = GRPC_CHTTP2_DATA_ERROR;
+            grpc_slice_unref_internal(exec_ctx, slice);
+            return GRPC_ERROR_REF(p->error);
+        }
+        if (++cur == end) {
+          p->state = GRPC_CHTTP2_DATA_FH_1;
+          grpc_slice_unref_internal(exec_ctx, slice);
+          continue;
+        }
+      /* fallthrough */
+      case GRPC_CHTTP2_DATA_FH_1:
+        p->frame_size = ((uint32_t)*cur) << 24;
+        if (++cur == end) {
+          p->state = GRPC_CHTTP2_DATA_FH_2;
+          grpc_slice_unref_internal(exec_ctx, slice);
+          continue;
+        }
+      /* fallthrough */
+      case GRPC_CHTTP2_DATA_FH_2:
+        p->frame_size |= ((uint32_t)*cur) << 16;
+        if (++cur == end) {
+          p->state = GRPC_CHTTP2_DATA_FH_3;
+          grpc_slice_unref_internal(exec_ctx, slice);
+          continue;
+        }
+      /* fallthrough */
+      case GRPC_CHTTP2_DATA_FH_3:
+        p->frame_size |= ((uint32_t)*cur) << 8;
+        if (++cur == end) {
+          p->state = GRPC_CHTTP2_DATA_FH_4;
+          grpc_slice_unref_internal(exec_ctx, slice);
+          continue;
+        }
+      /* fallthrough */
+      case GRPC_CHTTP2_DATA_FH_4:
+        GPR_ASSERT(stream_out != NULL);
+        GPR_ASSERT(p->parsing_frame == NULL);
+        p->frame_size |= ((uint32_t)*cur);
+        p->state = GRPC_CHTTP2_DATA_FRAME;
+        ++cur;
+        message_flags = 0;
+        if (p->is_frame_compressed) {
+          message_flags |= GRPC_WRITE_INTERNAL_COMPRESS;
+        }
+        p->parsing_frame = grpc_chttp2_incoming_byte_stream_create(
+            exec_ctx, t, s, p->frame_size, message_flags);
+        *stream_out = &p->parsing_frame->base;
+        if (p->parsing_frame->remaining_bytes == 0) {
+          GRPC_ERROR_UNREF(grpc_chttp2_incoming_byte_stream_finished(
+              exec_ctx, p->parsing_frame, GRPC_ERROR_NONE, true));
+          p->parsing_frame = NULL;
+          p->state = GRPC_CHTTP2_DATA_FH_0;
+        }
+        s->pending_byte_stream = true;
+
+        if (cur != end) {
+          grpc_slice_buffer_undo_take_first(
+              &s->unprocessed_incoming_frames_buffer,
+              grpc_slice_sub(slice, (size_t)(cur - beg), (size_t)(end - beg)));
+        }
+        grpc_slice_unref_internal(exec_ctx, slice);
+        return GRPC_ERROR_NONE;
+      case GRPC_CHTTP2_DATA_FRAME: {
+        GPR_ASSERT(p->parsing_frame != NULL);
+        GPR_ASSERT(slice_out != NULL);
+        if (cur == end) {
+          grpc_slice_unref_internal(exec_ctx, slice);
+          continue;
+        }
+        uint32_t remaining = (uint32_t)(end - cur);
+        if (remaining == p->frame_size) {
+          if (GRPC_ERROR_NONE != (error = grpc_chttp2_incoming_byte_stream_push(
+                                      exec_ctx, p->parsing_frame,
+                                      grpc_slice_sub(slice, (size_t)(cur - beg),
+                                                     (size_t)(end - beg)),
+                                      slice_out))) {
+            grpc_slice_unref_internal(exec_ctx, slice);
+            return error;
+          }
+          if (GRPC_ERROR_NONE !=
+              (error = grpc_chttp2_incoming_byte_stream_finished(
+                   exec_ctx, p->parsing_frame, GRPC_ERROR_NONE, true))) {
+            grpc_slice_unref_internal(exec_ctx, slice);
+            return error;
+          }
+          p->parsing_frame = NULL;
+          p->state = GRPC_CHTTP2_DATA_FH_0;
+          grpc_slice_unref_internal(exec_ctx, slice);
+          return GRPC_ERROR_NONE;
+        } else if (remaining < p->frame_size) {
+          if (GRPC_ERROR_NONE != (error = grpc_chttp2_incoming_byte_stream_push(
+                                      exec_ctx, p->parsing_frame,
+                                      grpc_slice_sub(slice, (size_t)(cur - beg),
+                                                     (size_t)(end - beg)),
+                                      slice_out))) {
+            return error;
+          }
+          p->frame_size -= remaining;
+          grpc_slice_unref_internal(exec_ctx, slice);
+          return GRPC_ERROR_NONE;
+        } else {
+          GPR_ASSERT(remaining > p->frame_size);
+          if (GRPC_ERROR_NONE !=
+              (grpc_chttp2_incoming_byte_stream_push(
+                  exec_ctx, p->parsing_frame,
+                  grpc_slice_sub(slice, (size_t)(cur - beg),
+                                 (size_t)(cur + p->frame_size - beg)),
+                  slice_out))) {
+            grpc_slice_unref_internal(exec_ctx, slice);
+            return error;
+          }
+          if (GRPC_ERROR_NONE !=
+              (error = grpc_chttp2_incoming_byte_stream_finished(
+                   exec_ctx, p->parsing_frame, GRPC_ERROR_NONE, true))) {
+            grpc_slice_unref_internal(exec_ctx, slice);
+            return error;
+          }
+          p->parsing_frame = NULL;
+          p->state = GRPC_CHTTP2_DATA_FH_0;
+          cur += p->frame_size;
+          grpc_slice_buffer_undo_take_first(
+              &s->unprocessed_incoming_frames_buffer,
+              grpc_slice_sub(slice, (size_t)(cur - beg), (size_t)(end - beg)));
+          grpc_slice_unref_internal(exec_ctx, slice);
+          return GRPC_ERROR_NONE;
+        }
+      }
+    }
   }
 
-  switch (p->state) {
-    case GRPC_CHTTP2_DATA_ERROR:
-      p->state = GRPC_CHTTP2_DATA_ERROR;
-      return GRPC_ERROR_REF(p->error);
-    fh_0:
-    case GRPC_CHTTP2_DATA_FH_0:
-      s->stats.incoming.framing_bytes++;
-      p->frame_type = *cur;
-      switch (p->frame_type) {
-        case 0:
-          p->is_frame_compressed = 0; /* GPR_FALSE */
-          break;
-        case 1:
-          p->is_frame_compressed = 1; /* GPR_TRUE */
-          break;
-        default:
-          gpr_asprintf(&msg, "Bad GRPC frame type 0x%02x", p->frame_type);
-          p->error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg);
-          p->error = grpc_error_set_int(p->error, GRPC_ERROR_INT_STREAM_ID,
-                                        (intptr_t)s->id);
-          gpr_free(msg);
-          msg = grpc_dump_slice(slice, GPR_DUMP_HEX | GPR_DUMP_ASCII);
-          p->error = grpc_error_set_str(p->error, GRPC_ERROR_STR_RAW_BYTES,
-                                        grpc_slice_from_copied_string(msg));
-          gpr_free(msg);
-          p->error =
-              grpc_error_set_int(p->error, GRPC_ERROR_INT_OFFSET, cur - beg);
-          p->state = GRPC_CHTTP2_DATA_ERROR;
-          return GRPC_ERROR_REF(p->error);
-      }
-      if (++cur == end) {
-        p->state = GRPC_CHTTP2_DATA_FH_1;
-        return GRPC_ERROR_NONE;
-      }
-    /* fallthrough */
-    case GRPC_CHTTP2_DATA_FH_1:
-      s->stats.incoming.framing_bytes++;
-      p->frame_size = ((uint32_t)*cur) << 24;
-      if (++cur == end) {
-        p->state = GRPC_CHTTP2_DATA_FH_2;
-        return GRPC_ERROR_NONE;
-      }
-    /* fallthrough */
-    case GRPC_CHTTP2_DATA_FH_2:
-      s->stats.incoming.framing_bytes++;
-      p->frame_size |= ((uint32_t)*cur) << 16;
-      if (++cur == end) {
-        p->state = GRPC_CHTTP2_DATA_FH_3;
-        return GRPC_ERROR_NONE;
-      }
-    /* fallthrough */
-    case GRPC_CHTTP2_DATA_FH_3:
-      s->stats.incoming.framing_bytes++;
-      p->frame_size |= ((uint32_t)*cur) << 8;
-      if (++cur == end) {
-        p->state = GRPC_CHTTP2_DATA_FH_4;
-        return GRPC_ERROR_NONE;
-      }
-    /* fallthrough */
-    case GRPC_CHTTP2_DATA_FH_4:
-      s->stats.incoming.framing_bytes++;
-      p->frame_size |= ((uint32_t)*cur);
-      p->state = GRPC_CHTTP2_DATA_FRAME;
-      ++cur;
-      message_flags = 0;
-      if (p->is_frame_compressed) {
-        message_flags |= GRPC_WRITE_INTERNAL_COMPRESS;
-      }
-      p->parsing_frame = incoming_byte_stream =
-          grpc_chttp2_incoming_byte_stream_create(exec_ctx, t, s, p->frame_size,
-                                                  message_flags);
-    /* fallthrough */
-    case GRPC_CHTTP2_DATA_FRAME:
-      if (cur == end) {
-        return GRPC_ERROR_NONE;
-      }
-      uint32_t remaining = (uint32_t)(end - cur);
-      if (remaining == p->frame_size) {
-        s->stats.incoming.data_bytes += p->frame_size;
-        grpc_chttp2_incoming_byte_stream_push(
-            exec_ctx, p->parsing_frame,
-            grpc_slice_sub(slice, (size_t)(cur - beg), (size_t)(end - beg)));
-        grpc_chttp2_incoming_byte_stream_finished(exec_ctx, p->parsing_frame,
-                                                  GRPC_ERROR_NONE);
-        p->parsing_frame = NULL;
-        p->state = GRPC_CHTTP2_DATA_FH_0;
-        return GRPC_ERROR_NONE;
-      } else if (remaining > p->frame_size) {
-        s->stats.incoming.data_bytes += p->frame_size;
-        grpc_chttp2_incoming_byte_stream_push(
-            exec_ctx, p->parsing_frame,
-            grpc_slice_sub(slice, (size_t)(cur - beg),
-                           (size_t)(cur + p->frame_size - beg)));
-        grpc_chttp2_incoming_byte_stream_finished(exec_ctx, p->parsing_frame,
-                                                  GRPC_ERROR_NONE);
-        p->parsing_frame = NULL;
-        cur += p->frame_size;
-        goto fh_0; /* loop */
-      } else {
-        GPR_ASSERT(remaining <= p->frame_size);
-        grpc_chttp2_incoming_byte_stream_push(
-            exec_ctx, p->parsing_frame,
-            grpc_slice_sub(slice, (size_t)(cur - beg), (size_t)(end - beg)));
-        p->frame_size -= remaining;
-        s->stats.incoming.data_bytes += remaining;
-        return GRPC_ERROR_NONE;
-      }
-  }
-
-  GPR_UNREACHABLE_CODE(
-      return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Should never reach here"));
+  return GRPC_ERROR_NONE;
 }
 
 grpc_error *grpc_chttp2_data_parser_parse(grpc_exec_ctx *exec_ctx, void *parser,
                                           grpc_chttp2_transport *t,
                                           grpc_chttp2_stream *s,
                                           grpc_slice slice, int is_last) {
-  grpc_chttp2_data_parser *p = parser;
-  grpc_error *error = parse_inner(exec_ctx, p, t, s, slice);
+  /* grpc_error *error = parse_inner_buffer(exec_ctx, p, t, s, slice); */
+  s->stats.incoming.framing_bytes += GRPC_SLICE_LENGTH(slice);
+  if (!s->pending_byte_stream) {
+    grpc_slice_ref_internal(slice);
+    grpc_slice_buffer_add(&s->frame_storage, slice);
+    grpc_chttp2_maybe_complete_recv_message(exec_ctx, t, s);
+  } else if (s->on_next) {
+    GPR_ASSERT(s->frame_storage.length == 0);
+    grpc_slice_ref_internal(slice);
+    grpc_slice_buffer_add(&s->unprocessed_incoming_frames_buffer, slice);
+    grpc_closure_sched(exec_ctx, s->on_next, GRPC_ERROR_NONE);
+    s->on_next = NULL;
+  } else {
+    grpc_slice_ref_internal(slice);
+    grpc_slice_buffer_add(&s->frame_storage, slice);
+  }
 
-  if (is_last && p->is_last_frame) {
+  if (is_last && s->received_last_frame) {
     grpc_chttp2_mark_stream_closed(exec_ctx, t, s, true, false,
                                    GRPC_ERROR_NONE);
   }
 
-  return error;
+  return GRPC_ERROR_NONE;
 }
diff --git a/src/core/ext/transport/chttp2/transport/frame_data.h b/src/core/ext/transport/chttp2/transport/frame_data.h
index 264ad14..2fb8983 100644
--- a/src/core/ext/transport/chttp2/transport/frame_data.h
+++ b/src/core/ext/transport/chttp2/transport/frame_data.h
@@ -56,28 +56,16 @@
 typedef struct grpc_chttp2_incoming_byte_stream
     grpc_chttp2_incoming_byte_stream;
 
-typedef struct grpc_chttp2_incoming_frame_queue {
-  grpc_chttp2_incoming_byte_stream *head;
-  grpc_chttp2_incoming_byte_stream *tail;
-} grpc_chttp2_incoming_frame_queue;
-
 typedef struct {
   grpc_chttp2_stream_state state;
-  uint8_t is_last_frame;
   uint8_t frame_type;
   uint32_t frame_size;
   grpc_error *error;
 
-  int is_frame_compressed;
+  bool is_frame_compressed;
   grpc_chttp2_incoming_byte_stream *parsing_frame;
 } grpc_chttp2_data_parser;
 
-void grpc_chttp2_incoming_frame_queue_merge(
-    grpc_chttp2_incoming_frame_queue *head_dst,
-    grpc_chttp2_incoming_frame_queue *tail_src);
-grpc_byte_stream *grpc_chttp2_incoming_frame_queue_pop(
-    grpc_chttp2_incoming_frame_queue *q);
-
 /* initialize per-stream state for data frame parsing */
 grpc_error *grpc_chttp2_data_parser_init(grpc_chttp2_data_parser *parser);
 
@@ -87,7 +75,8 @@
 /* start processing a new data frame */
 grpc_error *grpc_chttp2_data_parser_begin_frame(grpc_chttp2_data_parser *parser,
                                                 uint8_t flags,
-                                                uint32_t stream_id);
+                                                uint32_t stream_id,
+                                                grpc_chttp2_stream *s);
 
 /* handle a slice of a data frame - is_last indicates the last slice of a
    frame */
@@ -101,4 +90,11 @@
                              grpc_transport_one_way_stats *stats,
                              grpc_slice_buffer *outbuf);
 
+grpc_error *deframe_unprocessed_incoming_frames(grpc_exec_ctx *exec_ctx,
+                                                grpc_chttp2_data_parser *p,
+                                                grpc_chttp2_stream *s,
+                                                grpc_slice_buffer *slices,
+                                                grpc_slice *slice_out,
+                                                grpc_byte_stream **stream_out);
+
 #endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_FRAME_DATA_H */
diff --git a/src/core/ext/transport/chttp2/transport/frame_settings.c b/src/core/ext/transport/chttp2/transport/frame_settings.c
index 16881c0..4f2b827 100644
--- a/src/core/ext/transport/chttp2/transport/frame_settings.c
+++ b/src/core/ext/transport/chttp2/transport/frame_settings.c
@@ -46,29 +46,6 @@
 #include "src/core/lib/debug/trace.h"
 #include "src/core/lib/transport/http2_errors.h"
 
-#define MAX_MAX_HEADER_LIST_SIZE (1024 * 1024 * 1024)
-
-/* HTTP/2 mandated initial connection settings */
-const grpc_chttp2_setting_parameters
-    grpc_chttp2_settings_parameters[GRPC_CHTTP2_NUM_SETTINGS] = {
-        {NULL, 0, 0, 0, GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE,
-         GRPC_HTTP2_PROTOCOL_ERROR},
-        {"HEADER_TABLE_SIZE", 4096, 0, 0xffffffff,
-         GRPC_CHTTP2_CLAMP_INVALID_VALUE, GRPC_HTTP2_PROTOCOL_ERROR},
-        {"ENABLE_PUSH", 1, 0, 1, GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE,
-         GRPC_HTTP2_PROTOCOL_ERROR},
-        {"MAX_CONCURRENT_STREAMS", 0xffffffffu, 0, 0xffffffffu,
-         GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE, GRPC_HTTP2_PROTOCOL_ERROR},
-        {"INITIAL_WINDOW_SIZE", 65535, 0, 0x7fffffffu,
-         GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE,
-         GRPC_HTTP2_FLOW_CONTROL_ERROR},
-        {"MAX_FRAME_SIZE", 16384, 16384, 16777215,
-         GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE, GRPC_HTTP2_PROTOCOL_ERROR},
-        {"MAX_HEADER_LIST_SIZE", MAX_MAX_HEADER_LIST_SIZE, 0,
-         MAX_MAX_HEADER_LIST_SIZE, GRPC_CHTTP2_CLAMP_INVALID_VALUE,
-         GRPC_HTTP2_PROTOCOL_ERROR},
-};
-
 static uint8_t *fill_header(uint8_t *out, uint32_t length, uint8_t flags) {
   *out++ = (uint8_t)(length >> 16);
   *out++ = (uint8_t)(length >> 8);
@@ -98,9 +75,8 @@
 
   for (i = 0; i < count; i++) {
     if (new[i] != old[i] || (force_mask & (1u << i)) != 0) {
-      GPR_ASSERT(i);
-      *p++ = (uint8_t)(i >> 8);
-      *p++ = (uint8_t)(i);
+      *p++ = (uint8_t)(grpc_setting_id_to_wire_id[i] >> 8);
+      *p++ = (uint8_t)(grpc_setting_id_to_wire_id[i]);
       *p++ = (uint8_t)(new[i] >> 24);
       *p++ = (uint8_t)(new[i] >> 16);
       *p++ = (uint8_t)(new[i] >> 8);
@@ -154,6 +130,7 @@
   const uint8_t *cur = GRPC_SLICE_START_PTR(slice);
   const uint8_t *end = GRPC_SLICE_END_PTR(slice);
   char *msg;
+  grpc_chttp2_setting_id id;
 
   if (parser->is_ack) {
     return GRPC_ERROR_NONE;
@@ -216,9 +193,9 @@
         parser->value |= *cur;
         cur++;
 
-        if (parser->id > 0 && parser->id < GRPC_CHTTP2_NUM_SETTINGS) {
+        if (grpc_wire_id_to_setting_id(parser->id, &id)) {
           const grpc_chttp2_setting_parameters *sp =
-              &grpc_chttp2_settings_parameters[parser->id];
+              &grpc_chttp2_settings_parameters[id];
           if (parser->value < sp->min_value || parser->value > sp->max_value) {
             switch (sp->invalid_value_behavior) {
               case GRPC_CHTTP2_CLAMP_INVALID_VALUE:
@@ -237,19 +214,19 @@
                 return err;
             }
           }
-          if (parser->id == GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE &&
-              parser->incoming_settings[parser->id] != parser->value) {
+          if (id == GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE &&
+              parser->incoming_settings[id] != parser->value) {
             t->initial_window_update +=
-                (int64_t)parser->value - parser->incoming_settings[parser->id];
+                (int64_t)parser->value - parser->incoming_settings[id];
             if (grpc_http_trace) {
               gpr_log(GPR_DEBUG, "adding %d for initial_window change",
                       (int)t->initial_window_update);
             }
           }
-          parser->incoming_settings[parser->id] = parser->value;
+          parser->incoming_settings[id] = parser->value;
           if (grpc_http_trace) {
-            gpr_log(GPR_DEBUG, "CHTTP2:%s:%s: got setting %d = %d",
-                    t->is_client ? "CLI" : "SVR", t->peer_string, parser->id,
+            gpr_log(GPR_DEBUG, "CHTTP2:%s:%s: got setting %s = %d",
+                    t->is_client ? "CLI" : "SVR", t->peer_string, sp->name,
                     parser->value);
           }
         } else if (grpc_http_trace) {
diff --git a/src/core/ext/transport/chttp2/transport/frame_settings.h b/src/core/ext/transport/chttp2/transport/frame_settings.h
index 4413779..2a85d0d 100644
--- a/src/core/ext/transport/chttp2/transport/frame_settings.h
+++ b/src/core/ext/transport/chttp2/transport/frame_settings.h
@@ -37,6 +37,7 @@
 #include <grpc/slice.h>
 #include <grpc/support/port_platform.h>
 #include "src/core/ext/transport/chttp2/transport/frame.h"
+#include "src/core/ext/transport/chttp2/transport/http2_settings.h"
 #include "src/core/lib/iomgr/exec_ctx.h"
 
 typedef enum {
@@ -48,17 +49,6 @@
   GRPC_CHTTP2_SPS_VAL3
 } grpc_chttp2_settings_parse_state;
 
-/* The things HTTP/2 defines as connection level settings */
-typedef enum {
-  GRPC_CHTTP2_SETTINGS_HEADER_TABLE_SIZE = 1,
-  GRPC_CHTTP2_SETTINGS_ENABLE_PUSH = 2,
-  GRPC_CHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS = 3,
-  GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE = 4,
-  GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE = 5,
-  GRPC_CHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE = 6,
-  GRPC_CHTTP2_NUM_SETTINGS
-} grpc_chttp2_setting_id;
-
 typedef struct {
   grpc_chttp2_settings_parse_state state;
   uint32_t *target_settings;
@@ -68,24 +58,6 @@
   uint32_t incoming_settings[GRPC_CHTTP2_NUM_SETTINGS];
 } grpc_chttp2_settings_parser;
 
-typedef enum {
-  GRPC_CHTTP2_CLAMP_INVALID_VALUE,
-  GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE
-} grpc_chttp2_invalid_value_behavior;
-
-typedef struct {
-  const char *name;
-  uint32_t default_value;
-  uint32_t min_value;
-  uint32_t max_value;
-  grpc_chttp2_invalid_value_behavior invalid_value_behavior;
-  uint32_t error_value;
-} grpc_chttp2_setting_parameters;
-
-/* HTTP/2 mandated connection setting parameters */
-extern const grpc_chttp2_setting_parameters
-    grpc_chttp2_settings_parameters[GRPC_CHTTP2_NUM_SETTINGS];
-
 /* Create a settings frame by diffing old & new, and updating old to be new */
 grpc_slice grpc_chttp2_settings_create(uint32_t *old, const uint32_t *newval,
                                        uint32_t force_mask, size_t count);
diff --git a/src/core/ext/transport/chttp2/transport/hpack_encoder.c b/src/core/ext/transport/chttp2/transport/hpack_encoder.c
index 84586cd..b1bc677 100644
--- a/src/core/ext/transport/chttp2/transport/hpack_encoder.c
+++ b/src/core/ext/transport/chttp2/transport/hpack_encoder.c
@@ -86,6 +86,7 @@
   grpc_transport_one_way_stats *stats;
   /* maximum size of a frame */
   size_t max_frame_size;
+  bool use_true_binary_metadata;
 } framer_state;
 
 /* fills p (which is expected to be 9 bytes long) with a data frame header */
@@ -290,86 +291,113 @@
                            len);
 }
 
-static grpc_slice get_wire_value(grpc_mdelem elem, uint8_t *huffman_prefix) {
+typedef struct {
+  grpc_slice data;
+  uint8_t huffman_prefix;
+  bool insert_null_before_wire_value;
+} wire_value;
+
+static wire_value get_wire_value(grpc_mdelem elem, bool true_binary_enabled) {
   if (grpc_is_binary_header(GRPC_MDKEY(elem))) {
-    *huffman_prefix = 0x80;
-    return grpc_chttp2_base64_encode_and_huffman_compress(GRPC_MDVALUE(elem));
+    if (true_binary_enabled) {
+      return (wire_value){
+          .huffman_prefix = 0x00,
+          .insert_null_before_wire_value = true,
+          .data = grpc_slice_ref_internal(GRPC_MDVALUE(elem)),
+      };
+    } else {
+      return (wire_value){
+          .huffman_prefix = 0x80,
+          .insert_null_before_wire_value = false,
+          .data = grpc_chttp2_base64_encode_and_huffman_compress(
+              GRPC_MDVALUE(elem)),
+      };
+    }
+  } else {
+    /* TODO(ctiller): opportunistically compress non-binary headers */
+    return (wire_value){
+        .huffman_prefix = 0x00,
+        .insert_null_before_wire_value = false,
+        .data = grpc_slice_ref_internal(GRPC_MDVALUE(elem)),
+    };
   }
-  /* TODO(ctiller): opportunistically compress non-binary headers */
-  *huffman_prefix = 0x00;
-  return grpc_slice_ref_internal(GRPC_MDVALUE(elem));
+}
+
+static size_t wire_value_length(wire_value v) {
+  return GPR_SLICE_LENGTH(v.data) + v.insert_null_before_wire_value;
+}
+
+static void add_wire_value(framer_state *st, wire_value v) {
+  if (v.insert_null_before_wire_value) *add_tiny_header_data(st, 1) = 0;
+  add_header_data(st, v.data);
 }
 
 static void emit_lithdr_incidx(grpc_chttp2_hpack_compressor *c,
                                uint32_t key_index, grpc_mdelem elem,
                                framer_state *st) {
   uint32_t len_pfx = GRPC_CHTTP2_VARINT_LENGTH(key_index, 2);
-  uint8_t huffman_prefix;
-  grpc_slice value_slice = get_wire_value(elem, &huffman_prefix);
-  size_t len_val = GRPC_SLICE_LENGTH(value_slice);
+  wire_value value = get_wire_value(elem, st->use_true_binary_metadata);
+  size_t len_val = wire_value_length(value);
   uint32_t len_val_len;
   GPR_ASSERT(len_val <= UINT32_MAX);
   len_val_len = GRPC_CHTTP2_VARINT_LENGTH((uint32_t)len_val, 1);
   GRPC_CHTTP2_WRITE_VARINT(key_index, 2, 0x40,
                            add_tiny_header_data(st, len_pfx), len_pfx);
-  GRPC_CHTTP2_WRITE_VARINT((uint32_t)len_val, 1, huffman_prefix,
+  GRPC_CHTTP2_WRITE_VARINT((uint32_t)len_val, 1, value.huffman_prefix,
                            add_tiny_header_data(st, len_val_len), len_val_len);
-  add_header_data(st, value_slice);
+  add_wire_value(st, value);
 }
 
 static void emit_lithdr_noidx(grpc_chttp2_hpack_compressor *c,
                               uint32_t key_index, grpc_mdelem elem,
                               framer_state *st) {
   uint32_t len_pfx = GRPC_CHTTP2_VARINT_LENGTH(key_index, 4);
-  uint8_t huffman_prefix;
-  grpc_slice value_slice = get_wire_value(elem, &huffman_prefix);
-  size_t len_val = GRPC_SLICE_LENGTH(value_slice);
+  wire_value value = get_wire_value(elem, st->use_true_binary_metadata);
+  size_t len_val = wire_value_length(value);
   uint32_t len_val_len;
   GPR_ASSERT(len_val <= UINT32_MAX);
   len_val_len = GRPC_CHTTP2_VARINT_LENGTH((uint32_t)len_val, 1);
   GRPC_CHTTP2_WRITE_VARINT(key_index, 4, 0x00,
                            add_tiny_header_data(st, len_pfx), len_pfx);
-  GRPC_CHTTP2_WRITE_VARINT((uint32_t)len_val, 1, huffman_prefix,
+  GRPC_CHTTP2_WRITE_VARINT((uint32_t)len_val, 1, value.huffman_prefix,
                            add_tiny_header_data(st, len_val_len), len_val_len);
-  add_header_data(st, value_slice);
+  add_wire_value(st, value);
 }
 
 static void emit_lithdr_incidx_v(grpc_chttp2_hpack_compressor *c,
                                  grpc_mdelem elem, framer_state *st) {
   uint32_t len_key = (uint32_t)GRPC_SLICE_LENGTH(GRPC_MDKEY(elem));
-  uint8_t huffman_prefix;
-  grpc_slice value_slice = get_wire_value(elem, &huffman_prefix);
-  uint32_t len_val = (uint32_t)GRPC_SLICE_LENGTH(value_slice);
+  wire_value value = get_wire_value(elem, st->use_true_binary_metadata);
+  uint32_t len_val = (uint32_t)wire_value_length(value);
   uint32_t len_key_len = GRPC_CHTTP2_VARINT_LENGTH(len_key, 1);
   uint32_t len_val_len = GRPC_CHTTP2_VARINT_LENGTH(len_val, 1);
   GPR_ASSERT(len_key <= UINT32_MAX);
-  GPR_ASSERT(GRPC_SLICE_LENGTH(value_slice) <= UINT32_MAX);
+  GPR_ASSERT(wire_value_length(value) <= UINT32_MAX);
   *add_tiny_header_data(st, 1) = 0x40;
   GRPC_CHTTP2_WRITE_VARINT(len_key, 1, 0x00,
                            add_tiny_header_data(st, len_key_len), len_key_len);
   add_header_data(st, grpc_slice_ref_internal(GRPC_MDKEY(elem)));
-  GRPC_CHTTP2_WRITE_VARINT(len_val, 1, huffman_prefix,
+  GRPC_CHTTP2_WRITE_VARINT(len_val, 1, value.huffman_prefix,
                            add_tiny_header_data(st, len_val_len), len_val_len);
-  add_header_data(st, value_slice);
+  add_wire_value(st, value);
 }
 
 static void emit_lithdr_noidx_v(grpc_chttp2_hpack_compressor *c,
                                 grpc_mdelem elem, framer_state *st) {
   uint32_t len_key = (uint32_t)GRPC_SLICE_LENGTH(GRPC_MDKEY(elem));
-  uint8_t huffman_prefix;
-  grpc_slice value_slice = get_wire_value(elem, &huffman_prefix);
-  uint32_t len_val = (uint32_t)GRPC_SLICE_LENGTH(value_slice);
+  wire_value value = get_wire_value(elem, st->use_true_binary_metadata);
+  uint32_t len_val = (uint32_t)wire_value_length(value);
   uint32_t len_key_len = GRPC_CHTTP2_VARINT_LENGTH(len_key, 1);
   uint32_t len_val_len = GRPC_CHTTP2_VARINT_LENGTH(len_val, 1);
   GPR_ASSERT(len_key <= UINT32_MAX);
-  GPR_ASSERT(GRPC_SLICE_LENGTH(value_slice) <= UINT32_MAX);
+  GPR_ASSERT(wire_value_length(value) <= UINT32_MAX);
   *add_tiny_header_data(st, 1) = 0x00;
   GRPC_CHTTP2_WRITE_VARINT(len_key, 1, 0x00,
                            add_tiny_header_data(st, len_key_len), len_key_len);
   add_header_data(st, grpc_slice_ref_internal(GRPC_MDKEY(elem)));
-  GRPC_CHTTP2_WRITE_VARINT(len_val, 1, huffman_prefix,
+  GRPC_CHTTP2_WRITE_VARINT(len_val, 1, value.huffman_prefix,
                            add_tiny_header_data(st, len_val_len), len_val_len);
-  add_header_data(st, value_slice);
+  add_wire_value(st, value);
 }
 
 static void emit_advertise_table_size_change(grpc_chttp2_hpack_compressor *c,
@@ -595,23 +623,22 @@
 
 void grpc_chttp2_encode_header(grpc_exec_ctx *exec_ctx,
                                grpc_chttp2_hpack_compressor *c,
-                               uint32_t stream_id,
-                               grpc_metadata_batch *metadata, int is_eof,
-                               size_t max_frame_size,
-                               grpc_transport_one_way_stats *stats,
+                               grpc_metadata_batch *metadata,
+                               const grpc_encode_header_options *options,
                                grpc_slice_buffer *outbuf) {
   framer_state st;
   grpc_linked_mdelem *l;
   gpr_timespec deadline;
 
-  GPR_ASSERT(stream_id != 0);
+  GPR_ASSERT(options->stream_id != 0);
 
   st.seen_regular_header = 0;
-  st.stream_id = stream_id;
+  st.stream_id = options->stream_id;
   st.output = outbuf;
   st.is_first_frame = 1;
-  st.stats = stats;
-  st.max_frame_size = max_frame_size;
+  st.stats = options->stats;
+  st.max_frame_size = options->max_frame_size;
+  st.use_true_binary_metadata = options->use_true_binary_metadata;
 
   /* Encode a metadata batch; store the returned values, representing
      a metadata element that needs to be unreffed back into the metadata
@@ -630,5 +657,5 @@
     deadline_enc(exec_ctx, c, deadline, &st);
   }
 
-  finish_frame(&st, 1, is_eof);
+  finish_frame(&st, 1, options->is_eof);
 }
diff --git a/src/core/ext/transport/chttp2/transport/hpack_encoder.h b/src/core/ext/transport/chttp2/transport/hpack_encoder.h
index 83ba5b1..6ce3209 100644
--- a/src/core/ext/transport/chttp2/transport/hpack_encoder.h
+++ b/src/core/ext/transport/chttp2/transport/hpack_encoder.h
@@ -90,11 +90,18 @@
 void grpc_chttp2_hpack_compressor_set_max_usable_size(
     grpc_chttp2_hpack_compressor *c, uint32_t max_table_size);
 
+typedef struct {
+  uint32_t stream_id;
+  bool is_eof;
+  bool use_true_binary_metadata;
+  size_t max_frame_size;
+  grpc_transport_one_way_stats *stats;
+} grpc_encode_header_options;
+
 void grpc_chttp2_encode_header(grpc_exec_ctx *exec_ctx,
-                               grpc_chttp2_hpack_compressor *c, uint32_t id,
-                               grpc_metadata_batch *metadata, int is_eof,
-                               size_t max_frame_size,
-                               grpc_transport_one_way_stats *stats,
+                               grpc_chttp2_hpack_compressor *c,
+                               grpc_metadata_batch *metadata,
+                               const grpc_encode_header_options *options,
                                grpc_slice_buffer *outbuf);
 
 #endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_HPACK_ENCODER_H */
diff --git a/src/core/ext/transport/chttp2/transport/hpack_parser.c b/src/core/ext/transport/chttp2/transport/hpack_parser.c
index 5099d73..1846a85 100644
--- a/src/core/ext/transport/chttp2/transport/hpack_parser.c
+++ b/src/core/ext/transport/chttp2/transport/hpack_parser.c
@@ -38,11 +38,6 @@
 #include <stddef.h>
 #include <string.h>
 
-/* This is here for grpc_is_binary_header
- * TODO(murgatroid99): Remove this
- */
-#include <grpc/grpc.h>
-
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/port_platform.h>
@@ -55,13 +50,11 @@
 #include "src/core/lib/support/string.h"
 #include "src/core/lib/transport/http2_errors.h"
 
-/* TODO(ctiller): remove before submission */
-#include "src/core/lib/slice/slice_string_helpers.h"
-
 extern int grpc_http_trace;
 
 typedef enum {
   NOT_BINARY,
+  BINARY_BEGIN,
   B64_BYTE0,
   B64_BYTE1,
   B64_BYTE2,
@@ -1325,6 +1318,19 @@
     case NOT_BINARY:
       append_bytes(str, cur, (size_t)(end - cur));
       return GRPC_ERROR_NONE;
+    case BINARY_BEGIN:
+      if (cur == end) {
+        p->binary = BINARY_BEGIN;
+        return GRPC_ERROR_NONE;
+      }
+      if (*cur == 0) {
+        /* 'true-binary' case */
+        ++cur;
+        p->binary = NOT_BINARY;
+        append_bytes(str, cur, (size_t)(end - cur));
+        return GRPC_ERROR_NONE;
+      }
+    /* fallthrough */
     b64_byte0:
     case B64_BYTE0:
       if (cur == end) {
@@ -1409,6 +1415,8 @@
   switch ((binary_state)p->binary) {
     case NOT_BINARY:
       break;
+    case BINARY_BEGIN:
+      break;
     case B64_BYTE0:
       break;
     case B64_BYTE1:
@@ -1571,7 +1579,7 @@
                                       const uint8_t *cur, const uint8_t *end,
                                       bool is_binary) {
   return begin_parse_string(exec_ctx, p, cur, end,
-                            is_binary ? B64_BYTE0 : NOT_BINARY, &p->value);
+                            is_binary ? BINARY_BEGIN : NOT_BINARY, &p->value);
 }
 
 static grpc_error *parse_value_string_with_indexed_key(
diff --git a/src/core/ext/transport/chttp2/transport/http2_settings.c b/src/core/ext/transport/chttp2/transport/http2_settings.c
new file mode 100644
index 0000000..d490510
--- /dev/null
+++ b/src/core/ext/transport/chttp2/transport/http2_settings.c
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2017, 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.
+ */
+
+/*
+ * Automatically generated by tools/codegen/core/gen_settings_ids.py
+ */
+
+#include "src/core/ext/transport/chttp2/transport/http2_settings.h"
+
+#include <grpc/support/useful.h>
+#include "src/core/lib/transport/http2_errors.h"
+
+const uint16_t grpc_setting_id_to_wire_id[] = {1, 2, 3, 4, 5, 6, 65027};
+
+bool grpc_wire_id_to_setting_id(uint32_t wire_id, grpc_chttp2_setting_id *out) {
+  uint32_t i = wire_id - 1;
+  uint32_t x = i % 256;
+  uint32_t y = i / 256;
+  uint32_t h = x;
+  switch (y) {
+    case 254:
+      h += 4;
+      break;
+  }
+  *out = (grpc_chttp2_setting_id)h;
+  return h < GPR_ARRAY_SIZE(grpc_setting_id_to_wire_id) &&
+         grpc_setting_id_to_wire_id[h] == wire_id;
+}
+
+const grpc_chttp2_setting_parameters
+    grpc_chttp2_settings_parameters[GRPC_CHTTP2_NUM_SETTINGS] = {
+        {"HEADER_TABLE_SIZE", 4096u, 0u, 4294967295u,
+         GRPC_CHTTP2_CLAMP_INVALID_VALUE, GRPC_HTTP2_PROTOCOL_ERROR},
+        {"ENABLE_PUSH", 1u, 0u, 1u, GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE,
+         GRPC_HTTP2_PROTOCOL_ERROR},
+        {"MAX_CONCURRENT_STREAMS", 4294967295u, 0u, 4294967295u,
+         GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE, GRPC_HTTP2_PROTOCOL_ERROR},
+        {"INITIAL_WINDOW_SIZE", 65535u, 0u, 2147483647u,
+         GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE,
+         GRPC_HTTP2_FLOW_CONTROL_ERROR},
+        {"MAX_FRAME_SIZE", 16384u, 16384u, 16777215u,
+         GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE, GRPC_HTTP2_PROTOCOL_ERROR},
+        {"MAX_HEADER_LIST_SIZE", 16777216u, 0u, 16777216u,
+         GRPC_CHTTP2_CLAMP_INVALID_VALUE, GRPC_HTTP2_PROTOCOL_ERROR},
+        {"GRPC_ALLOW_TRUE_BINARY_METADATA", 0u, 0u, 1u,
+         GRPC_CHTTP2_CLAMP_INVALID_VALUE, GRPC_HTTP2_PROTOCOL_ERROR},
+};
diff --git a/src/core/ext/transport/chttp2/transport/http2_settings.h b/src/core/ext/transport/chttp2/transport/http2_settings.h
new file mode 100644
index 0000000..9781cdc
--- /dev/null
+++ b/src/core/ext/transport/chttp2/transport/http2_settings.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2017, 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.
+ */
+
+/*
+ * Automatically generated by tools/codegen/core/gen_settings_ids.py
+ */
+
+#ifndef GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_HTTP2_SETTINGS_H
+#define GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_HTTP2_SETTINGS_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+typedef enum {
+  GRPC_CHTTP2_SETTINGS_HEADER_TABLE_SIZE = 0,               /* wire id 1 */
+  GRPC_CHTTP2_SETTINGS_ENABLE_PUSH = 1,                     /* wire id 2 */
+  GRPC_CHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS = 2,          /* wire id 3 */
+  GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE = 3,             /* wire id 4 */
+  GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE = 4,                  /* wire id 5 */
+  GRPC_CHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE = 5,            /* wire id 6 */
+  GRPC_CHTTP2_SETTINGS_GRPC_ALLOW_TRUE_BINARY_METADATA = 6, /* wire id 65027 */
+} grpc_chttp2_setting_id;
+
+#define GRPC_CHTTP2_NUM_SETTINGS 7
+extern const uint16_t grpc_setting_id_to_wire_id[];
+
+bool grpc_wire_id_to_setting_id(uint32_t wire_id, grpc_chttp2_setting_id *out);
+
+typedef enum {
+  GRPC_CHTTP2_CLAMP_INVALID_VALUE,
+  GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE
+} grpc_chttp2_invalid_value_behavior;
+
+typedef struct {
+  const char *name;
+  uint32_t default_value;
+  uint32_t min_value;
+  uint32_t max_value;
+  grpc_chttp2_invalid_value_behavior invalid_value_behavior;
+  uint32_t error_value;
+} grpc_chttp2_setting_parameters;
+
+extern const grpc_chttp2_setting_parameters
+    grpc_chttp2_settings_parameters[GRPC_CHTTP2_NUM_SETTINGS];
+
+#endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_HTTP2_SETTINGS_H */
diff --git a/src/core/ext/transport/chttp2/transport/internal.h b/src/core/ext/transport/chttp2/transport/internal.h
index 6eb848b..0aaa4ae 100644
--- a/src/core/ext/transport/chttp2/transport/internal.h
+++ b/src/core/ext/transport/chttp2/transport/internal.h
@@ -195,22 +195,20 @@
 struct grpc_chttp2_incoming_byte_stream {
   grpc_byte_stream base;
   gpr_refcount refs;
-  struct grpc_chttp2_incoming_byte_stream *next_message;
-  grpc_error *error;
 
-  grpc_chttp2_transport *transport;
-  grpc_chttp2_stream *stream;
-  bool is_tail;
+  grpc_chttp2_transport *transport; /* immutable */
+  grpc_chttp2_stream *stream;       /* immutable */
 
-  gpr_mu slice_mu;  // protects slices, on_next
-  grpc_slice_buffer slices;
-  grpc_closure *on_next;
-  grpc_slice *next;
+  /* Accessed only by transport thread when stream->pending_byte_stream == false
+   * Accessed only by application thread when stream->pending_byte_stream ==
+   * true */
   uint32_t remaining_bytes;
 
+  /* Accessed only by transport thread when stream->pending_byte_stream == false
+   * Accessed only by application thread when stream->pending_byte_stream ==
+   * true */
   struct {
     grpc_closure closure;
-    grpc_slice *slice;
     size_t max_size_hint;
     grpc_closure *on_complete;
   } next_action;
@@ -222,6 +220,7 @@
   GRPC_CHTTP2_KEEPALIVE_STATE_WAITING,
   GRPC_CHTTP2_KEEPALIVE_STATE_PINGING,
   GRPC_CHTTP2_KEEPALIVE_STATE_DYING,
+  GRPC_CHTTP2_KEEPALIVE_STATE_DISABLED,
 } grpc_chttp2_keepalive_state;
 
 struct grpc_chttp2_transport {
@@ -445,8 +444,8 @@
   uint32_t id;
 
   /** window available for us to send to peer, over or under the initial window
-    * size of the transport... ie:
-    * outgoing_window = outgoing_window_delta + transport.initial_window_size */
+   * size of the transport... ie:
+   * outgoing_window = outgoing_window_delta + transport.initial_window_size */
   int64_t outgoing_window_delta;
   /** things the upper layers would like to send */
   grpc_metadata_batch *send_initial_metadata;
@@ -473,9 +472,6 @@
   grpc_transport_stream_stats *collecting_stats;
   grpc_transport_stream_stats stats;
 
-  /** number of streams that are currently being read */
-  gpr_refcount active_streams;
-
   /** Is this stream closed for writing. */
   bool write_closed;
   /** Is this stream reading half-closed. */
@@ -499,7 +495,17 @@
 
   grpc_chttp2_incoming_metadata_buffer metadata_buffer[2];
 
-  grpc_chttp2_incoming_frame_queue incoming_frames;
+  grpc_slice_buffer frame_storage; /* protected by t combiner */
+
+  /* Accessed only by transport thread when stream->pending_byte_stream == false
+   * Accessed only by application thread when stream->pending_byte_stream ==
+   * true */
+  grpc_slice_buffer unprocessed_incoming_frames_buffer;
+  grpc_closure *on_next;    /* protected by t combiner */
+  bool pending_byte_stream; /* protected by t combiner */
+  grpc_closure reset_byte_stream;
+  grpc_error *byte_stream_error; /* protected by t combiner */
+  bool received_last_frame;      /* protected by t combiner */
 
   gpr_timespec deadline;
 
@@ -512,6 +518,9 @@
    * incoming_window = incoming_window_delta + transport.initial_window_size */
   int64_t incoming_window_delta;
   /** parsing state for data frames */
+  /* Accessed only by transport thread when stream->pending_byte_stream == false
+   * Accessed only by application thread when stream->pending_byte_stream ==
+   * true */
   grpc_chttp2_data_parser data_parser;
   /** number of bytes received - reset at end of parse thread execution */
   int64_t received_bytes;
@@ -790,10 +799,13 @@
 grpc_chttp2_incoming_byte_stream *grpc_chttp2_incoming_byte_stream_create(
     grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, grpc_chttp2_stream *s,
     uint32_t frame_size, uint32_t flags);
-void grpc_chttp2_incoming_byte_stream_push(grpc_exec_ctx *exec_ctx,
-                                           grpc_chttp2_incoming_byte_stream *bs,
-                                           grpc_slice slice);
-void grpc_chttp2_incoming_byte_stream_finished(
+grpc_error *grpc_chttp2_incoming_byte_stream_push(
+    grpc_exec_ctx *exec_ctx, grpc_chttp2_incoming_byte_stream *bs,
+    grpc_slice slice, grpc_slice *slice_out);
+grpc_error *grpc_chttp2_incoming_byte_stream_finished(
+    grpc_exec_ctx *exec_ctx, grpc_chttp2_incoming_byte_stream *bs,
+    grpc_error *error, bool reset_on_error);
+void grpc_chttp2_incoming_byte_stream_notify(
     grpc_exec_ctx *exec_ctx, grpc_chttp2_incoming_byte_stream *bs,
     grpc_error *error);
 
diff --git a/src/core/ext/transport/chttp2/transport/parsing.c b/src/core/ext/transport/chttp2/transport/parsing.c
index 7e457ce..638b137 100644
--- a/src/core/ext/transport/chttp2/transport/parsing.c
+++ b/src/core/ext/transport/chttp2/transport/parsing.c
@@ -458,12 +458,13 @@
     return init_skip_frame_parser(exec_ctx, t, 0);
   }
   if (err == GRPC_ERROR_NONE) {
-    err = grpc_chttp2_data_parser_begin_frame(&s->data_parser,
-                                              t->incoming_frame_flags, s->id);
+    err = grpc_chttp2_data_parser_begin_frame(
+        &s->data_parser, t->incoming_frame_flags, s->id, s);
   }
 error_handler:
   if (err == GRPC_ERROR_NONE) {
     t->incoming_stream = s;
+    /* t->parser = grpc_chttp2_data_parser_parse;*/
     t->parser = grpc_chttp2_data_parser_parse;
     t->parser_data = &s->data_parser;
     return GRPC_ERROR_NONE;
diff --git a/src/core/ext/transport/chttp2/transport/writing.c b/src/core/ext/transport/chttp2/transport/writing.c
index be41b3d..069780a 100644
--- a/src/core/ext/transport/chttp2/transport/writing.c
+++ b/src/core/ext/transport/chttp2/transport/writing.c
@@ -219,10 +219,18 @@
 
     /* send initial metadata if it's available */
     if (!sent_initial_metadata && s->send_initial_metadata) {
-      grpc_chttp2_encode_header(
-          exec_ctx, &t->hpack_compressor, s->id, s->send_initial_metadata, 0,
-          t->settings[GRPC_ACKED_SETTINGS][GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE],
-          &s->stats.outgoing, &t->outbuf);
+      grpc_encode_header_options hopt = {
+          .stream_id = s->id,
+          .is_eof = false,
+          .use_true_binary_metadata =
+              t->settings
+                  [GRPC_PEER_SETTINGS]
+                  [GRPC_CHTTP2_SETTINGS_GRPC_ALLOW_TRUE_BINARY_METADATA] != 0,
+          .max_frame_size = t->settings[GRPC_PEER_SETTINGS]
+                                       [GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE],
+          .stats = &s->stats.outgoing};
+      grpc_chttp2_encode_header(exec_ctx, &t->hpack_compressor,
+                                s->send_initial_metadata, &hopt, &t->outbuf);
       s->send_initial_metadata = NULL;
       s->sent_initial_metadata = true;
       sent_initial_metadata = true;
@@ -259,7 +267,7 @@
                 (int64_t)t->settings[GRPC_PEER_SETTINGS]
                                     [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]);
         uint32_t max_outgoing = (uint32_t)GPR_MIN(
-            t->settings[GRPC_ACKED_SETTINGS]
+            t->settings[GRPC_PEER_SETTINGS]
                        [GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE],
             GPR_MIN(stream_outgoing_window, t->outgoing_window));
         if (max_outgoing > 0) {
@@ -315,11 +323,21 @@
           grpc_chttp2_encode_data(s->id, &s->flow_controlled_buffer, 0, true,
                                   &s->stats.outgoing, &t->outbuf);
         } else {
-          grpc_chttp2_encode_header(
-              exec_ctx, &t->hpack_compressor, s->id, s->send_trailing_metadata,
-              true, t->settings[GRPC_ACKED_SETTINGS]
-                               [GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE],
-              &s->stats.outgoing, &t->outbuf);
+          grpc_encode_header_options hopt = {
+              .stream_id = s->id,
+              .is_eof = true,
+              .use_true_binary_metadata =
+                  t->settings
+                      [GRPC_PEER_SETTINGS]
+                      [GRPC_CHTTP2_SETTINGS_GRPC_ALLOW_TRUE_BINARY_METADATA] !=
+                  0,
+              .max_frame_size =
+                  t->settings[GRPC_PEER_SETTINGS]
+                             [GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE],
+              .stats = &s->stats.outgoing};
+          grpc_chttp2_encode_header(exec_ctx, &t->hpack_compressor,
+                                    s->send_trailing_metadata, &hopt,
+                                    &t->outbuf);
         }
         s->send_trailing_metadata = NULL;
         s->sent_trailing_metadata = true;
diff --git a/src/core/ext/transport/cronet/transport/cronet_transport.c b/src/core/ext/transport/cronet/transport/cronet_transport.c
index 88335ec..7896c70 100644
--- a/src/core/ext/transport/cronet/transport/cronet_transport.c
+++ b/src/core/ext/transport/cronet/transport/cronet_transport.c
@@ -973,9 +973,20 @@
       grpc_slice_buffer write_slice_buffer;
       grpc_slice slice;
       grpc_slice_buffer_init(&write_slice_buffer);
-      grpc_byte_stream_next(
-          NULL, stream_op->payload->send_message.send_message, &slice,
-          stream_op->payload->send_message.send_message->length, NULL);
+      if (1 != grpc_byte_stream_next(
+                   exec_ctx, stream_op->payload->send_message.send_message,
+                   stream_op->payload->send_message.send_message->length,
+                   NULL)) {
+        /* Should never reach here */
+        GPR_ASSERT(false);
+      }
+      if (GRPC_ERROR_NONE !=
+          grpc_byte_stream_pull(exec_ctx,
+                                stream_op->payload->send_message.send_message,
+                                &slice)) {
+        /* Should never reach here */
+        GPR_ASSERT(false);
+      }
       grpc_slice_buffer_add(&write_slice_buffer, slice);
       if (write_slice_buffer.count != 1) {
         /* Empty request not handled yet */
diff --git a/src/core/lib/channel/channel_args.c b/src/core/lib/channel/channel_args.c
index a6d124c..238d176 100644
--- a/src/core/lib/channel/channel_args.c
+++ b/src/core/lib/channel/channel_args.c
@@ -31,17 +31,18 @@
  *
  */
 
-#include "src/core/lib/channel/channel_args.h"
-#include <grpc/grpc.h>
-#include "src/core/lib/support/string.h"
+#include <limits.h>
+#include <string.h>
 
 #include <grpc/compression.h>
+#include <grpc/grpc.h>
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
 #include <grpc/support/useful.h>
 
-#include <string.h>
+#include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/support/string.h"
 
 static grpc_arg copy_arg(const grpc_arg *src) {
   grpc_arg dst;
@@ -329,7 +330,9 @@
   return NULL;
 }
 
-int grpc_channel_arg_get_integer(grpc_arg *arg, grpc_integer_options options) {
+int grpc_channel_arg_get_integer(const grpc_arg *arg,
+                                 const grpc_integer_options options) {
+  if (arg == NULL) return options.default_value;
   if (arg->type != GRPC_ARG_INTEGER) {
     gpr_log(GPR_ERROR, "%s ignored: it must be an integer", arg->key);
     return options.default_value;
@@ -347,9 +350,25 @@
   return arg->value.integer;
 }
 
+bool grpc_channel_arg_get_bool(const grpc_arg *arg, bool default_value) {
+  if (arg == NULL) return default_value;
+  if (arg->type != GRPC_ARG_INTEGER) {
+    gpr_log(GPR_ERROR, "%s ignored: it must be an integer", arg->key);
+    return default_value;
+  }
+  switch (arg->value.integer) {
+    case 0:
+      return false;
+    case 1:
+      return true;
+    default:
+      gpr_log(GPR_ERROR, "%s treated as bool but set to %d (assuming true)",
+              arg->key, arg->value.integer);
+      return true;
+  }
+}
+
 bool grpc_channel_args_want_minimal_stack(const grpc_channel_args *args) {
-  const grpc_arg *arg = grpc_channel_args_find(args, GRPC_ARG_MINIMAL_STACK);
-  if (arg == NULL) return false;
-  if (arg->type == GRPC_ARG_INTEGER && arg->value.integer == 0) return false;
-  return true;
+  return grpc_channel_arg_get_bool(
+      grpc_channel_args_find(args, GRPC_ARG_MINIMAL_STACK), false);
 }
diff --git a/src/core/lib/channel/channel_args.h b/src/core/lib/channel/channel_args.h
index 158cda5..f0f603e 100644
--- a/src/core/lib/channel/channel_args.h
+++ b/src/core/lib/channel/channel_args.h
@@ -120,7 +120,11 @@
   int min_value;
   int max_value;
 } grpc_integer_options;
+
 /** Returns the value of \a arg, subject to the contraints in \a options. */
-int grpc_channel_arg_get_integer(grpc_arg *arg, grpc_integer_options options);
+int grpc_channel_arg_get_integer(const grpc_arg *arg,
+                                 const grpc_integer_options options);
+
+bool grpc_channel_arg_get_bool(const grpc_arg *arg, bool default_value);
 
 #endif /* GRPC_CORE_LIB_CHANNEL_CHANNEL_ARGS_H */
diff --git a/src/core/lib/channel/channel_stack_builder.c b/src/core/lib/channel/channel_stack_builder.c
index b515b73..88c02ed 100644
--- a/src/core/lib/channel/channel_stack_builder.c
+++ b/src/core/lib/channel/channel_stack_builder.c
@@ -113,6 +113,17 @@
   return create_iterator_at_filter_node(builder, &builder->end);
 }
 
+bool grpc_channel_stack_builder_iterator_is_end(
+    grpc_channel_stack_builder_iterator *iterator) {
+  return iterator->node == &iterator->builder->end;
+}
+
+const char *grpc_channel_stack_builder_iterator_filter_name(
+    grpc_channel_stack_builder_iterator *iterator) {
+  if (iterator->node->filter == NULL) return NULL;
+  return iterator->node->filter->name;
+}
+
 bool grpc_channel_stack_builder_move_next(
     grpc_channel_stack_builder_iterator *iterator) {
   if (iterator->node == &iterator->builder->end) return false;
diff --git a/src/core/lib/channel/channel_stack_builder.h b/src/core/lib/channel/channel_stack_builder.h
index 8adf38e..c78111b 100644
--- a/src/core/lib/channel/channel_stack_builder.h
+++ b/src/core/lib/channel/channel_stack_builder.h
@@ -98,6 +98,10 @@
 bool grpc_channel_stack_builder_iterator_is_end(
     grpc_channel_stack_builder_iterator *iterator);
 
+/// What is the name of the filter at this iterator position?
+const char *grpc_channel_stack_builder_iterator_filter_name(
+    grpc_channel_stack_builder_iterator *iterator);
+
 /// Move an iterator to the next item
 bool grpc_channel_stack_builder_move_next(
     grpc_channel_stack_builder_iterator *iterator);
diff --git a/src/core/lib/channel/context.h b/src/core/lib/channel/context.h
index 2c1174c..6c931ad 100644
--- a/src/core/lib/channel/context.h
+++ b/src/core/lib/channel/context.h
@@ -50,9 +50,6 @@
   /// Reserved for traffic_class_context.
   GRPC_CONTEXT_TRAFFIC,
 
-  /// Costs for Load Reporting.
-  GRPC_CONTEXT_LR_COST,
-
   GRPC_CONTEXT_COUNT
 } grpc_context_index;
 
diff --git a/src/core/lib/iomgr/closure.c b/src/core/lib/iomgr/closure.c
index 6633fb6..8ef0b21 100644
--- a/src/core/lib/iomgr/closure.c
+++ b/src/core/lib/iomgr/closure.c
@@ -45,6 +45,9 @@
   closure->cb = cb;
   closure->cb_arg = cb_arg;
   closure->scheduler = scheduler;
+#ifndef NDEBUG
+  closure->scheduled = false;
+#endif
   return closure;
 }
 
@@ -137,6 +140,10 @@
                         grpc_error *error) {
   GPR_TIMER_BEGIN("grpc_closure_sched", 0);
   if (c != NULL) {
+#ifndef NDEBUG
+    GPR_ASSERT(!c->scheduled);
+    c->scheduled = true;
+#endif
     assert(c->cb);
     c->scheduler->vtable->sched(exec_ctx, c, error);
   } else {
@@ -149,6 +156,10 @@
   grpc_closure *c = list->head;
   while (c != NULL) {
     grpc_closure *next = c->next_data.next;
+#ifndef NDEBUG
+    GPR_ASSERT(!c->scheduled);
+    c->scheduled = true;
+#endif
     assert(c->cb);
     c->scheduler->vtable->sched(exec_ctx, c, c->error_data.error);
     c = next;
diff --git a/src/core/lib/iomgr/closure.h b/src/core/lib/iomgr/closure.h
index 2510d50..2bedbf0 100644
--- a/src/core/lib/iomgr/closure.h
+++ b/src/core/lib/iomgr/closure.h
@@ -99,6 +99,10 @@
     grpc_error *error;
     uintptr_t scratch;
   } error_data;
+
+#ifndef NDEBUG
+  bool scheduled;
+#endif
 };
 
 /** Initializes \a closure with \a cb and \a cb_arg. Returns \a closure. */
diff --git a/src/core/lib/iomgr/combiner.c b/src/core/lib/iomgr/combiner.c
index 2bc476b..05cdbda 100644
--- a/src/core/lib/iomgr/combiner.c
+++ b/src/core/lib/iomgr/combiner.c
@@ -319,6 +319,9 @@
     GPR_TIMER_BEGIN("combiner.exec1", 0);
     grpc_closure *cl = (grpc_closure *)n;
     error_data err = unpack_error_data(cl->error_data.scratch);
+#ifndef NDEBUG
+    cl->scheduled = false;
+#endif
     cl->cb(exec_ctx, cl->cb_arg, err.error);
     if (err.covered_by_poller) {
       gpr_atm_no_barrier_fetch_add(&lock->elements_covered_by_poller, -1);
@@ -337,6 +340,9 @@
           gpr_log(GPR_DEBUG, "C:%p execute_final[%d] c=%p", lock, loops, c));
       grpc_closure *next = c->next_data.next;
       grpc_error *error = c->error_data.error;
+#ifndef NDEBUG
+      c->scheduled = false;
+#endif
       c->cb(exec_ctx, c->cb_arg, error);
       GRPC_ERROR_UNREF(error);
       c = next;
diff --git a/src/core/lib/iomgr/ev_epoll_linux.c b/src/core/lib/iomgr/ev_epoll_linux.c
index 4a0f913..e603a75 100644
--- a/src/core/lib/iomgr/ev_epoll_linux.c
+++ b/src/core/lib/iomgr/ev_epoll_linux.c
@@ -1348,6 +1348,9 @@
       }
       grpc_closure *c = (grpc_closure *)n;
       grpc_error *error = c->error_data.error;
+#ifndef NDEBUG
+      c->scheduled = false;
+#endif
       c->cb(exec_ctx, c->cb_arg, error);
       GRPC_ERROR_UNREF(error);
       return true;
diff --git a/src/core/lib/iomgr/exec_ctx.c b/src/core/lib/iomgr/exec_ctx.c
index 83bb436..2532a70 100644
--- a/src/core/lib/iomgr/exec_ctx.c
+++ b/src/core/lib/iomgr/exec_ctx.c
@@ -73,6 +73,9 @@
         grpc_closure *next = c->next_data.next;
         grpc_error *error = c->error_data.error;
         did_something = true;
+#ifndef NDEBUG
+        c->scheduled = false;
+#endif
         c->cb(exec_ctx, c->cb_arg, error);
         GRPC_ERROR_UNREF(error);
         c = next;
@@ -93,6 +96,9 @@
 
 static void exec_ctx_run(grpc_exec_ctx *exec_ctx, grpc_closure *closure,
                          grpc_error *error) {
+#ifndef NDEBUG
+  closure->scheduled = false;
+#endif
   closure->cb(exec_ctx, closure->cb_arg, error);
   GRPC_ERROR_UNREF(error);
 }
diff --git a/src/core/lib/iomgr/executor.c b/src/core/lib/iomgr/executor.c
index ae3e2ea..75fd5b1 100644
--- a/src/core/lib/iomgr/executor.c
+++ b/src/core/lib/iomgr/executor.c
@@ -83,6 +83,9 @@
       while (c != NULL) {
         grpc_closure *next = c->next_data.next;
         grpc_error *error = c->error_data.error;
+#ifndef NDEBUG
+        c->scheduled = false;
+#endif
         c->cb(&exec_ctx, c->cb_arg, error);
         GRPC_ERROR_UNREF(error);
         c = next;
@@ -146,6 +149,9 @@
   while (c != NULL) {
     grpc_closure *next = c->next_data.next;
     grpc_error *error = c->error_data.error;
+#ifndef NDEBUG
+    c->scheduled = false;
+#endif
     c->cb(exec_ctx, c->cb_arg, error);
     GRPC_ERROR_UNREF(error);
     c = next;
diff --git a/src/core/lib/iomgr/resolve_address_uv.c b/src/core/lib/iomgr/resolve_address_uv.c
index 102d1aa..6b46876 100644
--- a/src/core/lib/iomgr/resolve_address_uv.c
+++ b/src/core/lib/iomgr/resolve_address_uv.c
@@ -69,8 +69,9 @@
         int retry_status;
         uv_getaddrinfo_t *req = gpr_malloc(sizeof(uv_getaddrinfo_t));
         req->data = r;
+        r->port = svc[i][1];
         retry_status = uv_getaddrinfo(uv_default_loop(), req, getaddrinfo_cb,
-                                      r->host, svc[i][1], r->hints);
+                                      r->host, r->port, r->hints);
         if (retry_status < 0 || getaddrinfo_cb == NULL) {
           // The callback will not be called
           gpr_free(req);
diff --git a/src/core/lib/iomgr/sockaddr_utils.c b/src/core/lib/iomgr/sockaddr_utils.c
index 9d27326..a6a4cac 100644
--- a/src/core/lib/iomgr/sockaddr_utils.c
+++ b/src/core/lib/iomgr/sockaddr_utils.c
@@ -55,7 +55,9 @@
   GPR_ASSERT(resolved_addr != resolved_addr4_out);
   const struct sockaddr *addr = (const struct sockaddr *)resolved_addr->addr;
   struct sockaddr_in *addr4_out =
-      (struct sockaddr_in *)resolved_addr4_out->addr;
+      resolved_addr4_out == NULL
+          ? NULL
+          : (struct sockaddr_in *)resolved_addr4_out->addr;
   if (addr->sa_family == AF_INET6) {
     const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6 *)addr;
     if (memcmp(addr6->sin6_addr.s6_addr, kV4MappedPrefix,
diff --git a/src/core/lib/iomgr/sockaddr_utils.h b/src/core/lib/iomgr/sockaddr_utils.h
index 2b22f11..be3ea20 100644
--- a/src/core/lib/iomgr/sockaddr_utils.h
+++ b/src/core/lib/iomgr/sockaddr_utils.h
@@ -50,7 +50,7 @@
                               grpc_resolved_address *addr6_out);
 
 /* If addr is ::, 0.0.0.0, or ::ffff:0.0.0.0, writes the port number to
-   *port_out (if not NULL) and returns true, otherwise returns false. */
+ *port_out (if not NULL) and returns true, otherwise returns false. */
 int grpc_sockaddr_is_wildcard(const grpc_resolved_address *addr, int *port_out);
 
 /* Writes 0.0.0.0:port and [::]:port to separate sockaddrs. */
diff --git a/src/core/lib/iomgr/udp_server.c b/src/core/lib/iomgr/udp_server.c
index 60579e1..ca283d0 100644
--- a/src/core/lib/iomgr/udp_server.c
+++ b/src/core/lib/iomgr/udp_server.c
@@ -79,10 +79,15 @@
   grpc_resolved_address addr;
   grpc_closure read_closure;
   grpc_closure write_closure;
+  // To be called when corresponding QuicGrpcServer closes all active
+  // connections.
+  grpc_closure orphan_fd_closure;
   grpc_closure destroyed_closure;
   grpc_udp_server_read_cb read_cb;
   grpc_udp_server_write_cb write_cb;
   grpc_udp_server_orphan_cb orphan_cb;
+  // True if orphan_cb is trigered.
+  bool orphan_notified;
 
   struct grpc_udp_listener *next;
 };
@@ -146,6 +151,14 @@
   return s;
 }
 
+static void shutdown_fd(grpc_exec_ctx *exec_ctx, void *fd, grpc_error *error) {
+  grpc_fd_shutdown(exec_ctx, (grpc_fd *)fd, GRPC_ERROR_REF(error));
+}
+
+static void dummy_cb(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
+  // No-op.
+}
+
 static void finish_shutdown(grpc_exec_ctx *exec_ctx, grpc_udp_server *s) {
   if (s->shutdown_complete != NULL) {
     grpc_closure_sched(exec_ctx, s->shutdown_complete, GRPC_ERROR_NONE);
@@ -195,12 +208,16 @@
 
       grpc_closure_init(&sp->destroyed_closure, destroyed_port, s,
                         grpc_schedule_on_exec_ctx);
-
-      /* Call the orphan_cb to signal that the FD is about to be closed and
-       * should no longer be used. */
-      GPR_ASSERT(sp->orphan_cb);
-      sp->orphan_cb(exec_ctx, sp->emfd, sp->server->user_data);
-
+      if (!sp->orphan_notified) {
+        /* Call the orphan_cb to signal that the FD is about to be closed and
+         * should no longer be used. Because at this point, all listening ports
+         * have been shutdown already, no need to shutdown again.*/
+        grpc_closure_init(&sp->orphan_fd_closure, dummy_cb, sp->emfd,
+                          grpc_schedule_on_exec_ctx);
+        GPR_ASSERT(sp->orphan_cb);
+        sp->orphan_cb(exec_ctx, sp->emfd, &sp->orphan_fd_closure,
+                      sp->server->user_data);
+      }
       grpc_fd_orphan(exec_ctx, sp->emfd, &sp->destroyed_closure, NULL,
                      "udp_listener_shutdown");
     }
@@ -225,9 +242,11 @@
   if (s->active_ports) {
     for (sp = s->head; sp; sp = sp->next) {
       GPR_ASSERT(sp->orphan_cb);
-      sp->orphan_cb(exec_ctx, sp->emfd, sp->server->user_data);
-      grpc_fd_shutdown(exec_ctx, sp->emfd, GRPC_ERROR_CREATE_FROM_STATIC_STRING(
-                                               "Server destroyed"));
+      grpc_closure_init(&sp->orphan_fd_closure, shutdown_fd, sp->emfd,
+                        grpc_schedule_on_exec_ctx);
+      sp->orphan_cb(exec_ctx, sp->emfd, &sp->orphan_fd_closure,
+                    sp->server->user_data);
+      sp->orphan_notified = true;
     }
     gpr_mu_unlock(&s->mu);
   } else {
@@ -391,6 +410,7 @@
     sp->read_cb = read_cb;
     sp->write_cb = write_cb;
     sp->orphan_cb = orphan_cb;
+    sp->orphan_notified = false;
     GPR_ASSERT(sp->emfd);
     gpr_mu_unlock(&s->mu);
     gpr_free(name);
diff --git a/src/core/lib/iomgr/udp_server.h b/src/core/lib/iomgr/udp_server.h
index 9df3fe4..8006037 100644
--- a/src/core/lib/iomgr/udp_server.h
+++ b/src/core/lib/iomgr/udp_server.h
@@ -55,7 +55,9 @@
 
 /* Called when the grpc_fd is about to be orphaned (and the FD closed). */
 typedef void (*grpc_udp_server_orphan_cb)(grpc_exec_ctx *exec_ctx,
-                                          grpc_fd *emfd, void *user_data);
+                                          grpc_fd *emfd,
+                                          grpc_closure *shutdown_fd_callback,
+                                          void *user_data);
 
 /* Create a server, initially not bound to any ports */
 grpc_udp_server *grpc_udp_server_create(const grpc_channel_args *args);
diff --git a/src/core/lib/security/credentials/credentials.c b/src/core/lib/security/credentials/credentials.c
index 52b8014..d89da47 100644
--- a/src/core/lib/security/credentials/credentials.c
+++ b/src/core/lib/security/credentials/credentials.c
@@ -37,7 +37,6 @@
 #include <string.h>
 
 #include "src/core/lib/channel/channel_args.h"
-#include "src/core/lib/channel/http_client_filter.h"
 #include "src/core/lib/http/httpcli.h"
 #include "src/core/lib/http/parser.h"
 #include "src/core/lib/iomgr/executor.h"
diff --git a/src/core/lib/security/credentials/fake/fake_credentials.c b/src/core/lib/security/credentials/fake/fake_credentials.c
index 68636ba..3fdb67f 100644
--- a/src/core/lib/security/credentials/fake/fake_credentials.c
+++ b/src/core/lib/security/credentials/fake/fake_credentials.c
@@ -39,11 +39,15 @@
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
 
+#include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/iomgr/executor.h"
 #include "src/core/lib/support/string.h"
 
 /* -- Fake transport security credentials. -- */
 
+#define GRPC_ARG_FAKE_SECURITY_EXPECTED_TARGETS \
+  "grpc.fake_security.expected_targets"
+
 static grpc_security_status fake_transport_security_create_security_connector(
     grpc_exec_ctx *exec_ctx, grpc_channel_credentials *c,
     grpc_call_credentials *call_creds, const char *target,
@@ -88,6 +92,25 @@
   return c;
 }
 
+grpc_arg grpc_fake_transport_expected_targets_arg(char *expected_targets) {
+  grpc_arg arg;
+  arg.type = GRPC_ARG_STRING;
+  arg.key = GRPC_ARG_FAKE_SECURITY_EXPECTED_TARGETS;
+  arg.value.string = expected_targets;
+  return arg;
+}
+
+const char *grpc_fake_transport_get_expected_targets(
+    const grpc_channel_args *args) {
+  const grpc_arg *expected_target_arg =
+      grpc_channel_args_find(args, GRPC_ARG_FAKE_SECURITY_EXPECTED_TARGETS);
+  if (expected_target_arg != NULL &&
+      expected_target_arg->type == GRPC_ARG_STRING) {
+    return expected_target_arg->value.string;
+  }
+  return NULL;
+}
+
 /* -- Metadata-only test credentials. -- */
 
 static void md_only_test_destruct(grpc_exec_ctx *exec_ctx,
diff --git a/src/core/lib/security/credentials/fake/fake_credentials.h b/src/core/lib/security/credentials/fake/fake_credentials.h
index 0fe9841..a28b545 100644
--- a/src/core/lib/security/credentials/fake/fake_credentials.h
+++ b/src/core/lib/security/credentials/fake/fake_credentials.h
@@ -38,10 +38,17 @@
 
 /* -- Fake transport security credentials. -- */
 
+/* Creates a fake transport security credentials object for testing. */
+grpc_channel_credentials *grpc_fake_transport_security_credentials_create(void);
+
+/* Creates a fake server transport security credentials object for testing. */
+grpc_server_credentials *grpc_fake_transport_security_server_credentials_create(
+    void);
+
 /* Used to verify the target names given to the fake transport security
  * connector.
  *
- * Its syntax by example:
+ * The syntax of \a expected_targets by example:
  * For LB channels:
  *     "backend_target_1,backend_target_2,...;lb_target_1,lb_target_2,..."
  * For regular channels:
@@ -50,15 +57,11 @@
  * That is to say, LB channels have a heading list of LB targets separated from
  * the list of backend targets by a semicolon. For non-LB channels, only the
  * latter is present. */
-#define GRPC_ARG_FAKE_SECURITY_EXPECTED_TARGETS \
-  "grpc.test_only.fake_security.expected_target"
+grpc_arg grpc_fake_transport_expected_targets_arg(char *expected_targets);
 
-/* Creates a fake transport security credentials object for testing. */
-grpc_channel_credentials *grpc_fake_transport_security_credentials_create(void);
-
-/* Creates a fake server transport security credentials object for testing. */
-grpc_server_credentials *grpc_fake_transport_security_server_credentials_create(
-    void);
+/* Return the value associated with the expected targets channel arg or NULL */
+const char *grpc_fake_transport_get_expected_targets(
+    const grpc_channel_args *args);
 
 /* --  Metadata-only Test credentials. -- */
 
diff --git a/src/core/lib/security/credentials/ssl/ssl_credentials.c b/src/core/lib/security/credentials/ssl/ssl_credentials.c
index 4b17ac8..b63bb6b 100644
--- a/src/core/lib/security/credentials/ssl/ssl_credentials.c
+++ b/src/core/lib/security/credentials/ssl/ssl_credentials.c
@@ -36,7 +36,6 @@
 #include <string.h>
 
 #include "src/core/lib/channel/channel_args.h"
-#include "src/core/lib/channel/http_client_filter.h"
 #include "src/core/lib/surface/api_trace.h"
 
 #include <grpc/support/alloc.h>
diff --git a/src/core/lib/security/transport/security_connector.c b/src/core/lib/security/transport/security_connector.c
index dbe3263..b15196e 100644
--- a/src/core/lib/security/transport/security_connector.c
+++ b/src/core/lib/security/transport/security_connector.c
@@ -423,12 +423,8 @@
   c->base.check_call_host = fake_channel_check_call_host;
   c->base.add_handshakers = fake_channel_add_handshakers;
   c->target = gpr_strdup(target);
-  const grpc_arg *expected_target_arg =
-      grpc_channel_args_find(args, GRPC_ARG_FAKE_SECURITY_EXPECTED_TARGETS);
-  if (expected_target_arg != NULL) {
-    GPR_ASSERT(expected_target_arg->type == GRPC_ARG_STRING);
-    c->expected_targets = gpr_strdup(expected_target_arg->value.string);
-  }
+  const char *expected_targets = grpc_fake_transport_get_expected_targets(args);
+  c->expected_targets = gpr_strdup(expected_targets);
   c->is_lb_channel = (grpc_lb_targets_info_find_in_args(args) != NULL);
   return &c->base;
 }
diff --git a/src/core/lib/slice/slice.c b/src/core/lib/slice/slice.c
index 1cddf06..a2fcbbd 100644
--- a/src/core/lib/slice/slice.c
+++ b/src/core/lib/slice/slice.c
@@ -197,6 +197,7 @@
 }
 
 grpc_slice grpc_slice_from_copied_buffer(const char *source, size_t length) {
+  if (length == 0) return grpc_empty_slice();
   grpc_slice slice = grpc_slice_malloc(length);
   memcpy(GRPC_SLICE_START_PTR(slice), source, length);
   return slice;
@@ -382,8 +383,9 @@
 }
 
 int grpc_slice_default_eq_impl(grpc_slice a, grpc_slice b) {
-  return GRPC_SLICE_LENGTH(a) == GRPC_SLICE_LENGTH(b) &&
-         0 == memcmp(GRPC_SLICE_START_PTR(a), GRPC_SLICE_START_PTR(b),
+  if (GRPC_SLICE_LENGTH(a) != GRPC_SLICE_LENGTH(b)) return false;
+  if (GRPC_SLICE_LENGTH(a) == 0) return true;
+  return 0 == memcmp(GRPC_SLICE_START_PTR(a), GRPC_SLICE_START_PTR(b),
                      GRPC_SLICE_LENGTH(a));
 }
 
diff --git a/src/core/lib/surface/call.c b/src/core/lib/surface/call.c
index 97d50a9..3e96d09 100644
--- a/src/core/lib/surface/call.c
+++ b/src/core/lib/surface/call.c
@@ -1187,6 +1187,7 @@
 
 static void continue_receiving_slices(grpc_exec_ctx *exec_ctx,
                                       batch_control *bctl) {
+  grpc_error *error;
   grpc_call *call = bctl->call;
   for (;;) {
     size_t remaining = call->receiving_stream->length -
@@ -1198,11 +1199,22 @@
       finish_batch_step(exec_ctx, bctl);
       return;
     }
-    if (grpc_byte_stream_next(exec_ctx, call->receiving_stream,
-                              &call->receiving_slice, remaining,
+    if (grpc_byte_stream_next(exec_ctx, call->receiving_stream, remaining,
                               &call->receiving_slice_ready)) {
-      grpc_slice_buffer_add(&(*call->receiving_buffer)->data.raw.slice_buffer,
-                            call->receiving_slice);
+      error = grpc_byte_stream_pull(exec_ctx, call->receiving_stream,
+                                    &call->receiving_slice);
+      if (error == GRPC_ERROR_NONE) {
+        grpc_slice_buffer_add(&(*call->receiving_buffer)->data.raw.slice_buffer,
+                              call->receiving_slice);
+      } else {
+        grpc_byte_stream_destroy(exec_ctx, call->receiving_stream);
+        call->receiving_stream = NULL;
+        grpc_byte_buffer_destroy(*call->receiving_buffer);
+        *call->receiving_buffer = NULL;
+        call->receiving_message = 0;
+        finish_batch_step(exec_ctx, bctl);
+        return;
+      }
     } else {
       return;
     }
@@ -1213,12 +1225,24 @@
                                   grpc_error *error) {
   batch_control *bctl = bctlp;
   grpc_call *call = bctl->call;
+  grpc_byte_stream *bs = call->receiving_stream;
+  bool release_error = false;
 
   if (error == GRPC_ERROR_NONE) {
-    grpc_slice_buffer_add(&(*call->receiving_buffer)->data.raw.slice_buffer,
-                          call->receiving_slice);
-    continue_receiving_slices(exec_ctx, bctl);
-  } else {
+    grpc_slice slice;
+    error = grpc_byte_stream_pull(exec_ctx, bs, &slice);
+    if (error == GRPC_ERROR_NONE) {
+      grpc_slice_buffer_add(&(*call->receiving_buffer)->data.raw.slice_buffer,
+                            slice);
+      continue_receiving_slices(exec_ctx, bctl);
+    } else {
+      /* Error returned by grpc_byte_stream_pull needs to be released manually
+       */
+      release_error = true;
+    }
+  }
+
+  if (error != GRPC_ERROR_NONE) {
     if (grpc_trace_operation_failures) {
       GRPC_LOG_IF_ERROR("receiving_slice_ready", GRPC_ERROR_REF(error));
     }
@@ -1226,7 +1250,11 @@
     call->receiving_stream = NULL;
     grpc_byte_buffer_destroy(*call->receiving_buffer);
     *call->receiving_buffer = NULL;
+    call->receiving_message = 0;
     finish_batch_step(exec_ctx, bctl);
+    if (release_error) {
+      GRPC_ERROR_UNREF(error);
+    }
   }
 }
 
diff --git a/src/core/lib/surface/channel_init.c b/src/core/lib/surface/channel_init.c
index 7acb444..20f5753 100644
--- a/src/core/lib/surface/channel_init.c
+++ b/src/core/lib/surface/channel_init.c
@@ -104,30 +104,13 @@
   }
 }
 
-static const char *name_for_type(grpc_channel_stack_type type) {
-  switch (type) {
-    case GRPC_CLIENT_CHANNEL:
-      return "CLIENT_CHANNEL";
-    case GRPC_CLIENT_SUBCHANNEL:
-      return "CLIENT_SUBCHANNEL";
-    case GRPC_SERVER_CHANNEL:
-      return "SERVER_CHANNEL";
-    case GRPC_CLIENT_LAME_CHANNEL:
-      return "CLIENT_LAME_CHANNEL";
-    case GRPC_CLIENT_DIRECT_CHANNEL:
-      return "CLIENT_DIRECT_CHANNEL";
-    case GRPC_NUM_CHANNEL_STACK_TYPES:
-      break;
-  }
-  GPR_UNREACHABLE_CODE(return "UNKNOWN");
-}
-
 bool grpc_channel_init_create_stack(grpc_exec_ctx *exec_ctx,
                                     grpc_channel_stack_builder *builder,
                                     grpc_channel_stack_type type) {
   GPR_ASSERT(g_finalized);
 
-  grpc_channel_stack_builder_set_name(builder, name_for_type(type));
+  grpc_channel_stack_builder_set_name(builder,
+                                      grpc_channel_stack_type_string(type));
 
   for (size_t i = 0; i < g_slots[type].num_slots; i++) {
     const stage_slot *slot = &g_slots[type].slots[i];
diff --git a/src/core/lib/surface/channel_stack_type.c b/src/core/lib/surface/channel_stack_type.c
index c35d603..ed3b53f 100644
--- a/src/core/lib/surface/channel_stack_type.c
+++ b/src/core/lib/surface/channel_stack_type.c
@@ -52,3 +52,21 @@
   }
   GPR_UNREACHABLE_CODE(return true;);
 }
+
+const char *grpc_channel_stack_type_string(grpc_channel_stack_type type) {
+  switch (type) {
+    case GRPC_CLIENT_CHANNEL:
+      return "CLIENT_CHANNEL";
+    case GRPC_CLIENT_SUBCHANNEL:
+      return "CLIENT_SUBCHANNEL";
+    case GRPC_SERVER_CHANNEL:
+      return "SERVER_CHANNEL";
+    case GRPC_CLIENT_LAME_CHANNEL:
+      return "CLIENT_LAME_CHANNEL";
+    case GRPC_CLIENT_DIRECT_CHANNEL:
+      return "CLIENT_DIRECT_CHANNEL";
+    case GRPC_NUM_CHANNEL_STACK_TYPES:
+      break;
+  }
+  GPR_UNREACHABLE_CODE(return "UNKNOWN");
+}
diff --git a/src/core/lib/surface/channel_stack_type.h b/src/core/lib/surface/channel_stack_type.h
index 4eea4f1..ccf4e53 100644
--- a/src/core/lib/surface/channel_stack_type.h
+++ b/src/core/lib/surface/channel_stack_type.h
@@ -55,4 +55,6 @@
 
 bool grpc_channel_stack_type_is_client(grpc_channel_stack_type type);
 
+const char *grpc_channel_stack_type_string(grpc_channel_stack_type type);
+
 #endif /* GRPC_CORE_LIB_SURFACE_CHANNEL_STACK_TYPE_H */
diff --git a/src/core/lib/surface/completion_queue.c b/src/core/lib/surface/completion_queue.c
index 3273add..35e9f7e 100644
--- a/src/core/lib/surface/completion_queue.c
+++ b/src/core/lib/surface/completion_queue.c
@@ -64,6 +64,10 @@
 struct grpc_completion_queue {
   /** owned by pollset */
   gpr_mu *mu;
+
+  grpc_cq_completion_type completion_type;
+  grpc_cq_polling_type polling_type;
+
   /** completed events */
   grpc_cq_completion completed_head;
   grpc_cq_completion *completed_tail;
@@ -79,6 +83,7 @@
   int shutdown_called;
   int is_server_cq;
   /** Can the server cq accept incoming channels */
+  /* TODO: sreek - This will no longer be needed. Use polling_type set */
   int is_non_listening_server_cq;
   int num_pluckers;
   plucker pluckers[GRPC_MAX_COMPLETION_QUEUE_PLUCKERS];
@@ -110,13 +115,17 @@
 static void on_pollset_shutdown_done(grpc_exec_ctx *exec_ctx, void *cc,
                                      grpc_error *error);
 
-grpc_completion_queue *grpc_completion_queue_create(void *reserved) {
+grpc_completion_queue *grpc_completion_queue_create_internal(
+    grpc_cq_completion_type completion_type,
+    grpc_cq_polling_type polling_type) {
   grpc_completion_queue *cc;
-  GPR_ASSERT(!reserved);
 
-  GPR_TIMER_BEGIN("grpc_completion_queue_create", 0);
+  GPR_TIMER_BEGIN("grpc_completion_queue_create_internal", 0);
 
-  GRPC_API_TRACE("grpc_completion_queue_create(reserved=%p)", 1, (reserved));
+  GRPC_API_TRACE(
+      "grpc_completion_queue_create_internal(completion_type=%d, "
+      "polling_type=%d)",
+      2, (completion_type, polling_type));
 
   cc = gpr_zalloc(sizeof(grpc_completion_queue) + grpc_pollset_size());
   grpc_pollset_init(POLLSET_FROM_CQ(cc), &cc->mu);
@@ -125,6 +134,9 @@
   cc->outstanding_tag_capacity = 0;
 #endif
 
+  cc->completion_type = completion_type;
+  cc->polling_type = polling_type;
+
   /* Initial ref is dropped by grpc_completion_queue_shutdown */
   gpr_ref_init(&cc->pending_events, 1);
   /* One for destroy(), one for pollset_shutdown */
@@ -143,11 +155,19 @@
   grpc_closure_init(&cc->pollset_shutdown_done, on_pollset_shutdown_done, cc,
                     grpc_schedule_on_exec_ctx);
 
-  GPR_TIMER_END("grpc_completion_queue_create", 0);
+  GPR_TIMER_END("grpc_completion_queue_create_internal", 0);
 
   return cc;
 }
 
+grpc_cq_completion_type grpc_get_cq_completion_type(grpc_completion_queue *cc) {
+  return cc->completion_type;
+}
+
+grpc_cq_polling_type grpc_get_cq_polling_type(grpc_completion_queue *cc) {
+  return cc->polling_type;
+}
+
 #ifdef GRPC_CQ_REF_COUNT_DEBUG
 void grpc_cq_internal_ref(grpc_completion_queue *cc, const char *reason,
                           const char *file, int line) {
@@ -347,6 +367,13 @@
   grpc_event ret;
   gpr_timespec now;
 
+  if (cc->completion_type != GRPC_CQ_NEXT) {
+    gpr_log(GPR_ERROR,
+            "grpc_completion_queue_next() cannot be called on this completion "
+            "queue since its completion type is not GRPC_CQ_NEXT");
+    abort();
+  }
+
   GPR_TIMER_BEGIN("grpc_completion_queue_next", 0);
 
   GRPC_API_TRACE(
@@ -516,6 +543,13 @@
 
   GPR_TIMER_BEGIN("grpc_completion_queue_pluck", 0);
 
+  if (cc->completion_type != GRPC_CQ_PLUCK) {
+    gpr_log(GPR_ERROR,
+            "grpc_completion_queue_pluck() cannot be called on this completion "
+            "queue since its completion type is not GRPC_CQ_PLUCK");
+    abort();
+  }
+
   if (grpc_cq_pluck_trace) {
     GRPC_API_TRACE(
         "grpc_completion_queue_pluck("
@@ -680,10 +714,14 @@
 }
 
 void grpc_cq_mark_non_listening_server_cq(grpc_completion_queue *cc) {
+  /* TODO: sreek - use cc->polling_type field here and add a validation check
+     (i.e grpc_cq_mark_non_listening_server_cq can only be called on a cc whose
+     polling_type is set to GRPC_CQ_NON_LISTENING */
   cc->is_non_listening_server_cq = 1;
 }
 
 bool grpc_cq_is_non_listening_server_cq(grpc_completion_queue *cc) {
+  /* TODO (sreek) - return (cc->polling_type == GRPC_CQ_NON_LISTENING) */
   return (cc->is_non_listening_server_cq == 1);
 }
 
diff --git a/src/core/lib/surface/completion_queue.h b/src/core/lib/surface/completion_queue.h
index 5d73dd7..1ff3d64 100644
--- a/src/core/lib/surface/completion_queue.h
+++ b/src/core/lib/surface/completion_queue.h
@@ -99,4 +99,10 @@
 void grpc_cq_mark_server_cq(grpc_completion_queue *cc);
 int grpc_cq_is_server_cq(grpc_completion_queue *cc);
 
+grpc_cq_completion_type grpc_get_cq_completion_type(grpc_completion_queue *cc);
+grpc_cq_polling_type grpc_get_cq_polling_type(grpc_completion_queue *cc);
+
+grpc_completion_queue *grpc_completion_queue_create_internal(
+    grpc_cq_completion_type completion_type, grpc_cq_polling_type polling_type);
+
 #endif /* GRPC_CORE_LIB_SURFACE_COMPLETION_QUEUE_H */
diff --git a/src/core/lib/surface/completion_queue_factory.c b/src/core/lib/surface/completion_queue_factory.c
index db67a51..d68b84e 100644
--- a/src/core/lib/surface/completion_queue_factory.c
+++ b/src/core/lib/surface/completion_queue_factory.c
@@ -36,12 +36,15 @@
 
 #include <grpc/support/log.h>
 
-/* TODO (sreek) - Currently this does not use the attributes arg. This will be
-   added in a future PR */
+/*
+ * == Default completion queue factory implementation ==
+ */
+
 static grpc_completion_queue* default_create(
     const grpc_completion_queue_factory* factory,
-    const grpc_completion_queue_attributes* attributes) {
-  return grpc_completion_queue_create(NULL);
+    const grpc_completion_queue_attributes* attr) {
+  return grpc_completion_queue_create_internal(attr->cq_completion_type,
+                                               attr->cq_polling_type);
 }
 
 static grpc_completion_queue_factory_vtable default_vtable = {default_create};
@@ -49,19 +52,24 @@
 static const grpc_completion_queue_factory g_default_cq_factory = {
     "Default Factory", NULL, &default_vtable};
 
+/*
+ * == Completion queue factory APIs
+ */
+
 const grpc_completion_queue_factory* grpc_completion_queue_factory_lookup(
     const grpc_completion_queue_attributes* attributes) {
-  /* As we add more fields to grpc_completion_queue_attributes, we may have to
-     change this assert to:
-         GPR_ASSERT (attributes->version >= 1 &&
-             attributes->version <= GRPC_CQ_CURRENT_VERSION) */
-  GPR_ASSERT(attributes->version == 1);
+  GPR_ASSERT(attributes->version >= 1 &&
+             attributes->version <= GRPC_CQ_CURRENT_VERSION);
 
   /* The default factory can handle version 1 of the attributes structure. We
      may have to change this as more fields are added to the structure */
   return &g_default_cq_factory;
 }
 
+/*
+ * == Completion queue creation APIs ==
+ */
+
 grpc_completion_queue* grpc_completion_queue_create_for_next(void* reserved) {
   GPR_ASSERT(!reserved);
   grpc_completion_queue_attributes attr = {1, GRPC_CQ_NEXT,
@@ -75,3 +83,10 @@
                                            GRPC_CQ_DEFAULT_POLLING};
   return g_default_cq_factory.vtable->create(&g_default_cq_factory, &attr);
 }
+
+grpc_completion_queue* grpc_completion_queue_create(
+    const grpc_completion_queue_factory* factory,
+    const grpc_completion_queue_attributes* attr, void* reserved) {
+  GPR_ASSERT(!reserved);
+  return factory->vtable->create(factory, attr);
+}
diff --git a/src/core/lib/surface/init.c b/src/core/lib/surface/init.c
index 91bd014..4b381b1 100644
--- a/src/core/lib/surface/init.c
+++ b/src/core/lib/surface/init.c
@@ -41,13 +41,8 @@
 #include <grpc/support/log.h>
 #include <grpc/support/time.h>
 #include "src/core/lib/channel/channel_stack.h"
-#include "src/core/lib/channel/compress_filter.h"
 #include "src/core/lib/channel/connected_channel.h"
-#include "src/core/lib/channel/deadline_filter.h"
 #include "src/core/lib/channel/handshaker_registry.h"
-#include "src/core/lib/channel/http_client_filter.h"
-#include "src/core/lib/channel/http_server_filter.h"
-#include "src/core/lib/channel/message_size_filter.h"
 #include "src/core/lib/debug/trace.h"
 #include "src/core/lib/http/parser.h"
 #include "src/core/lib/iomgr/combiner.h"
@@ -95,57 +90,13 @@
       builder, (const grpc_channel_filter *)arg, NULL, NULL);
 }
 
-static bool maybe_add_http_filter(grpc_exec_ctx *exec_ctx,
-                                  grpc_channel_stack_builder *builder,
-                                  void *arg) {
-  grpc_transport *t = grpc_channel_stack_builder_get_transport(builder);
-  if (t && strstr(t->vtable->name, "http")) {
-    return grpc_channel_stack_builder_prepend_filter(
-        builder, (const grpc_channel_filter *)arg, NULL, NULL);
-  }
-  return true;
-}
-
 static void register_builtin_channel_init() {
-  grpc_channel_init_register_stage(
-      GRPC_CLIENT_DIRECT_CHANNEL, GRPC_CHANNEL_INIT_BUILTIN_PRIORITY,
-      prepend_filter, (void *)&grpc_client_deadline_filter);
-  grpc_channel_init_register_stage(
-      GRPC_SERVER_CHANNEL, GRPC_CHANNEL_INIT_BUILTIN_PRIORITY, prepend_filter,
-      (void *)&grpc_server_deadline_filter);
-  grpc_channel_init_register_stage(
-      GRPC_CLIENT_SUBCHANNEL, GRPC_CHANNEL_INIT_BUILTIN_PRIORITY,
-      prepend_filter, (void *)&grpc_message_size_filter);
-  grpc_channel_init_register_stage(
-      GRPC_CLIENT_DIRECT_CHANNEL, GRPC_CHANNEL_INIT_BUILTIN_PRIORITY,
-      prepend_filter, (void *)&grpc_message_size_filter);
-  grpc_channel_init_register_stage(
-      GRPC_SERVER_CHANNEL, GRPC_CHANNEL_INIT_BUILTIN_PRIORITY, prepend_filter,
-      (void *)&grpc_message_size_filter);
-  grpc_channel_init_register_stage(
-      GRPC_CLIENT_CHANNEL, GRPC_CHANNEL_INIT_BUILTIN_PRIORITY, prepend_filter,
-      (void *)&grpc_compress_filter);
-  grpc_channel_init_register_stage(
-      GRPC_CLIENT_DIRECT_CHANNEL, GRPC_CHANNEL_INIT_BUILTIN_PRIORITY,
-      prepend_filter, (void *)&grpc_compress_filter);
-  grpc_channel_init_register_stage(
-      GRPC_SERVER_CHANNEL, GRPC_CHANNEL_INIT_BUILTIN_PRIORITY, prepend_filter,
-      (void *)&grpc_compress_filter);
-  grpc_channel_init_register_stage(
-      GRPC_CLIENT_SUBCHANNEL, GRPC_CHANNEL_INIT_BUILTIN_PRIORITY,
-      maybe_add_http_filter, (void *)&grpc_http_client_filter);
   grpc_channel_init_register_stage(GRPC_CLIENT_SUBCHANNEL,
                                    GRPC_CHANNEL_INIT_BUILTIN_PRIORITY,
                                    grpc_add_connected_filter, NULL);
-  grpc_channel_init_register_stage(
-      GRPC_CLIENT_DIRECT_CHANNEL, GRPC_CHANNEL_INIT_BUILTIN_PRIORITY,
-      maybe_add_http_filter, (void *)&grpc_http_client_filter);
   grpc_channel_init_register_stage(GRPC_CLIENT_DIRECT_CHANNEL,
                                    GRPC_CHANNEL_INIT_BUILTIN_PRIORITY,
                                    grpc_add_connected_filter, NULL);
-  grpc_channel_init_register_stage(
-      GRPC_SERVER_CHANNEL, GRPC_CHANNEL_INIT_BUILTIN_PRIORITY,
-      maybe_add_http_filter, (void *)&grpc_http_server_filter);
   grpc_channel_init_register_stage(GRPC_SERVER_CHANNEL,
                                    GRPC_CHANNEL_INIT_BUILTIN_PRIORITY,
                                    grpc_add_connected_filter, NULL);
@@ -189,7 +140,6 @@
     grpc_register_tracer("channel_stack_builder",
                          &grpc_trace_channel_stack_builder);
     grpc_register_tracer("http1", &grpc_http1_trace);
-    grpc_register_tracer("compression", &grpc_compression_trace);
     grpc_register_tracer("queue_pluck", &grpc_cq_pluck_trace);
     grpc_register_tracer("combiner", &grpc_combiner_trace);
     grpc_register_tracer("server_channel", &grpc_server_channel_trace);
diff --git a/src/core/lib/surface/server.c b/src/core/lib/surface/server.c
index 191ee75..38800ea 100644
--- a/src/core/lib/surface/server.c
+++ b/src/core/lib/surface/server.c
@@ -44,6 +44,7 @@
 
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/channel/connected_channel.h"
+#include "src/core/lib/iomgr/executor.h"
 #include "src/core/lib/iomgr/iomgr.h"
 #include "src/core/lib/slice/slice_internal.h"
 #include "src/core/lib/support/stack_lockfree.h"
@@ -211,6 +212,11 @@
   gpr_mu mu_global; /* mutex for server and channel state */
   gpr_mu mu_call;   /* mutex for call-specific state */
 
+  /* startup synchronization: flag is protected by mu_global, signals whether
+     we are doing the listener start routine or not */
+  bool starting;
+  gpr_cv starting_cv;
+
   registered_method *registered_methods;
   /** one request matcher for unregistered methods */
   request_matcher unregistered_request_matcher;
@@ -388,6 +394,7 @@
   grpc_channel_args_destroy(exec_ctx, server->channel_args);
   gpr_mu_destroy(&server->mu_global);
   gpr_mu_destroy(&server->mu_call);
+  gpr_cv_destroy(&server->starting_cv);
   while ((rm = server->registered_methods) != NULL) {
     server->registered_methods = rm->next;
     if (server->started) {
@@ -1000,6 +1007,15 @@
   GRPC_API_TRACE(
       "grpc_server_register_completion_queue(server=%p, cq=%p, reserved=%p)", 3,
       (server, cq, reserved));
+
+  if (grpc_get_cq_completion_type(cq) != GRPC_CQ_NEXT) {
+    gpr_log(GPR_INFO,
+            "Completion queue which is not of type GRPC_CQ_NEXT is being "
+            "registered as a server-completion-queue");
+    /* Ideally we should log an error and abort but ruby-wrapped-language API
+       calls grpc_completion_queue_pluck() on server completion queues */
+  }
+
   register_completion_queue(server, cq, false, reserved);
 }
 
@@ -1021,6 +1037,7 @@
 
   gpr_mu_init(&server->mu_global);
   gpr_mu_init(&server->mu_call);
+  gpr_cv_init(&server->starting_cv);
 
   /* decremented by grpc_server_destroy */
   gpr_ref_init(&server->internal_refcount, 1);
@@ -1077,8 +1094,22 @@
   return m;
 }
 
+static void start_listeners(grpc_exec_ctx *exec_ctx, void *s,
+                            grpc_error *error) {
+  grpc_server *server = s;
+  for (listener *l = server->listeners; l; l = l->next) {
+    l->start(exec_ctx, server, l->arg, server->pollsets, server->pollset_count);
+  }
+
+  gpr_mu_lock(&server->mu_global);
+  server->starting = false;
+  gpr_cv_signal(&server->starting_cv);
+  gpr_mu_unlock(&server->mu_global);
+
+  server_unref(exec_ctx, server);
+}
+
 void grpc_server_start(grpc_server *server) {
-  listener *l;
   size_t i;
   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
 
@@ -1112,10 +1143,11 @@
                          (size_t)server->max_requested_calls_per_cq, server);
   }
 
-  for (l = server->listeners; l; l = l->next) {
-    l->start(&exec_ctx, server, l->arg, server->pollsets,
-             server->pollset_count);
-  }
+  server_ref(server);
+  server->starting = true;
+  grpc_closure_sched(&exec_ctx, grpc_closure_create(start_listeners, server,
+                                                    grpc_executor_scheduler),
+                     GRPC_ERROR_NONE);
 
   grpc_exec_ctx_finish(&exec_ctx);
 }
@@ -1249,8 +1281,14 @@
   GRPC_API_TRACE("grpc_server_shutdown_and_notify(server=%p, cq=%p, tag=%p)", 3,
                  (server, cq, tag));
 
-  /* lock, and gather up some stuff to do */
+  /* wait for startup to be finished: locks mu_global */
   gpr_mu_lock(&server->mu_global);
+  while (server->starting) {
+    gpr_cv_wait(&server->starting_cv, &server->mu_global,
+                gpr_inf_future(GPR_CLOCK_REALTIME));
+  }
+
+  /* stay locked, and gather up some stuff to do */
   grpc_cq_begin_op(cq, tag);
   if (server->shutdown_published) {
     grpc_cq_end_op(&exec_ctx, cq, tag, GRPC_ERROR_NONE, done_published_shutdown,
diff --git a/src/core/lib/surface/version.c b/src/core/lib/surface/version.c
index ba80bd8..3793845 100644
--- a/src/core/lib/surface/version.c
+++ b/src/core/lib/surface/version.c
@@ -36,6 +36,6 @@
 
 #include <grpc/grpc.h>
 
-const char *grpc_version_string(void) { return "3.0.0-dev"; }
+const char *grpc_version_string(void) { return "4.0.0-dev"; }
 
 const char *grpc_g_stands_for(void) { return "gentle"; }
diff --git a/src/core/lib/transport/byte_stream.c b/src/core/lib/transport/byte_stream.c
index 4d42061..5800c70 100644
--- a/src/core/lib/transport/byte_stream.c
+++ b/src/core/lib/transport/byte_stream.c
@@ -40,10 +40,15 @@
 #include "src/core/lib/slice/slice_internal.h"
 
 int grpc_byte_stream_next(grpc_exec_ctx *exec_ctx,
-                          grpc_byte_stream *byte_stream, grpc_slice *slice,
-                          size_t max_size_hint, grpc_closure *on_complete) {
-  return byte_stream->next(exec_ctx, byte_stream, slice, max_size_hint,
-                           on_complete);
+                          grpc_byte_stream *byte_stream, size_t max_size_hint,
+                          grpc_closure *on_complete) {
+  return byte_stream->next(exec_ctx, byte_stream, max_size_hint, on_complete);
+}
+
+grpc_error *grpc_byte_stream_pull(grpc_exec_ctx *exec_ctx,
+                                  grpc_byte_stream *byte_stream,
+                                  grpc_slice *slice) {
+  return byte_stream->pull(exec_ctx, byte_stream, slice);
 }
 
 void grpc_byte_stream_destroy(grpc_exec_ctx *exec_ctx,
@@ -53,16 +58,24 @@
 
 /* slice_buffer_stream */
 
-static int slice_buffer_stream_next(grpc_exec_ctx *exec_ctx,
-                                    grpc_byte_stream *byte_stream,
-                                    grpc_slice *slice, size_t max_size_hint,
-                                    grpc_closure *on_complete) {
+static bool slice_buffer_stream_next(grpc_exec_ctx *exec_ctx,
+                                     grpc_byte_stream *byte_stream,
+                                     size_t max_size_hint,
+                                     grpc_closure *on_complete) {
+  grpc_slice_buffer_stream *stream = (grpc_slice_buffer_stream *)byte_stream;
+  GPR_ASSERT(stream->cursor < stream->backing_buffer->count);
+  return true;
+}
+
+static grpc_error *slice_buffer_stream_pull(grpc_exec_ctx *exec_ctx,
+                                            grpc_byte_stream *byte_stream,
+                                            grpc_slice *slice) {
   grpc_slice_buffer_stream *stream = (grpc_slice_buffer_stream *)byte_stream;
   GPR_ASSERT(stream->cursor < stream->backing_buffer->count);
   *slice =
       grpc_slice_ref_internal(stream->backing_buffer->slices[stream->cursor]);
   stream->cursor++;
-  return 1;
+  return GRPC_ERROR_NONE;
 }
 
 static void slice_buffer_stream_destroy(grpc_exec_ctx *exec_ctx,
@@ -75,6 +88,7 @@
   stream->base.length = (uint32_t)slice_buffer->length;
   stream->base.flags = flags;
   stream->base.next = slice_buffer_stream_next;
+  stream->base.pull = slice_buffer_stream_pull;
   stream->base.destroy = slice_buffer_stream_destroy;
   stream->backing_buffer = slice_buffer;
   stream->cursor = 0;
diff --git a/src/core/lib/transport/byte_stream.h b/src/core/lib/transport/byte_stream.h
index 1fdd5b4..381c65f 100644
--- a/src/core/lib/transport/byte_stream.h
+++ b/src/core/lib/transport/byte_stream.h
@@ -49,9 +49,10 @@
 struct grpc_byte_stream {
   uint32_t length;
   uint32_t flags;
-  int (*next)(grpc_exec_ctx *exec_ctx, grpc_byte_stream *byte_stream,
-              grpc_slice *slice, size_t max_size_hint,
-              grpc_closure *on_complete);
+  bool (*next)(grpc_exec_ctx *exec_ctx, grpc_byte_stream *byte_stream,
+               size_t max_size_hint, grpc_closure *on_complete);
+  grpc_error *(*pull)(grpc_exec_ctx *exec_ctx, grpc_byte_stream *byte_stream,
+                      grpc_slice *slice);
   void (*destroy)(grpc_exec_ctx *exec_ctx, grpc_byte_stream *byte_stream);
 };
 
@@ -61,12 +62,20 @@
  *
  * max_size_hint can be set as a hint as to the maximum number
  * of bytes that would be acceptable to read.
+ */
+int grpc_byte_stream_next(grpc_exec_ctx *exec_ctx,
+                          grpc_byte_stream *byte_stream, size_t max_size_hint,
+                          grpc_closure *on_complete);
+
+/* returns the next slice in the byte stream when it is ready (indicated by
+ * either grpc_byte_stream_next returning 1 or on_complete passed to
+ * grpc_byte_stream_next is called).
  *
  * once a slice is returned into *slice, it is owned by the caller.
  */
-int grpc_byte_stream_next(grpc_exec_ctx *exec_ctx,
-                          grpc_byte_stream *byte_stream, grpc_slice *slice,
-                          size_t max_size_hint, grpc_closure *on_complete);
+grpc_error *grpc_byte_stream_pull(grpc_exec_ctx *exec_ctx,
+                                  grpc_byte_stream *byte_stream,
+                                  grpc_slice *slice);
 
 void grpc_byte_stream_destroy(grpc_exec_ctx *exec_ctx,
                               grpc_byte_stream *byte_stream);
diff --git a/src/core/lib/transport/pid_controller.c b/src/core/lib/transport/pid_controller.c
index 19cb1c0..c851564 100644
--- a/src/core/lib/transport/pid_controller.c
+++ b/src/core/lib/transport/pid_controller.c
@@ -49,6 +49,7 @@
 
 double grpc_pid_controller_update(grpc_pid_controller *pid_controller,
                                   double error, double dt) {
+  if (dt == 0) return pid_controller->last_control_value;
   /* integrate error using the trapezoid rule */
   pid_controller->error_integral +=
       dt * (pid_controller->last_error + error) * 0.5;
diff --git a/src/core/lib/transport/static_metadata.c b/src/core/lib/transport/static_metadata.c
index c13ba23..862cdaa 100644
--- a/src/core/lib/transport/static_metadata.c
+++ b/src/core/lib/transport/static_metadata.c
@@ -51,67 +51,69 @@
     115, 103, 114, 112, 99,  45,  112, 97,  121, 108, 111, 97,  100, 45,  98,
     105, 110, 103, 114, 112, 99,  45,  101, 110, 99,  111, 100, 105, 110, 103,
     103, 114, 112, 99,  45,  97,  99,  99,  101, 112, 116, 45,  101, 110, 99,
-    111, 100, 105, 110, 103, 99,  111, 110, 116, 101, 110, 116, 45,  116, 121,
-    112, 101, 103, 114, 112, 99,  45,  105, 110, 116, 101, 114, 110, 97,  108,
-    45,  101, 110, 99,  111, 100, 105, 110, 103, 45,  114, 101, 113, 117, 101,
-    115, 116, 117, 115, 101, 114, 45,  97,  103, 101, 110, 116, 104, 111, 115,
-    116, 108, 98,  45,  116, 111, 107, 101, 110, 103, 114, 112, 99,  45,  116,
-    105, 109, 101, 111, 117, 116, 103, 114, 112, 99,  45,  116, 114, 97,  99,
-    105, 110, 103, 45,  98,  105, 110, 103, 114, 112, 99,  45,  115, 116, 97,
-    116, 115, 45,  98,  105, 110, 103, 114, 112, 99,  46,  119, 97,  105, 116,
-    95,  102, 111, 114, 95,  114, 101, 97,  100, 121, 103, 114, 112, 99,  46,
-    116, 105, 109, 101, 111, 117, 116, 103, 114, 112, 99,  46,  109, 97,  120,
-    95,  114, 101, 113, 117, 101, 115, 116, 95,  109, 101, 115, 115, 97,  103,
-    101, 95,  98,  121, 116, 101, 115, 103, 114, 112, 99,  46,  109, 97,  120,
-    95,  114, 101, 115, 112, 111, 110, 115, 101, 95,  109, 101, 115, 115, 97,
-    103, 101, 95,  98,  121, 116, 101, 115, 47,  103, 114, 112, 99,  46,  108,
-    98,  46,  118, 49,  46,  76,  111, 97,  100, 66,  97,  108, 97,  110, 99,
-    101, 114, 47,  66,  97,  108, 97,  110, 99,  101, 76,  111, 97,  100, 48,
-    49,  50,  105, 100, 101, 110, 116, 105, 116, 121, 103, 122, 105, 112, 100,
-    101, 102, 108, 97,  116, 101, 116, 114, 97,  105, 108, 101, 114, 115, 97,
-    112, 112, 108, 105, 99,  97,  116, 105, 111, 110, 47,  103, 114, 112, 99,
-    80,  79,  83,  84,  50,  48,  48,  52,  48,  52,  104, 116, 116, 112, 104,
-    116, 116, 112, 115, 103, 114, 112, 99,  71,  69,  84,  80,  85,  84,  47,
-    47,  105, 110, 100, 101, 120, 46,  104, 116, 109, 108, 50,  48,  52,  50,
-    48,  54,  51,  48,  52,  52,  48,  48,  53,  48,  48,  97,  99,  99,  101,
-    112, 116, 45,  99,  104, 97,  114, 115, 101, 116, 97,  99,  99,  101, 112,
-    116, 45,  101, 110, 99,  111, 100, 105, 110, 103, 103, 122, 105, 112, 44,
-    32,  100, 101, 102, 108, 97,  116, 101, 97,  99,  99,  101, 112, 116, 45,
-    108, 97,  110, 103, 117, 97,  103, 101, 97,  99,  99,  101, 112, 116, 45,
-    114, 97,  110, 103, 101, 115, 97,  99,  99,  101, 112, 116, 97,  99,  99,
-    101, 115, 115, 45,  99,  111, 110, 116, 114, 111, 108, 45,  97,  108, 108,
-    111, 119, 45,  111, 114, 105, 103, 105, 110, 97,  103, 101, 97,  108, 108,
-    111, 119, 97,  117, 116, 104, 111, 114, 105, 122, 97,  116, 105, 111, 110,
-    99,  97,  99,  104, 101, 45,  99,  111, 110, 116, 114, 111, 108, 99,  111,
-    110, 116, 101, 110, 116, 45,  100, 105, 115, 112, 111, 115, 105, 116, 105,
-    111, 110, 99,  111, 110, 116, 101, 110, 116, 45,  101, 110, 99,  111, 100,
-    105, 110, 103, 99,  111, 110, 116, 101, 110, 116, 45,  108, 97,  110, 103,
-    117, 97,  103, 101, 99,  111, 110, 116, 101, 110, 116, 45,  108, 101, 110,
-    103, 116, 104, 99,  111, 110, 116, 101, 110, 116, 45,  108, 111, 99,  97,
-    116, 105, 111, 110, 99,  111, 110, 116, 101, 110, 116, 45,  114, 97,  110,
-    103, 101, 99,  111, 111, 107, 105, 101, 100, 97,  116, 101, 101, 116, 97,
-    103, 101, 120, 112, 101, 99,  116, 101, 120, 112, 105, 114, 101, 115, 102,
-    114, 111, 109, 105, 102, 45,  109, 97,  116, 99,  104, 105, 102, 45,  109,
-    111, 100, 105, 102, 105, 101, 100, 45,  115, 105, 110, 99,  101, 105, 102,
-    45,  110, 111, 110, 101, 45,  109, 97,  116, 99,  104, 105, 102, 45,  114,
-    97,  110, 103, 101, 105, 102, 45,  117, 110, 109, 111, 100, 105, 102, 105,
-    101, 100, 45,  115, 105, 110, 99,  101, 108, 97,  115, 116, 45,  109, 111,
-    100, 105, 102, 105, 101, 100, 108, 105, 110, 107, 108, 111, 99,  97,  116,
-    105, 111, 110, 109, 97,  120, 45,  102, 111, 114, 119, 97,  114, 100, 115,
-    112, 114, 111, 120, 121, 45,  97,  117, 116, 104, 101, 110, 116, 105, 99,
-    97,  116, 101, 112, 114, 111, 120, 121, 45,  97,  117, 116, 104, 111, 114,
-    105, 122, 97,  116, 105, 111, 110, 114, 97,  110, 103, 101, 114, 101, 102,
-    101, 114, 101, 114, 114, 101, 102, 114, 101, 115, 104, 114, 101, 116, 114,
-    121, 45,  97,  102, 116, 101, 114, 115, 101, 114, 118, 101, 114, 115, 101,
-    116, 45,  99,  111, 111, 107, 105, 101, 115, 116, 114, 105, 99,  116, 45,
-    116, 114, 97,  110, 115, 112, 111, 114, 116, 45,  115, 101, 99,  117, 114,
-    105, 116, 121, 116, 114, 97,  110, 115, 102, 101, 114, 45,  101, 110, 99,
-    111, 100, 105, 110, 103, 118, 97,  114, 121, 118, 105, 97,  119, 119, 119,
-    45,  97,  117, 116, 104, 101, 110, 116, 105, 99,  97,  116, 101, 105, 100,
-    101, 110, 116, 105, 116, 121, 44,  100, 101, 102, 108, 97,  116, 101, 105,
-    100, 101, 110, 116, 105, 116, 121, 44,  103, 122, 105, 112, 100, 101, 102,
-    108, 97,  116, 101, 44,  103, 122, 105, 112, 105, 100, 101, 110, 116, 105,
-    116, 121, 44,  100, 101, 102, 108, 97,  116, 101, 44,  103, 122, 105, 112};
+    111, 100, 105, 110, 103, 103, 114, 112, 99,  45,  115, 101, 114, 118, 101,
+    114, 45,  115, 116, 97,  116, 115, 45,  98,  105, 110, 103, 114, 112, 99,
+    45,  116, 97,  103, 115, 45,  98,  105, 110, 103, 114, 112, 99,  45,  116,
+    114, 97,  99,  101, 45,  98,  105, 110, 99,  111, 110, 116, 101, 110, 116,
+    45,  116, 121, 112, 101, 103, 114, 112, 99,  45,  105, 110, 116, 101, 114,
+    110, 97,  108, 45,  101, 110, 99,  111, 100, 105, 110, 103, 45,  114, 101,
+    113, 117, 101, 115, 116, 117, 115, 101, 114, 45,  97,  103, 101, 110, 116,
+    104, 111, 115, 116, 108, 98,  45,  116, 111, 107, 101, 110, 103, 114, 112,
+    99,  45,  116, 105, 109, 101, 111, 117, 116, 103, 114, 112, 99,  46,  119,
+    97,  105, 116, 95,  102, 111, 114, 95,  114, 101, 97,  100, 121, 103, 114,
+    112, 99,  46,  116, 105, 109, 101, 111, 117, 116, 103, 114, 112, 99,  46,
+    109, 97,  120, 95,  114, 101, 113, 117, 101, 115, 116, 95,  109, 101, 115,
+    115, 97,  103, 101, 95,  98,  121, 116, 101, 115, 103, 114, 112, 99,  46,
+    109, 97,  120, 95,  114, 101, 115, 112, 111, 110, 115, 101, 95,  109, 101,
+    115, 115, 97,  103, 101, 95,  98,  121, 116, 101, 115, 47,  103, 114, 112,
+    99,  46,  108, 98,  46,  118, 49,  46,  76,  111, 97,  100, 66,  97,  108,
+    97,  110, 99,  101, 114, 47,  66,  97,  108, 97,  110, 99,  101, 76,  111,
+    97,  100, 48,  49,  50,  105, 100, 101, 110, 116, 105, 116, 121, 103, 122,
+    105, 112, 100, 101, 102, 108, 97,  116, 101, 116, 114, 97,  105, 108, 101,
+    114, 115, 97,  112, 112, 108, 105, 99,  97,  116, 105, 111, 110, 47,  103,
+    114, 112, 99,  80,  79,  83,  84,  50,  48,  48,  52,  48,  52,  104, 116,
+    116, 112, 104, 116, 116, 112, 115, 103, 114, 112, 99,  71,  69,  84,  80,
+    85,  84,  47,  47,  105, 110, 100, 101, 120, 46,  104, 116, 109, 108, 50,
+    48,  52,  50,  48,  54,  51,  48,  52,  52,  48,  48,  53,  48,  48,  97,
+    99,  99,  101, 112, 116, 45,  99,  104, 97,  114, 115, 101, 116, 97,  99,
+    99,  101, 112, 116, 45,  101, 110, 99,  111, 100, 105, 110, 103, 103, 122,
+    105, 112, 44,  32,  100, 101, 102, 108, 97,  116, 101, 97,  99,  99,  101,
+    112, 116, 45,  108, 97,  110, 103, 117, 97,  103, 101, 97,  99,  99,  101,
+    112, 116, 45,  114, 97,  110, 103, 101, 115, 97,  99,  99,  101, 112, 116,
+    97,  99,  99,  101, 115, 115, 45,  99,  111, 110, 116, 114, 111, 108, 45,
+    97,  108, 108, 111, 119, 45,  111, 114, 105, 103, 105, 110, 97,  103, 101,
+    97,  108, 108, 111, 119, 97,  117, 116, 104, 111, 114, 105, 122, 97,  116,
+    105, 111, 110, 99,  97,  99,  104, 101, 45,  99,  111, 110, 116, 114, 111,
+    108, 99,  111, 110, 116, 101, 110, 116, 45,  100, 105, 115, 112, 111, 115,
+    105, 116, 105, 111, 110, 99,  111, 110, 116, 101, 110, 116, 45,  101, 110,
+    99,  111, 100, 105, 110, 103, 99,  111, 110, 116, 101, 110, 116, 45,  108,
+    97,  110, 103, 117, 97,  103, 101, 99,  111, 110, 116, 101, 110, 116, 45,
+    108, 101, 110, 103, 116, 104, 99,  111, 110, 116, 101, 110, 116, 45,  108,
+    111, 99,  97,  116, 105, 111, 110, 99,  111, 110, 116, 101, 110, 116, 45,
+    114, 97,  110, 103, 101, 99,  111, 111, 107, 105, 101, 100, 97,  116, 101,
+    101, 116, 97,  103, 101, 120, 112, 101, 99,  116, 101, 120, 112, 105, 114,
+    101, 115, 102, 114, 111, 109, 105, 102, 45,  109, 97,  116, 99,  104, 105,
+    102, 45,  109, 111, 100, 105, 102, 105, 101, 100, 45,  115, 105, 110, 99,
+    101, 105, 102, 45,  110, 111, 110, 101, 45,  109, 97,  116, 99,  104, 105,
+    102, 45,  114, 97,  110, 103, 101, 105, 102, 45,  117, 110, 109, 111, 100,
+    105, 102, 105, 101, 100, 45,  115, 105, 110, 99,  101, 108, 97,  115, 116,
+    45,  109, 111, 100, 105, 102, 105, 101, 100, 108, 98,  45,  99,  111, 115,
+    116, 45,  98,  105, 110, 108, 105, 110, 107, 108, 111, 99,  97,  116, 105,
+    111, 110, 109, 97,  120, 45,  102, 111, 114, 119, 97,  114, 100, 115, 112,
+    114, 111, 120, 121, 45,  97,  117, 116, 104, 101, 110, 116, 105, 99,  97,
+    116, 101, 112, 114, 111, 120, 121, 45,  97,  117, 116, 104, 111, 114, 105,
+    122, 97,  116, 105, 111, 110, 114, 97,  110, 103, 101, 114, 101, 102, 101,
+    114, 101, 114, 114, 101, 102, 114, 101, 115, 104, 114, 101, 116, 114, 121,
+    45,  97,  102, 116, 101, 114, 115, 101, 114, 118, 101, 114, 115, 101, 116,
+    45,  99,  111, 111, 107, 105, 101, 115, 116, 114, 105, 99,  116, 45,  116,
+    114, 97,  110, 115, 112, 111, 114, 116, 45,  115, 101, 99,  117, 114, 105,
+    116, 121, 116, 114, 97,  110, 115, 102, 101, 114, 45,  101, 110, 99,  111,
+    100, 105, 110, 103, 118, 97,  114, 121, 118, 105, 97,  119, 119, 119, 45,
+    97,  117, 116, 104, 101, 110, 116, 105, 99,  97,  116, 101, 105, 100, 101,
+    110, 116, 105, 116, 121, 44,  100, 101, 102, 108, 97,  116, 101, 105, 100,
+    101, 110, 116, 105, 116, 121, 44,  103, 122, 105, 112, 100, 101, 102, 108,
+    97,  116, 101, 44,  103, 122, 105, 112, 105, 100, 101, 110, 116, 105, 116,
+    121, 44,  100, 101, 102, 108, 97,  116, 101, 44,  103, 122, 105, 112};
 
 static void static_ref(void *unused) {}
 static void static_unref(grpc_exec_ctx *exec_ctx, void *unused) {}
@@ -220,6 +222,8 @@
     {&grpc_static_metadata_vtable, &static_sub_refcnt},
     {&grpc_static_metadata_vtable, &static_sub_refcnt},
     {&grpc_static_metadata_vtable, &static_sub_refcnt},
+    {&grpc_static_metadata_vtable, &static_sub_refcnt},
+    {&grpc_static_metadata_vtable, &static_sub_refcnt},
 };
 
 const grpc_slice grpc_static_slice_table[GRPC_STATIC_MDSTR_COUNT] = {
@@ -246,196 +250,201 @@
     {.refcount = &grpc_static_metadata_refcounts[10],
      .data.refcounted = {g_bytes + 90, 20}},
     {.refcount = &grpc_static_metadata_refcounts[11],
-     .data.refcounted = {g_bytes + 110, 12}},
+     .data.refcounted = {g_bytes + 110, 21}},
     {.refcount = &grpc_static_metadata_refcounts[12],
-     .data.refcounted = {g_bytes + 122, 30}},
+     .data.refcounted = {g_bytes + 131, 13}},
     {.refcount = &grpc_static_metadata_refcounts[13],
-     .data.refcounted = {g_bytes + 152, 10}},
+     .data.refcounted = {g_bytes + 144, 14}},
     {.refcount = &grpc_static_metadata_refcounts[14],
-     .data.refcounted = {g_bytes + 162, 4}},
+     .data.refcounted = {g_bytes + 158, 12}},
     {.refcount = &grpc_static_metadata_refcounts[15],
-     .data.refcounted = {g_bytes + 166, 8}},
+     .data.refcounted = {g_bytes + 170, 30}},
     {.refcount = &grpc_static_metadata_refcounts[16],
-     .data.refcounted = {g_bytes + 174, 12}},
+     .data.refcounted = {g_bytes + 200, 10}},
     {.refcount = &grpc_static_metadata_refcounts[17],
-     .data.refcounted = {g_bytes + 186, 16}},
+     .data.refcounted = {g_bytes + 210, 4}},
     {.refcount = &grpc_static_metadata_refcounts[18],
-     .data.refcounted = {g_bytes + 202, 14}},
+     .data.refcounted = {g_bytes + 214, 8}},
     {.refcount = &grpc_static_metadata_refcounts[19],
-     .data.refcounted = {g_bytes + 216, 0}},
+     .data.refcounted = {g_bytes + 222, 12}},
     {.refcount = &grpc_static_metadata_refcounts[20],
-     .data.refcounted = {g_bytes + 216, 19}},
+     .data.refcounted = {g_bytes + 234, 0}},
     {.refcount = &grpc_static_metadata_refcounts[21],
-     .data.refcounted = {g_bytes + 235, 12}},
+     .data.refcounted = {g_bytes + 234, 19}},
     {.refcount = &grpc_static_metadata_refcounts[22],
-     .data.refcounted = {g_bytes + 247, 30}},
+     .data.refcounted = {g_bytes + 253, 12}},
     {.refcount = &grpc_static_metadata_refcounts[23],
-     .data.refcounted = {g_bytes + 277, 31}},
+     .data.refcounted = {g_bytes + 265, 30}},
     {.refcount = &grpc_static_metadata_refcounts[24],
-     .data.refcounted = {g_bytes + 308, 36}},
+     .data.refcounted = {g_bytes + 295, 31}},
     {.refcount = &grpc_static_metadata_refcounts[25],
-     .data.refcounted = {g_bytes + 344, 1}},
+     .data.refcounted = {g_bytes + 326, 36}},
     {.refcount = &grpc_static_metadata_refcounts[26],
-     .data.refcounted = {g_bytes + 345, 1}},
+     .data.refcounted = {g_bytes + 362, 1}},
     {.refcount = &grpc_static_metadata_refcounts[27],
-     .data.refcounted = {g_bytes + 346, 1}},
+     .data.refcounted = {g_bytes + 363, 1}},
     {.refcount = &grpc_static_metadata_refcounts[28],
-     .data.refcounted = {g_bytes + 347, 8}},
+     .data.refcounted = {g_bytes + 364, 1}},
     {.refcount = &grpc_static_metadata_refcounts[29],
-     .data.refcounted = {g_bytes + 355, 4}},
+     .data.refcounted = {g_bytes + 365, 8}},
     {.refcount = &grpc_static_metadata_refcounts[30],
-     .data.refcounted = {g_bytes + 359, 7}},
+     .data.refcounted = {g_bytes + 373, 4}},
     {.refcount = &grpc_static_metadata_refcounts[31],
-     .data.refcounted = {g_bytes + 366, 8}},
+     .data.refcounted = {g_bytes + 377, 7}},
     {.refcount = &grpc_static_metadata_refcounts[32],
-     .data.refcounted = {g_bytes + 374, 16}},
+     .data.refcounted = {g_bytes + 384, 8}},
     {.refcount = &grpc_static_metadata_refcounts[33],
-     .data.refcounted = {g_bytes + 390, 4}},
+     .data.refcounted = {g_bytes + 392, 16}},
     {.refcount = &grpc_static_metadata_refcounts[34],
-     .data.refcounted = {g_bytes + 394, 3}},
+     .data.refcounted = {g_bytes + 408, 4}},
     {.refcount = &grpc_static_metadata_refcounts[35],
-     .data.refcounted = {g_bytes + 397, 3}},
+     .data.refcounted = {g_bytes + 412, 3}},
     {.refcount = &grpc_static_metadata_refcounts[36],
-     .data.refcounted = {g_bytes + 400, 4}},
+     .data.refcounted = {g_bytes + 415, 3}},
     {.refcount = &grpc_static_metadata_refcounts[37],
-     .data.refcounted = {g_bytes + 404, 5}},
+     .data.refcounted = {g_bytes + 418, 4}},
     {.refcount = &grpc_static_metadata_refcounts[38],
-     .data.refcounted = {g_bytes + 409, 4}},
+     .data.refcounted = {g_bytes + 422, 5}},
     {.refcount = &grpc_static_metadata_refcounts[39],
-     .data.refcounted = {g_bytes + 413, 3}},
+     .data.refcounted = {g_bytes + 427, 4}},
     {.refcount = &grpc_static_metadata_refcounts[40],
-     .data.refcounted = {g_bytes + 416, 3}},
-    {.refcount = &grpc_static_metadata_refcounts[41],
-     .data.refcounted = {g_bytes + 419, 1}},
-    {.refcount = &grpc_static_metadata_refcounts[42],
-     .data.refcounted = {g_bytes + 420, 11}},
-    {.refcount = &grpc_static_metadata_refcounts[43],
      .data.refcounted = {g_bytes + 431, 3}},
-    {.refcount = &grpc_static_metadata_refcounts[44],
+    {.refcount = &grpc_static_metadata_refcounts[41],
      .data.refcounted = {g_bytes + 434, 3}},
+    {.refcount = &grpc_static_metadata_refcounts[42],
+     .data.refcounted = {g_bytes + 437, 1}},
+    {.refcount = &grpc_static_metadata_refcounts[43],
+     .data.refcounted = {g_bytes + 438, 11}},
+    {.refcount = &grpc_static_metadata_refcounts[44],
+     .data.refcounted = {g_bytes + 449, 3}},
     {.refcount = &grpc_static_metadata_refcounts[45],
-     .data.refcounted = {g_bytes + 437, 3}},
+     .data.refcounted = {g_bytes + 452, 3}},
     {.refcount = &grpc_static_metadata_refcounts[46],
-     .data.refcounted = {g_bytes + 440, 3}},
+     .data.refcounted = {g_bytes + 455, 3}},
     {.refcount = &grpc_static_metadata_refcounts[47],
-     .data.refcounted = {g_bytes + 443, 3}},
+     .data.refcounted = {g_bytes + 458, 3}},
     {.refcount = &grpc_static_metadata_refcounts[48],
-     .data.refcounted = {g_bytes + 446, 14}},
+     .data.refcounted = {g_bytes + 461, 3}},
     {.refcount = &grpc_static_metadata_refcounts[49],
-     .data.refcounted = {g_bytes + 460, 15}},
+     .data.refcounted = {g_bytes + 464, 14}},
     {.refcount = &grpc_static_metadata_refcounts[50],
-     .data.refcounted = {g_bytes + 475, 13}},
+     .data.refcounted = {g_bytes + 478, 15}},
     {.refcount = &grpc_static_metadata_refcounts[51],
-     .data.refcounted = {g_bytes + 488, 15}},
+     .data.refcounted = {g_bytes + 493, 13}},
     {.refcount = &grpc_static_metadata_refcounts[52],
-     .data.refcounted = {g_bytes + 503, 13}},
+     .data.refcounted = {g_bytes + 506, 15}},
     {.refcount = &grpc_static_metadata_refcounts[53],
-     .data.refcounted = {g_bytes + 516, 6}},
+     .data.refcounted = {g_bytes + 521, 13}},
     {.refcount = &grpc_static_metadata_refcounts[54],
-     .data.refcounted = {g_bytes + 522, 27}},
+     .data.refcounted = {g_bytes + 534, 6}},
     {.refcount = &grpc_static_metadata_refcounts[55],
-     .data.refcounted = {g_bytes + 549, 3}},
+     .data.refcounted = {g_bytes + 540, 27}},
     {.refcount = &grpc_static_metadata_refcounts[56],
-     .data.refcounted = {g_bytes + 552, 5}},
+     .data.refcounted = {g_bytes + 567, 3}},
     {.refcount = &grpc_static_metadata_refcounts[57],
-     .data.refcounted = {g_bytes + 557, 13}},
+     .data.refcounted = {g_bytes + 570, 5}},
     {.refcount = &grpc_static_metadata_refcounts[58],
-     .data.refcounted = {g_bytes + 570, 13}},
+     .data.refcounted = {g_bytes + 575, 13}},
     {.refcount = &grpc_static_metadata_refcounts[59],
-     .data.refcounted = {g_bytes + 583, 19}},
+     .data.refcounted = {g_bytes + 588, 13}},
     {.refcount = &grpc_static_metadata_refcounts[60],
-     .data.refcounted = {g_bytes + 602, 16}},
+     .data.refcounted = {g_bytes + 601, 19}},
     {.refcount = &grpc_static_metadata_refcounts[61],
-     .data.refcounted = {g_bytes + 618, 16}},
+     .data.refcounted = {g_bytes + 620, 16}},
     {.refcount = &grpc_static_metadata_refcounts[62],
-     .data.refcounted = {g_bytes + 634, 14}},
+     .data.refcounted = {g_bytes + 636, 16}},
     {.refcount = &grpc_static_metadata_refcounts[63],
-     .data.refcounted = {g_bytes + 648, 16}},
+     .data.refcounted = {g_bytes + 652, 14}},
     {.refcount = &grpc_static_metadata_refcounts[64],
-     .data.refcounted = {g_bytes + 664, 13}},
+     .data.refcounted = {g_bytes + 666, 16}},
     {.refcount = &grpc_static_metadata_refcounts[65],
-     .data.refcounted = {g_bytes + 677, 6}},
+     .data.refcounted = {g_bytes + 682, 13}},
     {.refcount = &grpc_static_metadata_refcounts[66],
-     .data.refcounted = {g_bytes + 683, 4}},
+     .data.refcounted = {g_bytes + 695, 6}},
     {.refcount = &grpc_static_metadata_refcounts[67],
-     .data.refcounted = {g_bytes + 687, 4}},
+     .data.refcounted = {g_bytes + 701, 4}},
     {.refcount = &grpc_static_metadata_refcounts[68],
-     .data.refcounted = {g_bytes + 691, 6}},
+     .data.refcounted = {g_bytes + 705, 4}},
     {.refcount = &grpc_static_metadata_refcounts[69],
-     .data.refcounted = {g_bytes + 697, 7}},
+     .data.refcounted = {g_bytes + 709, 6}},
     {.refcount = &grpc_static_metadata_refcounts[70],
-     .data.refcounted = {g_bytes + 704, 4}},
+     .data.refcounted = {g_bytes + 715, 7}},
     {.refcount = &grpc_static_metadata_refcounts[71],
-     .data.refcounted = {g_bytes + 708, 8}},
+     .data.refcounted = {g_bytes + 722, 4}},
     {.refcount = &grpc_static_metadata_refcounts[72],
-     .data.refcounted = {g_bytes + 716, 17}},
+     .data.refcounted = {g_bytes + 726, 8}},
     {.refcount = &grpc_static_metadata_refcounts[73],
-     .data.refcounted = {g_bytes + 733, 13}},
+     .data.refcounted = {g_bytes + 734, 17}},
     {.refcount = &grpc_static_metadata_refcounts[74],
-     .data.refcounted = {g_bytes + 746, 8}},
+     .data.refcounted = {g_bytes + 751, 13}},
     {.refcount = &grpc_static_metadata_refcounts[75],
-     .data.refcounted = {g_bytes + 754, 19}},
+     .data.refcounted = {g_bytes + 764, 8}},
     {.refcount = &grpc_static_metadata_refcounts[76],
-     .data.refcounted = {g_bytes + 773, 13}},
+     .data.refcounted = {g_bytes + 772, 19}},
     {.refcount = &grpc_static_metadata_refcounts[77],
-     .data.refcounted = {g_bytes + 786, 4}},
+     .data.refcounted = {g_bytes + 791, 13}},
     {.refcount = &grpc_static_metadata_refcounts[78],
-     .data.refcounted = {g_bytes + 790, 8}},
+     .data.refcounted = {g_bytes + 804, 11}},
     {.refcount = &grpc_static_metadata_refcounts[79],
-     .data.refcounted = {g_bytes + 798, 12}},
+     .data.refcounted = {g_bytes + 815, 4}},
     {.refcount = &grpc_static_metadata_refcounts[80],
-     .data.refcounted = {g_bytes + 810, 18}},
+     .data.refcounted = {g_bytes + 819, 8}},
     {.refcount = &grpc_static_metadata_refcounts[81],
-     .data.refcounted = {g_bytes + 828, 19}},
+     .data.refcounted = {g_bytes + 827, 12}},
     {.refcount = &grpc_static_metadata_refcounts[82],
-     .data.refcounted = {g_bytes + 847, 5}},
+     .data.refcounted = {g_bytes + 839, 18}},
     {.refcount = &grpc_static_metadata_refcounts[83],
-     .data.refcounted = {g_bytes + 852, 7}},
+     .data.refcounted = {g_bytes + 857, 19}},
     {.refcount = &grpc_static_metadata_refcounts[84],
-     .data.refcounted = {g_bytes + 859, 7}},
+     .data.refcounted = {g_bytes + 876, 5}},
     {.refcount = &grpc_static_metadata_refcounts[85],
-     .data.refcounted = {g_bytes + 866, 11}},
+     .data.refcounted = {g_bytes + 881, 7}},
     {.refcount = &grpc_static_metadata_refcounts[86],
-     .data.refcounted = {g_bytes + 877, 6}},
+     .data.refcounted = {g_bytes + 888, 7}},
     {.refcount = &grpc_static_metadata_refcounts[87],
-     .data.refcounted = {g_bytes + 883, 10}},
+     .data.refcounted = {g_bytes + 895, 11}},
     {.refcount = &grpc_static_metadata_refcounts[88],
-     .data.refcounted = {g_bytes + 893, 25}},
+     .data.refcounted = {g_bytes + 906, 6}},
     {.refcount = &grpc_static_metadata_refcounts[89],
-     .data.refcounted = {g_bytes + 918, 17}},
+     .data.refcounted = {g_bytes + 912, 10}},
     {.refcount = &grpc_static_metadata_refcounts[90],
-     .data.refcounted = {g_bytes + 935, 4}},
+     .data.refcounted = {g_bytes + 922, 25}},
     {.refcount = &grpc_static_metadata_refcounts[91],
-     .data.refcounted = {g_bytes + 939, 3}},
+     .data.refcounted = {g_bytes + 947, 17}},
     {.refcount = &grpc_static_metadata_refcounts[92],
-     .data.refcounted = {g_bytes + 942, 16}},
+     .data.refcounted = {g_bytes + 964, 4}},
     {.refcount = &grpc_static_metadata_refcounts[93],
-     .data.refcounted = {g_bytes + 958, 16}},
+     .data.refcounted = {g_bytes + 968, 3}},
     {.refcount = &grpc_static_metadata_refcounts[94],
-     .data.refcounted = {g_bytes + 974, 13}},
+     .data.refcounted = {g_bytes + 971, 16}},
     {.refcount = &grpc_static_metadata_refcounts[95],
-     .data.refcounted = {g_bytes + 987, 12}},
+     .data.refcounted = {g_bytes + 987, 16}},
     {.refcount = &grpc_static_metadata_refcounts[96],
-     .data.refcounted = {g_bytes + 999, 21}},
+     .data.refcounted = {g_bytes + 1003, 13}},
+    {.refcount = &grpc_static_metadata_refcounts[97],
+     .data.refcounted = {g_bytes + 1016, 12}},
+    {.refcount = &grpc_static_metadata_refcounts[98],
+     .data.refcounted = {g_bytes + 1028, 21}},
 };
 
 uintptr_t grpc_static_mdelem_user_data[GRPC_STATIC_MDELEM_COUNT] = {
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 4, 4, 6, 6, 8, 8};
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 4, 4, 6, 6, 8, 8};
 
 static const int8_t elems_r[] = {
-    10,  8,   -3, 0,   9,   21,  -75, 22,  0,   10,  -7,  20, 0,  19, 18, 17,
-    0,   0,   0,  0,   0,   0,   0,   0,   0,   0,   0,   0,  0,  0,  0,  0,
-    0,   0,   0,  0,   0,   0,   0,   0,   0,   0,   0,   0,  0,  0,  0,  0,
-    -48, -49, 16, -51, -52, -53, -54, -54, -55, -56, -57, 0,  37, 36, 35, 34,
-    33,  32,  31, 30,  29,  28,  27,  26,  25,  24,  23,  22, 21, 20, 19, 18,
-    17,  16,  15, 14,  13,  12,  11,  14,  13,  12,  11,  10, 9,  8,  0};
+    10,  8,   -3,  0,   9,  21, -77, 22,  0,   10, -7,  0,   0,   0,
+    14,  0,   13,  12,  11, 0,  0,   0,   0,   0,  0,   0,   0,   0,
+    0,   0,   0,   0,   0,  0,  0,   0,   0,   0,  0,   0,   0,   0,
+    0,   0,   0,   0,   0,  0,  0,   -50, -51, 16, -53, -54, -55, -56,
+    -56, -57, -58, -59, 0,  37, 36,  35,  34,  33, 32,  31,  30,  29,
+    28,  27,  26,  25,  24, 23, 22,  21,  20,  19, 18,  17,  16,  15,
+    14,  13,  12,  11,  10, 13, 12,  11,  10,  9,  8,   7,   0};
 static uint32_t elems_phash(uint32_t i) {
-  i -= 41;
-  uint32_t x = i % 95;
-  uint32_t y = i / 95;
+  i -= 42;
+  uint32_t x = i % 97;
+  uint32_t y = i / 97;
   uint32_t h = x;
   if (y < GPR_ARRAY_SIZE(elems_r)) {
     uint32_t delta = (uint32_t)elems_r[y];
@@ -445,29 +454,30 @@
 }
 
 static const uint16_t elem_keys[] = {
-    998,  999,  1000, 237,  238,  239,  240,  241,  136,  137,  41,   42,
-    424,  425,  426,  901,  902,  903,  704,  705,  1086, 516,  706,  1280,
-    1377, 1474, 4675, 4772, 4803, 4966, 5063, 5160, 5257, 1099, 5354, 5451,
-    5548, 5645, 5742, 5839, 5936, 6033, 6130, 6227, 6324, 6421, 6518, 6615,
-    6712, 6809, 6906, 7003, 7100, 7197, 7294, 7391, 7488, 7585, 7682, 7779,
-    7876, 7973, 8070, 8167, 8264, 1063, 1064, 1065, 1066, 8361, 8458, 8555,
-    8652, 8749, 8846, 8943, 310,  0,    0,    0,    0,    0,    0,    0,
+    1019, 1020, 1021, 242,  243,  244,  245,  246,  139,  140,  42,   43,
+    433,  434,  435,  920,  921,  922,  719,  720,  1406, 527,  721,  1604,
+    1703, 1802, 4871, 4970, 5001, 5168, 5267, 5366, 5465, 1419, 5564, 5663,
+    5762, 5861, 5960, 6059, 6158, 6257, 6356, 6455, 6554, 6653, 6752, 6851,
+    6950, 7049, 7148, 7247, 7346, 7445, 7544, 7643, 7742, 7841, 7940, 8039,
+    8138, 8237, 8336, 8435, 8534, 8633, 1085, 1086, 1087, 1088, 8732, 8831,
+    8930, 9029, 9128, 9227, 9326, 0,    317,  0,    0,    0,    0,    0,
     0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
-    0,    0,    0,    130,  228,  229,  0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    133,  233,  234,  0,    0,    0,    0,
     0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
-    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0};
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0};
 static const uint8_t elem_idxs[] = {
-    73,  76,  74,  19,  20,  21,  22,  23,  15,  16,  17,  18,  11,  12,  13,
-    3,   4,   5,   0,   1,   41,  6,   2,   69,  48,  55,  24,  25,  26,  27,
+    74,  77,  75,  19,  20,  21,  22,  23,  15,  16,  17,  18,  11,  12,  13,
+    3,   4,   5,   0,   1,   41,  6,   2,   70,  48,  55,  24,  25,  26,  27,
     28,  29,  30,  7,   31,  32,  33,  34,  35,  36,  37,  38,  39,  40,  42,
     43,  44,  45,  46,  47,  49,  50,  51,  52,  53,  54,  56,  57,  58,  59,
-    60,  61,  62,  63,  64,  75,  77,  78,  79,  65,  66,  67,  68,  70,  71,
-    72,  14,  255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-    255, 255, 255, 255, 255, 255, 255, 255, 255, 8,   9,   10};
+    60,  61,  62,  63,  64,  65,  76,  78,  79,  80,  66,  67,  68,  69,  71,
+    72,  73,  255, 14,  255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 8,   9,   10};
 
 grpc_mdelem grpc_static_mdelem_for_static_strings(int a, int b) {
   if (a == -1 || b == -1) return GRPC_MDNULL;
-  uint32_t k = (uint32_t)(a * 97 + b);
+  uint32_t k = (uint32_t)(a * 99 + b);
   uint32_t h = elems_phash(k);
   return h < GPR_ARRAY_SIZE(elem_keys) && elem_keys[h] == k
              ? GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[elem_idxs[h]],
@@ -478,324 +488,328 @@
 grpc_mdelem_data grpc_static_mdelem_table[GRPC_STATIC_MDELEM_COUNT] = {
     {{.refcount = &grpc_static_metadata_refcounts[7],
       .data.refcounted = {g_bytes + 50, 11}},
-     {.refcount = &grpc_static_metadata_refcounts[25],
-      .data.refcounted = {g_bytes + 344, 1}}},
-    {{.refcount = &grpc_static_metadata_refcounts[7],
-      .data.refcounted = {g_bytes + 50, 11}},
      {.refcount = &grpc_static_metadata_refcounts[26],
-      .data.refcounted = {g_bytes + 345, 1}}},
+      .data.refcounted = {g_bytes + 362, 1}}},
     {{.refcount = &grpc_static_metadata_refcounts[7],
       .data.refcounted = {g_bytes + 50, 11}},
      {.refcount = &grpc_static_metadata_refcounts[27],
-      .data.refcounted = {g_bytes + 346, 1}}},
-    {{.refcount = &grpc_static_metadata_refcounts[9],
-      .data.refcounted = {g_bytes + 77, 13}},
+      .data.refcounted = {g_bytes + 363, 1}}},
+    {{.refcount = &grpc_static_metadata_refcounts[7],
+      .data.refcounted = {g_bytes + 50, 11}},
      {.refcount = &grpc_static_metadata_refcounts[28],
-      .data.refcounted = {g_bytes + 347, 8}}},
+      .data.refcounted = {g_bytes + 364, 1}}},
     {{.refcount = &grpc_static_metadata_refcounts[9],
       .data.refcounted = {g_bytes + 77, 13}},
      {.refcount = &grpc_static_metadata_refcounts[29],
-      .data.refcounted = {g_bytes + 355, 4}}},
+      .data.refcounted = {g_bytes + 365, 8}}},
     {{.refcount = &grpc_static_metadata_refcounts[9],
       .data.refcounted = {g_bytes + 77, 13}},
      {.refcount = &grpc_static_metadata_refcounts[30],
-      .data.refcounted = {g_bytes + 359, 7}}},
+      .data.refcounted = {g_bytes + 373, 4}}},
+    {{.refcount = &grpc_static_metadata_refcounts[9],
+      .data.refcounted = {g_bytes + 77, 13}},
+     {.refcount = &grpc_static_metadata_refcounts[31],
+      .data.refcounted = {g_bytes + 377, 7}}},
     {{.refcount = &grpc_static_metadata_refcounts[5],
       .data.refcounted = {g_bytes + 36, 2}},
-     {.refcount = &grpc_static_metadata_refcounts[31],
-      .data.refcounted = {g_bytes + 366, 8}}},
-    {{.refcount = &grpc_static_metadata_refcounts[11],
-      .data.refcounted = {g_bytes + 110, 12}},
      {.refcount = &grpc_static_metadata_refcounts[32],
-      .data.refcounted = {g_bytes + 374, 16}}},
+      .data.refcounted = {g_bytes + 384, 8}}},
+    {{.refcount = &grpc_static_metadata_refcounts[14],
+      .data.refcounted = {g_bytes + 158, 12}},
+     {.refcount = &grpc_static_metadata_refcounts[33],
+      .data.refcounted = {g_bytes + 392, 16}}},
     {{.refcount = &grpc_static_metadata_refcounts[1],
       .data.refcounted = {g_bytes + 5, 7}},
-     {.refcount = &grpc_static_metadata_refcounts[33],
-      .data.refcounted = {g_bytes + 390, 4}}},
-    {{.refcount = &grpc_static_metadata_refcounts[2],
-      .data.refcounted = {g_bytes + 12, 7}},
      {.refcount = &grpc_static_metadata_refcounts[34],
-      .data.refcounted = {g_bytes + 394, 3}}},
+      .data.refcounted = {g_bytes + 408, 4}}},
     {{.refcount = &grpc_static_metadata_refcounts[2],
       .data.refcounted = {g_bytes + 12, 7}},
      {.refcount = &grpc_static_metadata_refcounts[35],
-      .data.refcounted = {g_bytes + 397, 3}}},
-    {{.refcount = &grpc_static_metadata_refcounts[4],
-      .data.refcounted = {g_bytes + 29, 7}},
+      .data.refcounted = {g_bytes + 412, 3}}},
+    {{.refcount = &grpc_static_metadata_refcounts[2],
+      .data.refcounted = {g_bytes + 12, 7}},
      {.refcount = &grpc_static_metadata_refcounts[36],
-      .data.refcounted = {g_bytes + 400, 4}}},
+      .data.refcounted = {g_bytes + 415, 3}}},
     {{.refcount = &grpc_static_metadata_refcounts[4],
       .data.refcounted = {g_bytes + 29, 7}},
      {.refcount = &grpc_static_metadata_refcounts[37],
-      .data.refcounted = {g_bytes + 404, 5}}},
+      .data.refcounted = {g_bytes + 418, 4}}},
     {{.refcount = &grpc_static_metadata_refcounts[4],
       .data.refcounted = {g_bytes + 29, 7}},
      {.refcount = &grpc_static_metadata_refcounts[38],
-      .data.refcounted = {g_bytes + 409, 4}}},
+      .data.refcounted = {g_bytes + 422, 5}}},
+    {{.refcount = &grpc_static_metadata_refcounts[4],
+      .data.refcounted = {g_bytes + 29, 7}},
+     {.refcount = &grpc_static_metadata_refcounts[39],
+      .data.refcounted = {g_bytes + 427, 4}}},
     {{.refcount = &grpc_static_metadata_refcounts[3],
       .data.refcounted = {g_bytes + 19, 10}},
-     {.refcount = &grpc_static_metadata_refcounts[19],
-      .data.refcounted = {g_bytes + 216, 0}}},
-    {{.refcount = &grpc_static_metadata_refcounts[1],
-      .data.refcounted = {g_bytes + 5, 7}},
-     {.refcount = &grpc_static_metadata_refcounts[39],
-      .data.refcounted = {g_bytes + 413, 3}}},
+     {.refcount = &grpc_static_metadata_refcounts[20],
+      .data.refcounted = {g_bytes + 234, 0}}},
     {{.refcount = &grpc_static_metadata_refcounts[1],
       .data.refcounted = {g_bytes + 5, 7}},
      {.refcount = &grpc_static_metadata_refcounts[40],
-      .data.refcounted = {g_bytes + 416, 3}}},
-    {{.refcount = &grpc_static_metadata_refcounts[0],
-      .data.refcounted = {g_bytes + 0, 5}},
+      .data.refcounted = {g_bytes + 431, 3}}},
+    {{.refcount = &grpc_static_metadata_refcounts[1],
+      .data.refcounted = {g_bytes + 5, 7}},
      {.refcount = &grpc_static_metadata_refcounts[41],
-      .data.refcounted = {g_bytes + 419, 1}}},
+      .data.refcounted = {g_bytes + 434, 3}}},
     {{.refcount = &grpc_static_metadata_refcounts[0],
       .data.refcounted = {g_bytes + 0, 5}},
      {.refcount = &grpc_static_metadata_refcounts[42],
-      .data.refcounted = {g_bytes + 420, 11}}},
-    {{.refcount = &grpc_static_metadata_refcounts[2],
-      .data.refcounted = {g_bytes + 12, 7}},
+      .data.refcounted = {g_bytes + 437, 1}}},
+    {{.refcount = &grpc_static_metadata_refcounts[0],
+      .data.refcounted = {g_bytes + 0, 5}},
      {.refcount = &grpc_static_metadata_refcounts[43],
-      .data.refcounted = {g_bytes + 431, 3}}},
+      .data.refcounted = {g_bytes + 438, 11}}},
     {{.refcount = &grpc_static_metadata_refcounts[2],
       .data.refcounted = {g_bytes + 12, 7}},
      {.refcount = &grpc_static_metadata_refcounts[44],
-      .data.refcounted = {g_bytes + 434, 3}}},
+      .data.refcounted = {g_bytes + 449, 3}}},
     {{.refcount = &grpc_static_metadata_refcounts[2],
       .data.refcounted = {g_bytes + 12, 7}},
      {.refcount = &grpc_static_metadata_refcounts[45],
-      .data.refcounted = {g_bytes + 437, 3}}},
+      .data.refcounted = {g_bytes + 452, 3}}},
     {{.refcount = &grpc_static_metadata_refcounts[2],
       .data.refcounted = {g_bytes + 12, 7}},
      {.refcount = &grpc_static_metadata_refcounts[46],
-      .data.refcounted = {g_bytes + 440, 3}}},
+      .data.refcounted = {g_bytes + 455, 3}}},
     {{.refcount = &grpc_static_metadata_refcounts[2],
       .data.refcounted = {g_bytes + 12, 7}},
      {.refcount = &grpc_static_metadata_refcounts[47],
-      .data.refcounted = {g_bytes + 443, 3}}},
-    {{.refcount = &grpc_static_metadata_refcounts[48],
-      .data.refcounted = {g_bytes + 446, 14}},
-     {.refcount = &grpc_static_metadata_refcounts[19],
-      .data.refcounted = {g_bytes + 216, 0}}},
+      .data.refcounted = {g_bytes + 458, 3}}},
+    {{.refcount = &grpc_static_metadata_refcounts[2],
+      .data.refcounted = {g_bytes + 12, 7}},
+     {.refcount = &grpc_static_metadata_refcounts[48],
+      .data.refcounted = {g_bytes + 461, 3}}},
     {{.refcount = &grpc_static_metadata_refcounts[49],
-      .data.refcounted = {g_bytes + 460, 15}},
-     {.refcount = &grpc_static_metadata_refcounts[19],
-      .data.refcounted = {g_bytes + 216, 0}}},
-    {{.refcount = &grpc_static_metadata_refcounts[49],
-      .data.refcounted = {g_bytes + 460, 15}},
-     {.refcount = &grpc_static_metadata_refcounts[50],
-      .data.refcounted = {g_bytes + 475, 13}}},
-    {{.refcount = &grpc_static_metadata_refcounts[51],
-      .data.refcounted = {g_bytes + 488, 15}},
-     {.refcount = &grpc_static_metadata_refcounts[19],
-      .data.refcounted = {g_bytes + 216, 0}}},
+      .data.refcounted = {g_bytes + 464, 14}},
+     {.refcount = &grpc_static_metadata_refcounts[20],
+      .data.refcounted = {g_bytes + 234, 0}}},
+    {{.refcount = &grpc_static_metadata_refcounts[50],
+      .data.refcounted = {g_bytes + 478, 15}},
+     {.refcount = &grpc_static_metadata_refcounts[20],
+      .data.refcounted = {g_bytes + 234, 0}}},
+    {{.refcount = &grpc_static_metadata_refcounts[50],
+      .data.refcounted = {g_bytes + 478, 15}},
+     {.refcount = &grpc_static_metadata_refcounts[51],
+      .data.refcounted = {g_bytes + 493, 13}}},
     {{.refcount = &grpc_static_metadata_refcounts[52],
-      .data.refcounted = {g_bytes + 503, 13}},
-     {.refcount = &grpc_static_metadata_refcounts[19],
-      .data.refcounted = {g_bytes + 216, 0}}},
+      .data.refcounted = {g_bytes + 506, 15}},
+     {.refcount = &grpc_static_metadata_refcounts[20],
+      .data.refcounted = {g_bytes + 234, 0}}},
     {{.refcount = &grpc_static_metadata_refcounts[53],
-      .data.refcounted = {g_bytes + 516, 6}},
-     {.refcount = &grpc_static_metadata_refcounts[19],
-      .data.refcounted = {g_bytes + 216, 0}}},
+      .data.refcounted = {g_bytes + 521, 13}},
+     {.refcount = &grpc_static_metadata_refcounts[20],
+      .data.refcounted = {g_bytes + 234, 0}}},
     {{.refcount = &grpc_static_metadata_refcounts[54],
-      .data.refcounted = {g_bytes + 522, 27}},
-     {.refcount = &grpc_static_metadata_refcounts[19],
-      .data.refcounted = {g_bytes + 216, 0}}},
+      .data.refcounted = {g_bytes + 534, 6}},
+     {.refcount = &grpc_static_metadata_refcounts[20],
+      .data.refcounted = {g_bytes + 234, 0}}},
     {{.refcount = &grpc_static_metadata_refcounts[55],
-      .data.refcounted = {g_bytes + 549, 3}},
-     {.refcount = &grpc_static_metadata_refcounts[19],
-      .data.refcounted = {g_bytes + 216, 0}}},
+      .data.refcounted = {g_bytes + 540, 27}},
+     {.refcount = &grpc_static_metadata_refcounts[20],
+      .data.refcounted = {g_bytes + 234, 0}}},
     {{.refcount = &grpc_static_metadata_refcounts[56],
-      .data.refcounted = {g_bytes + 552, 5}},
-     {.refcount = &grpc_static_metadata_refcounts[19],
-      .data.refcounted = {g_bytes + 216, 0}}},
+      .data.refcounted = {g_bytes + 567, 3}},
+     {.refcount = &grpc_static_metadata_refcounts[20],
+      .data.refcounted = {g_bytes + 234, 0}}},
     {{.refcount = &grpc_static_metadata_refcounts[57],
-      .data.refcounted = {g_bytes + 557, 13}},
-     {.refcount = &grpc_static_metadata_refcounts[19],
-      .data.refcounted = {g_bytes + 216, 0}}},
+      .data.refcounted = {g_bytes + 570, 5}},
+     {.refcount = &grpc_static_metadata_refcounts[20],
+      .data.refcounted = {g_bytes + 234, 0}}},
     {{.refcount = &grpc_static_metadata_refcounts[58],
-      .data.refcounted = {g_bytes + 570, 13}},
-     {.refcount = &grpc_static_metadata_refcounts[19],
-      .data.refcounted = {g_bytes + 216, 0}}},
+      .data.refcounted = {g_bytes + 575, 13}},
+     {.refcount = &grpc_static_metadata_refcounts[20],
+      .data.refcounted = {g_bytes + 234, 0}}},
     {{.refcount = &grpc_static_metadata_refcounts[59],
-      .data.refcounted = {g_bytes + 583, 19}},
-     {.refcount = &grpc_static_metadata_refcounts[19],
-      .data.refcounted = {g_bytes + 216, 0}}},
+      .data.refcounted = {g_bytes + 588, 13}},
+     {.refcount = &grpc_static_metadata_refcounts[20],
+      .data.refcounted = {g_bytes + 234, 0}}},
     {{.refcount = &grpc_static_metadata_refcounts[60],
-      .data.refcounted = {g_bytes + 602, 16}},
-     {.refcount = &grpc_static_metadata_refcounts[19],
-      .data.refcounted = {g_bytes + 216, 0}}},
+      .data.refcounted = {g_bytes + 601, 19}},
+     {.refcount = &grpc_static_metadata_refcounts[20],
+      .data.refcounted = {g_bytes + 234, 0}}},
     {{.refcount = &grpc_static_metadata_refcounts[61],
-      .data.refcounted = {g_bytes + 618, 16}},
-     {.refcount = &grpc_static_metadata_refcounts[19],
-      .data.refcounted = {g_bytes + 216, 0}}},
+      .data.refcounted = {g_bytes + 620, 16}},
+     {.refcount = &grpc_static_metadata_refcounts[20],
+      .data.refcounted = {g_bytes + 234, 0}}},
     {{.refcount = &grpc_static_metadata_refcounts[62],
-      .data.refcounted = {g_bytes + 634, 14}},
-     {.refcount = &grpc_static_metadata_refcounts[19],
-      .data.refcounted = {g_bytes + 216, 0}}},
+      .data.refcounted = {g_bytes + 636, 16}},
+     {.refcount = &grpc_static_metadata_refcounts[20],
+      .data.refcounted = {g_bytes + 234, 0}}},
     {{.refcount = &grpc_static_metadata_refcounts[63],
-      .data.refcounted = {g_bytes + 648, 16}},
-     {.refcount = &grpc_static_metadata_refcounts[19],
-      .data.refcounted = {g_bytes + 216, 0}}},
+      .data.refcounted = {g_bytes + 652, 14}},
+     {.refcount = &grpc_static_metadata_refcounts[20],
+      .data.refcounted = {g_bytes + 234, 0}}},
     {{.refcount = &grpc_static_metadata_refcounts[64],
-      .data.refcounted = {g_bytes + 664, 13}},
-     {.refcount = &grpc_static_metadata_refcounts[19],
-      .data.refcounted = {g_bytes + 216, 0}}},
-    {{.refcount = &grpc_static_metadata_refcounts[11],
-      .data.refcounted = {g_bytes + 110, 12}},
-     {.refcount = &grpc_static_metadata_refcounts[19],
-      .data.refcounted = {g_bytes + 216, 0}}},
+      .data.refcounted = {g_bytes + 666, 16}},
+     {.refcount = &grpc_static_metadata_refcounts[20],
+      .data.refcounted = {g_bytes + 234, 0}}},
     {{.refcount = &grpc_static_metadata_refcounts[65],
-      .data.refcounted = {g_bytes + 677, 6}},
-     {.refcount = &grpc_static_metadata_refcounts[19],
-      .data.refcounted = {g_bytes + 216, 0}}},
-    {{.refcount = &grpc_static_metadata_refcounts[66],
-      .data.refcounted = {g_bytes + 683, 4}},
-     {.refcount = &grpc_static_metadata_refcounts[19],
-      .data.refcounted = {g_bytes + 216, 0}}},
-    {{.refcount = &grpc_static_metadata_refcounts[67],
-      .data.refcounted = {g_bytes + 687, 4}},
-     {.refcount = &grpc_static_metadata_refcounts[19],
-      .data.refcounted = {g_bytes + 216, 0}}},
-    {{.refcount = &grpc_static_metadata_refcounts[68],
-      .data.refcounted = {g_bytes + 691, 6}},
-     {.refcount = &grpc_static_metadata_refcounts[19],
-      .data.refcounted = {g_bytes + 216, 0}}},
-    {{.refcount = &grpc_static_metadata_refcounts[69],
-      .data.refcounted = {g_bytes + 697, 7}},
-     {.refcount = &grpc_static_metadata_refcounts[19],
-      .data.refcounted = {g_bytes + 216, 0}}},
-    {{.refcount = &grpc_static_metadata_refcounts[70],
-      .data.refcounted = {g_bytes + 704, 4}},
-     {.refcount = &grpc_static_metadata_refcounts[19],
-      .data.refcounted = {g_bytes + 216, 0}}},
+      .data.refcounted = {g_bytes + 682, 13}},
+     {.refcount = &grpc_static_metadata_refcounts[20],
+      .data.refcounted = {g_bytes + 234, 0}}},
     {{.refcount = &grpc_static_metadata_refcounts[14],
-      .data.refcounted = {g_bytes + 162, 4}},
-     {.refcount = &grpc_static_metadata_refcounts[19],
-      .data.refcounted = {g_bytes + 216, 0}}},
+      .data.refcounted = {g_bytes + 158, 12}},
+     {.refcount = &grpc_static_metadata_refcounts[20],
+      .data.refcounted = {g_bytes + 234, 0}}},
+    {{.refcount = &grpc_static_metadata_refcounts[66],
+      .data.refcounted = {g_bytes + 695, 6}},
+     {.refcount = &grpc_static_metadata_refcounts[20],
+      .data.refcounted = {g_bytes + 234, 0}}},
+    {{.refcount = &grpc_static_metadata_refcounts[67],
+      .data.refcounted = {g_bytes + 701, 4}},
+     {.refcount = &grpc_static_metadata_refcounts[20],
+      .data.refcounted = {g_bytes + 234, 0}}},
+    {{.refcount = &grpc_static_metadata_refcounts[68],
+      .data.refcounted = {g_bytes + 705, 4}},
+     {.refcount = &grpc_static_metadata_refcounts[20],
+      .data.refcounted = {g_bytes + 234, 0}}},
+    {{.refcount = &grpc_static_metadata_refcounts[69],
+      .data.refcounted = {g_bytes + 709, 6}},
+     {.refcount = &grpc_static_metadata_refcounts[20],
+      .data.refcounted = {g_bytes + 234, 0}}},
+    {{.refcount = &grpc_static_metadata_refcounts[70],
+      .data.refcounted = {g_bytes + 715, 7}},
+     {.refcount = &grpc_static_metadata_refcounts[20],
+      .data.refcounted = {g_bytes + 234, 0}}},
     {{.refcount = &grpc_static_metadata_refcounts[71],
-      .data.refcounted = {g_bytes + 708, 8}},
-     {.refcount = &grpc_static_metadata_refcounts[19],
-      .data.refcounted = {g_bytes + 216, 0}}},
+      .data.refcounted = {g_bytes + 722, 4}},
+     {.refcount = &grpc_static_metadata_refcounts[20],
+      .data.refcounted = {g_bytes + 234, 0}}},
+    {{.refcount = &grpc_static_metadata_refcounts[17],
+      .data.refcounted = {g_bytes + 210, 4}},
+     {.refcount = &grpc_static_metadata_refcounts[20],
+      .data.refcounted = {g_bytes + 234, 0}}},
     {{.refcount = &grpc_static_metadata_refcounts[72],
-      .data.refcounted = {g_bytes + 716, 17}},
-     {.refcount = &grpc_static_metadata_refcounts[19],
-      .data.refcounted = {g_bytes + 216, 0}}},
+      .data.refcounted = {g_bytes + 726, 8}},
+     {.refcount = &grpc_static_metadata_refcounts[20],
+      .data.refcounted = {g_bytes + 234, 0}}},
     {{.refcount = &grpc_static_metadata_refcounts[73],
-      .data.refcounted = {g_bytes + 733, 13}},
-     {.refcount = &grpc_static_metadata_refcounts[19],
-      .data.refcounted = {g_bytes + 216, 0}}},
+      .data.refcounted = {g_bytes + 734, 17}},
+     {.refcount = &grpc_static_metadata_refcounts[20],
+      .data.refcounted = {g_bytes + 234, 0}}},
     {{.refcount = &grpc_static_metadata_refcounts[74],
-      .data.refcounted = {g_bytes + 746, 8}},
-     {.refcount = &grpc_static_metadata_refcounts[19],
-      .data.refcounted = {g_bytes + 216, 0}}},
+      .data.refcounted = {g_bytes + 751, 13}},
+     {.refcount = &grpc_static_metadata_refcounts[20],
+      .data.refcounted = {g_bytes + 234, 0}}},
     {{.refcount = &grpc_static_metadata_refcounts[75],
-      .data.refcounted = {g_bytes + 754, 19}},
-     {.refcount = &grpc_static_metadata_refcounts[19],
-      .data.refcounted = {g_bytes + 216, 0}}},
+      .data.refcounted = {g_bytes + 764, 8}},
+     {.refcount = &grpc_static_metadata_refcounts[20],
+      .data.refcounted = {g_bytes + 234, 0}}},
     {{.refcount = &grpc_static_metadata_refcounts[76],
-      .data.refcounted = {g_bytes + 773, 13}},
-     {.refcount = &grpc_static_metadata_refcounts[19],
-      .data.refcounted = {g_bytes + 216, 0}}},
-    {{.refcount = &grpc_static_metadata_refcounts[15],
-      .data.refcounted = {g_bytes + 166, 8}},
-     {.refcount = &grpc_static_metadata_refcounts[19],
-      .data.refcounted = {g_bytes + 216, 0}}},
+      .data.refcounted = {g_bytes + 772, 19}},
+     {.refcount = &grpc_static_metadata_refcounts[20],
+      .data.refcounted = {g_bytes + 234, 0}}},
     {{.refcount = &grpc_static_metadata_refcounts[77],
-      .data.refcounted = {g_bytes + 786, 4}},
-     {.refcount = &grpc_static_metadata_refcounts[19],
-      .data.refcounted = {g_bytes + 216, 0}}},
+      .data.refcounted = {g_bytes + 791, 13}},
+     {.refcount = &grpc_static_metadata_refcounts[20],
+      .data.refcounted = {g_bytes + 234, 0}}},
+    {{.refcount = &grpc_static_metadata_refcounts[18],
+      .data.refcounted = {g_bytes + 214, 8}},
+     {.refcount = &grpc_static_metadata_refcounts[20],
+      .data.refcounted = {g_bytes + 234, 0}}},
     {{.refcount = &grpc_static_metadata_refcounts[78],
-      .data.refcounted = {g_bytes + 790, 8}},
-     {.refcount = &grpc_static_metadata_refcounts[19],
-      .data.refcounted = {g_bytes + 216, 0}}},
+      .data.refcounted = {g_bytes + 804, 11}},
+     {.refcount = &grpc_static_metadata_refcounts[20],
+      .data.refcounted = {g_bytes + 234, 0}}},
     {{.refcount = &grpc_static_metadata_refcounts[79],
-      .data.refcounted = {g_bytes + 798, 12}},
-     {.refcount = &grpc_static_metadata_refcounts[19],
-      .data.refcounted = {g_bytes + 216, 0}}},
+      .data.refcounted = {g_bytes + 815, 4}},
+     {.refcount = &grpc_static_metadata_refcounts[20],
+      .data.refcounted = {g_bytes + 234, 0}}},
     {{.refcount = &grpc_static_metadata_refcounts[80],
-      .data.refcounted = {g_bytes + 810, 18}},
-     {.refcount = &grpc_static_metadata_refcounts[19],
-      .data.refcounted = {g_bytes + 216, 0}}},
+      .data.refcounted = {g_bytes + 819, 8}},
+     {.refcount = &grpc_static_metadata_refcounts[20],
+      .data.refcounted = {g_bytes + 234, 0}}},
     {{.refcount = &grpc_static_metadata_refcounts[81],
-      .data.refcounted = {g_bytes + 828, 19}},
-     {.refcount = &grpc_static_metadata_refcounts[19],
-      .data.refcounted = {g_bytes + 216, 0}}},
+      .data.refcounted = {g_bytes + 827, 12}},
+     {.refcount = &grpc_static_metadata_refcounts[20],
+      .data.refcounted = {g_bytes + 234, 0}}},
     {{.refcount = &grpc_static_metadata_refcounts[82],
-      .data.refcounted = {g_bytes + 847, 5}},
-     {.refcount = &grpc_static_metadata_refcounts[19],
-      .data.refcounted = {g_bytes + 216, 0}}},
+      .data.refcounted = {g_bytes + 839, 18}},
+     {.refcount = &grpc_static_metadata_refcounts[20],
+      .data.refcounted = {g_bytes + 234, 0}}},
     {{.refcount = &grpc_static_metadata_refcounts[83],
-      .data.refcounted = {g_bytes + 852, 7}},
-     {.refcount = &grpc_static_metadata_refcounts[19],
-      .data.refcounted = {g_bytes + 216, 0}}},
+      .data.refcounted = {g_bytes + 857, 19}},
+     {.refcount = &grpc_static_metadata_refcounts[20],
+      .data.refcounted = {g_bytes + 234, 0}}},
     {{.refcount = &grpc_static_metadata_refcounts[84],
-      .data.refcounted = {g_bytes + 859, 7}},
-     {.refcount = &grpc_static_metadata_refcounts[19],
-      .data.refcounted = {g_bytes + 216, 0}}},
+      .data.refcounted = {g_bytes + 876, 5}},
+     {.refcount = &grpc_static_metadata_refcounts[20],
+      .data.refcounted = {g_bytes + 234, 0}}},
     {{.refcount = &grpc_static_metadata_refcounts[85],
-      .data.refcounted = {g_bytes + 866, 11}},
-     {.refcount = &grpc_static_metadata_refcounts[19],
-      .data.refcounted = {g_bytes + 216, 0}}},
+      .data.refcounted = {g_bytes + 881, 7}},
+     {.refcount = &grpc_static_metadata_refcounts[20],
+      .data.refcounted = {g_bytes + 234, 0}}},
     {{.refcount = &grpc_static_metadata_refcounts[86],
-      .data.refcounted = {g_bytes + 877, 6}},
-     {.refcount = &grpc_static_metadata_refcounts[19],
-      .data.refcounted = {g_bytes + 216, 0}}},
+      .data.refcounted = {g_bytes + 888, 7}},
+     {.refcount = &grpc_static_metadata_refcounts[20],
+      .data.refcounted = {g_bytes + 234, 0}}},
     {{.refcount = &grpc_static_metadata_refcounts[87],
-      .data.refcounted = {g_bytes + 883, 10}},
-     {.refcount = &grpc_static_metadata_refcounts[19],
-      .data.refcounted = {g_bytes + 216, 0}}},
+      .data.refcounted = {g_bytes + 895, 11}},
+     {.refcount = &grpc_static_metadata_refcounts[20],
+      .data.refcounted = {g_bytes + 234, 0}}},
     {{.refcount = &grpc_static_metadata_refcounts[88],
-      .data.refcounted = {g_bytes + 893, 25}},
-     {.refcount = &grpc_static_metadata_refcounts[19],
-      .data.refcounted = {g_bytes + 216, 0}}},
+      .data.refcounted = {g_bytes + 906, 6}},
+     {.refcount = &grpc_static_metadata_refcounts[20],
+      .data.refcounted = {g_bytes + 234, 0}}},
     {{.refcount = &grpc_static_metadata_refcounts[89],
-      .data.refcounted = {g_bytes + 918, 17}},
-     {.refcount = &grpc_static_metadata_refcounts[19],
-      .data.refcounted = {g_bytes + 216, 0}}},
-    {{.refcount = &grpc_static_metadata_refcounts[13],
-      .data.refcounted = {g_bytes + 152, 10}},
-     {.refcount = &grpc_static_metadata_refcounts[19],
-      .data.refcounted = {g_bytes + 216, 0}}},
+      .data.refcounted = {g_bytes + 912, 10}},
+     {.refcount = &grpc_static_metadata_refcounts[20],
+      .data.refcounted = {g_bytes + 234, 0}}},
     {{.refcount = &grpc_static_metadata_refcounts[90],
-      .data.refcounted = {g_bytes + 935, 4}},
-     {.refcount = &grpc_static_metadata_refcounts[19],
-      .data.refcounted = {g_bytes + 216, 0}}},
+      .data.refcounted = {g_bytes + 922, 25}},
+     {.refcount = &grpc_static_metadata_refcounts[20],
+      .data.refcounted = {g_bytes + 234, 0}}},
     {{.refcount = &grpc_static_metadata_refcounts[91],
-      .data.refcounted = {g_bytes + 939, 3}},
-     {.refcount = &grpc_static_metadata_refcounts[19],
-      .data.refcounted = {g_bytes + 216, 0}}},
+      .data.refcounted = {g_bytes + 947, 17}},
+     {.refcount = &grpc_static_metadata_refcounts[20],
+      .data.refcounted = {g_bytes + 234, 0}}},
+    {{.refcount = &grpc_static_metadata_refcounts[16],
+      .data.refcounted = {g_bytes + 200, 10}},
+     {.refcount = &grpc_static_metadata_refcounts[20],
+      .data.refcounted = {g_bytes + 234, 0}}},
     {{.refcount = &grpc_static_metadata_refcounts[92],
-      .data.refcounted = {g_bytes + 942, 16}},
-     {.refcount = &grpc_static_metadata_refcounts[19],
-      .data.refcounted = {g_bytes + 216, 0}}},
-    {{.refcount = &grpc_static_metadata_refcounts[10],
-      .data.refcounted = {g_bytes + 90, 20}},
-     {.refcount = &grpc_static_metadata_refcounts[28],
-      .data.refcounted = {g_bytes + 347, 8}}},
-    {{.refcount = &grpc_static_metadata_refcounts[10],
-      .data.refcounted = {g_bytes + 90, 20}},
-     {.refcount = &grpc_static_metadata_refcounts[30],
-      .data.refcounted = {g_bytes + 359, 7}}},
-    {{.refcount = &grpc_static_metadata_refcounts[10],
-      .data.refcounted = {g_bytes + 90, 20}},
-     {.refcount = &grpc_static_metadata_refcounts[93],
-      .data.refcounted = {g_bytes + 958, 16}}},
+      .data.refcounted = {g_bytes + 964, 4}},
+     {.refcount = &grpc_static_metadata_refcounts[20],
+      .data.refcounted = {g_bytes + 234, 0}}},
+    {{.refcount = &grpc_static_metadata_refcounts[93],
+      .data.refcounted = {g_bytes + 968, 3}},
+     {.refcount = &grpc_static_metadata_refcounts[20],
+      .data.refcounted = {g_bytes + 234, 0}}},
+    {{.refcount = &grpc_static_metadata_refcounts[94],
+      .data.refcounted = {g_bytes + 971, 16}},
+     {.refcount = &grpc_static_metadata_refcounts[20],
+      .data.refcounted = {g_bytes + 234, 0}}},
     {{.refcount = &grpc_static_metadata_refcounts[10],
       .data.refcounted = {g_bytes + 90, 20}},
      {.refcount = &grpc_static_metadata_refcounts[29],
-      .data.refcounted = {g_bytes + 355, 4}}},
+      .data.refcounted = {g_bytes + 365, 8}}},
     {{.refcount = &grpc_static_metadata_refcounts[10],
       .data.refcounted = {g_bytes + 90, 20}},
-     {.refcount = &grpc_static_metadata_refcounts[94],
-      .data.refcounted = {g_bytes + 974, 13}}},
+     {.refcount = &grpc_static_metadata_refcounts[31],
+      .data.refcounted = {g_bytes + 377, 7}}},
     {{.refcount = &grpc_static_metadata_refcounts[10],
       .data.refcounted = {g_bytes + 90, 20}},
      {.refcount = &grpc_static_metadata_refcounts[95],
-      .data.refcounted = {g_bytes + 987, 12}}},
+      .data.refcounted = {g_bytes + 987, 16}}},
+    {{.refcount = &grpc_static_metadata_refcounts[10],
+      .data.refcounted = {g_bytes + 90, 20}},
+     {.refcount = &grpc_static_metadata_refcounts[30],
+      .data.refcounted = {g_bytes + 373, 4}}},
     {{.refcount = &grpc_static_metadata_refcounts[10],
       .data.refcounted = {g_bytes + 90, 20}},
      {.refcount = &grpc_static_metadata_refcounts[96],
-      .data.refcounted = {g_bytes + 999, 21}}},
+      .data.refcounted = {g_bytes + 1003, 13}}},
+    {{.refcount = &grpc_static_metadata_refcounts[10],
+      .data.refcounted = {g_bytes + 90, 20}},
+     {.refcount = &grpc_static_metadata_refcounts[97],
+      .data.refcounted = {g_bytes + 1016, 12}}},
+    {{.refcount = &grpc_static_metadata_refcounts[10],
+      .data.refcounted = {g_bytes + 90, 20}},
+     {.refcount = &grpc_static_metadata_refcounts[98],
+      .data.refcounted = {g_bytes + 1028, 21}}},
 };
-const uint8_t grpc_static_accept_encoding_metadata[8] = {0,  73, 74, 75,
-                                                         76, 77, 78, 79};
+const uint8_t grpc_static_accept_encoding_metadata[8] = {0,  74, 75, 76,
+                                                         77, 78, 79, 80};
diff --git a/src/core/lib/transport/static_metadata.h b/src/core/lib/transport/static_metadata.h
index f9600ee..84fb316 100644
--- a/src/core/lib/transport/static_metadata.h
+++ b/src/core/lib/transport/static_metadata.h
@@ -44,7 +44,7 @@
 
 #include "src/core/lib/transport/metadata.h"
 
-#define GRPC_STATIC_MDSTR_COUNT 97
+#define GRPC_STATIC_MDSTR_COUNT 99
 extern const grpc_slice grpc_static_slice_table[GRPC_STATIC_MDSTR_COUNT];
 /* ":path" */
 #define GRPC_MDSTR_PATH (grpc_static_slice_table[0])
@@ -68,182 +68,186 @@
 #define GRPC_MDSTR_GRPC_ENCODING (grpc_static_slice_table[9])
 /* "grpc-accept-encoding" */
 #define GRPC_MDSTR_GRPC_ACCEPT_ENCODING (grpc_static_slice_table[10])
+/* "grpc-server-stats-bin" */
+#define GRPC_MDSTR_GRPC_SERVER_STATS_BIN (grpc_static_slice_table[11])
+/* "grpc-tags-bin" */
+#define GRPC_MDSTR_GRPC_TAGS_BIN (grpc_static_slice_table[12])
+/* "grpc-trace-bin" */
+#define GRPC_MDSTR_GRPC_TRACE_BIN (grpc_static_slice_table[13])
 /* "content-type" */
-#define GRPC_MDSTR_CONTENT_TYPE (grpc_static_slice_table[11])
+#define GRPC_MDSTR_CONTENT_TYPE (grpc_static_slice_table[14])
 /* "grpc-internal-encoding-request" */
-#define GRPC_MDSTR_GRPC_INTERNAL_ENCODING_REQUEST (grpc_static_slice_table[12])
+#define GRPC_MDSTR_GRPC_INTERNAL_ENCODING_REQUEST (grpc_static_slice_table[15])
 /* "user-agent" */
-#define GRPC_MDSTR_USER_AGENT (grpc_static_slice_table[13])
+#define GRPC_MDSTR_USER_AGENT (grpc_static_slice_table[16])
 /* "host" */
-#define GRPC_MDSTR_HOST (grpc_static_slice_table[14])
+#define GRPC_MDSTR_HOST (grpc_static_slice_table[17])
 /* "lb-token" */
-#define GRPC_MDSTR_LB_TOKEN (grpc_static_slice_table[15])
+#define GRPC_MDSTR_LB_TOKEN (grpc_static_slice_table[18])
 /* "grpc-timeout" */
-#define GRPC_MDSTR_GRPC_TIMEOUT (grpc_static_slice_table[16])
-/* "grpc-tracing-bin" */
-#define GRPC_MDSTR_GRPC_TRACING_BIN (grpc_static_slice_table[17])
-/* "grpc-stats-bin" */
-#define GRPC_MDSTR_GRPC_STATS_BIN (grpc_static_slice_table[18])
+#define GRPC_MDSTR_GRPC_TIMEOUT (grpc_static_slice_table[19])
 /* "" */
-#define GRPC_MDSTR_EMPTY (grpc_static_slice_table[19])
+#define GRPC_MDSTR_EMPTY (grpc_static_slice_table[20])
 /* "grpc.wait_for_ready" */
-#define GRPC_MDSTR_GRPC_DOT_WAIT_FOR_READY (grpc_static_slice_table[20])
+#define GRPC_MDSTR_GRPC_DOT_WAIT_FOR_READY (grpc_static_slice_table[21])
 /* "grpc.timeout" */
-#define GRPC_MDSTR_GRPC_DOT_TIMEOUT (grpc_static_slice_table[21])
+#define GRPC_MDSTR_GRPC_DOT_TIMEOUT (grpc_static_slice_table[22])
 /* "grpc.max_request_message_bytes" */
 #define GRPC_MDSTR_GRPC_DOT_MAX_REQUEST_MESSAGE_BYTES \
-  (grpc_static_slice_table[22])
+  (grpc_static_slice_table[23])
 /* "grpc.max_response_message_bytes" */
 #define GRPC_MDSTR_GRPC_DOT_MAX_RESPONSE_MESSAGE_BYTES \
-  (grpc_static_slice_table[23])
+  (grpc_static_slice_table[24])
 /* "/grpc.lb.v1.LoadBalancer/BalanceLoad" */
 #define GRPC_MDSTR_SLASH_GRPC_DOT_LB_DOT_V1_DOT_LOADBALANCER_SLASH_BALANCELOAD \
-  (grpc_static_slice_table[24])
+  (grpc_static_slice_table[25])
 /* "0" */
-#define GRPC_MDSTR_0 (grpc_static_slice_table[25])
+#define GRPC_MDSTR_0 (grpc_static_slice_table[26])
 /* "1" */
-#define GRPC_MDSTR_1 (grpc_static_slice_table[26])
+#define GRPC_MDSTR_1 (grpc_static_slice_table[27])
 /* "2" */
-#define GRPC_MDSTR_2 (grpc_static_slice_table[27])
+#define GRPC_MDSTR_2 (grpc_static_slice_table[28])
 /* "identity" */
-#define GRPC_MDSTR_IDENTITY (grpc_static_slice_table[28])
+#define GRPC_MDSTR_IDENTITY (grpc_static_slice_table[29])
 /* "gzip" */
-#define GRPC_MDSTR_GZIP (grpc_static_slice_table[29])
+#define GRPC_MDSTR_GZIP (grpc_static_slice_table[30])
 /* "deflate" */
-#define GRPC_MDSTR_DEFLATE (grpc_static_slice_table[30])
+#define GRPC_MDSTR_DEFLATE (grpc_static_slice_table[31])
 /* "trailers" */
-#define GRPC_MDSTR_TRAILERS (grpc_static_slice_table[31])
+#define GRPC_MDSTR_TRAILERS (grpc_static_slice_table[32])
 /* "application/grpc" */
-#define GRPC_MDSTR_APPLICATION_SLASH_GRPC (grpc_static_slice_table[32])
+#define GRPC_MDSTR_APPLICATION_SLASH_GRPC (grpc_static_slice_table[33])
 /* "POST" */
-#define GRPC_MDSTR_POST (grpc_static_slice_table[33])
+#define GRPC_MDSTR_POST (grpc_static_slice_table[34])
 /* "200" */
-#define GRPC_MDSTR_200 (grpc_static_slice_table[34])
+#define GRPC_MDSTR_200 (grpc_static_slice_table[35])
 /* "404" */
-#define GRPC_MDSTR_404 (grpc_static_slice_table[35])
+#define GRPC_MDSTR_404 (grpc_static_slice_table[36])
 /* "http" */
-#define GRPC_MDSTR_HTTP (grpc_static_slice_table[36])
+#define GRPC_MDSTR_HTTP (grpc_static_slice_table[37])
 /* "https" */
-#define GRPC_MDSTR_HTTPS (grpc_static_slice_table[37])
+#define GRPC_MDSTR_HTTPS (grpc_static_slice_table[38])
 /* "grpc" */
-#define GRPC_MDSTR_GRPC (grpc_static_slice_table[38])
+#define GRPC_MDSTR_GRPC (grpc_static_slice_table[39])
 /* "GET" */
-#define GRPC_MDSTR_GET (grpc_static_slice_table[39])
+#define GRPC_MDSTR_GET (grpc_static_slice_table[40])
 /* "PUT" */
-#define GRPC_MDSTR_PUT (grpc_static_slice_table[40])
+#define GRPC_MDSTR_PUT (grpc_static_slice_table[41])
 /* "/" */
-#define GRPC_MDSTR_SLASH (grpc_static_slice_table[41])
+#define GRPC_MDSTR_SLASH (grpc_static_slice_table[42])
 /* "/index.html" */
-#define GRPC_MDSTR_SLASH_INDEX_DOT_HTML (grpc_static_slice_table[42])
+#define GRPC_MDSTR_SLASH_INDEX_DOT_HTML (grpc_static_slice_table[43])
 /* "204" */
-#define GRPC_MDSTR_204 (grpc_static_slice_table[43])
+#define GRPC_MDSTR_204 (grpc_static_slice_table[44])
 /* "206" */
-#define GRPC_MDSTR_206 (grpc_static_slice_table[44])
+#define GRPC_MDSTR_206 (grpc_static_slice_table[45])
 /* "304" */
-#define GRPC_MDSTR_304 (grpc_static_slice_table[45])
+#define GRPC_MDSTR_304 (grpc_static_slice_table[46])
 /* "400" */
-#define GRPC_MDSTR_400 (grpc_static_slice_table[46])
+#define GRPC_MDSTR_400 (grpc_static_slice_table[47])
 /* "500" */
-#define GRPC_MDSTR_500 (grpc_static_slice_table[47])
+#define GRPC_MDSTR_500 (grpc_static_slice_table[48])
 /* "accept-charset" */
-#define GRPC_MDSTR_ACCEPT_CHARSET (grpc_static_slice_table[48])
+#define GRPC_MDSTR_ACCEPT_CHARSET (grpc_static_slice_table[49])
 /* "accept-encoding" */
-#define GRPC_MDSTR_ACCEPT_ENCODING (grpc_static_slice_table[49])
+#define GRPC_MDSTR_ACCEPT_ENCODING (grpc_static_slice_table[50])
 /* "gzip, deflate" */
-#define GRPC_MDSTR_GZIP_COMMA_DEFLATE (grpc_static_slice_table[50])
+#define GRPC_MDSTR_GZIP_COMMA_DEFLATE (grpc_static_slice_table[51])
 /* "accept-language" */
-#define GRPC_MDSTR_ACCEPT_LANGUAGE (grpc_static_slice_table[51])
+#define GRPC_MDSTR_ACCEPT_LANGUAGE (grpc_static_slice_table[52])
 /* "accept-ranges" */
-#define GRPC_MDSTR_ACCEPT_RANGES (grpc_static_slice_table[52])
+#define GRPC_MDSTR_ACCEPT_RANGES (grpc_static_slice_table[53])
 /* "accept" */
-#define GRPC_MDSTR_ACCEPT (grpc_static_slice_table[53])
+#define GRPC_MDSTR_ACCEPT (grpc_static_slice_table[54])
 /* "access-control-allow-origin" */
-#define GRPC_MDSTR_ACCESS_CONTROL_ALLOW_ORIGIN (grpc_static_slice_table[54])
+#define GRPC_MDSTR_ACCESS_CONTROL_ALLOW_ORIGIN (grpc_static_slice_table[55])
 /* "age" */
-#define GRPC_MDSTR_AGE (grpc_static_slice_table[55])
+#define GRPC_MDSTR_AGE (grpc_static_slice_table[56])
 /* "allow" */
-#define GRPC_MDSTR_ALLOW (grpc_static_slice_table[56])
+#define GRPC_MDSTR_ALLOW (grpc_static_slice_table[57])
 /* "authorization" */
-#define GRPC_MDSTR_AUTHORIZATION (grpc_static_slice_table[57])
+#define GRPC_MDSTR_AUTHORIZATION (grpc_static_slice_table[58])
 /* "cache-control" */
-#define GRPC_MDSTR_CACHE_CONTROL (grpc_static_slice_table[58])
+#define GRPC_MDSTR_CACHE_CONTROL (grpc_static_slice_table[59])
 /* "content-disposition" */
-#define GRPC_MDSTR_CONTENT_DISPOSITION (grpc_static_slice_table[59])
+#define GRPC_MDSTR_CONTENT_DISPOSITION (grpc_static_slice_table[60])
 /* "content-encoding" */
-#define GRPC_MDSTR_CONTENT_ENCODING (grpc_static_slice_table[60])
+#define GRPC_MDSTR_CONTENT_ENCODING (grpc_static_slice_table[61])
 /* "content-language" */
-#define GRPC_MDSTR_CONTENT_LANGUAGE (grpc_static_slice_table[61])
+#define GRPC_MDSTR_CONTENT_LANGUAGE (grpc_static_slice_table[62])
 /* "content-length" */
-#define GRPC_MDSTR_CONTENT_LENGTH (grpc_static_slice_table[62])
+#define GRPC_MDSTR_CONTENT_LENGTH (grpc_static_slice_table[63])
 /* "content-location" */
-#define GRPC_MDSTR_CONTENT_LOCATION (grpc_static_slice_table[63])
+#define GRPC_MDSTR_CONTENT_LOCATION (grpc_static_slice_table[64])
 /* "content-range" */
-#define GRPC_MDSTR_CONTENT_RANGE (grpc_static_slice_table[64])
+#define GRPC_MDSTR_CONTENT_RANGE (grpc_static_slice_table[65])
 /* "cookie" */
-#define GRPC_MDSTR_COOKIE (grpc_static_slice_table[65])
+#define GRPC_MDSTR_COOKIE (grpc_static_slice_table[66])
 /* "date" */
-#define GRPC_MDSTR_DATE (grpc_static_slice_table[66])
+#define GRPC_MDSTR_DATE (grpc_static_slice_table[67])
 /* "etag" */
-#define GRPC_MDSTR_ETAG (grpc_static_slice_table[67])
+#define GRPC_MDSTR_ETAG (grpc_static_slice_table[68])
 /* "expect" */
-#define GRPC_MDSTR_EXPECT (grpc_static_slice_table[68])
+#define GRPC_MDSTR_EXPECT (grpc_static_slice_table[69])
 /* "expires" */
-#define GRPC_MDSTR_EXPIRES (grpc_static_slice_table[69])
+#define GRPC_MDSTR_EXPIRES (grpc_static_slice_table[70])
 /* "from" */
-#define GRPC_MDSTR_FROM (grpc_static_slice_table[70])
+#define GRPC_MDSTR_FROM (grpc_static_slice_table[71])
 /* "if-match" */
-#define GRPC_MDSTR_IF_MATCH (grpc_static_slice_table[71])
+#define GRPC_MDSTR_IF_MATCH (grpc_static_slice_table[72])
 /* "if-modified-since" */
-#define GRPC_MDSTR_IF_MODIFIED_SINCE (grpc_static_slice_table[72])
+#define GRPC_MDSTR_IF_MODIFIED_SINCE (grpc_static_slice_table[73])
 /* "if-none-match" */
-#define GRPC_MDSTR_IF_NONE_MATCH (grpc_static_slice_table[73])
+#define GRPC_MDSTR_IF_NONE_MATCH (grpc_static_slice_table[74])
 /* "if-range" */
-#define GRPC_MDSTR_IF_RANGE (grpc_static_slice_table[74])
+#define GRPC_MDSTR_IF_RANGE (grpc_static_slice_table[75])
 /* "if-unmodified-since" */
-#define GRPC_MDSTR_IF_UNMODIFIED_SINCE (grpc_static_slice_table[75])
+#define GRPC_MDSTR_IF_UNMODIFIED_SINCE (grpc_static_slice_table[76])
 /* "last-modified" */
-#define GRPC_MDSTR_LAST_MODIFIED (grpc_static_slice_table[76])
+#define GRPC_MDSTR_LAST_MODIFIED (grpc_static_slice_table[77])
+/* "lb-cost-bin" */
+#define GRPC_MDSTR_LB_COST_BIN (grpc_static_slice_table[78])
 /* "link" */
-#define GRPC_MDSTR_LINK (grpc_static_slice_table[77])
+#define GRPC_MDSTR_LINK (grpc_static_slice_table[79])
 /* "location" */
-#define GRPC_MDSTR_LOCATION (grpc_static_slice_table[78])
+#define GRPC_MDSTR_LOCATION (grpc_static_slice_table[80])
 /* "max-forwards" */
-#define GRPC_MDSTR_MAX_FORWARDS (grpc_static_slice_table[79])
+#define GRPC_MDSTR_MAX_FORWARDS (grpc_static_slice_table[81])
 /* "proxy-authenticate" */
-#define GRPC_MDSTR_PROXY_AUTHENTICATE (grpc_static_slice_table[80])
+#define GRPC_MDSTR_PROXY_AUTHENTICATE (grpc_static_slice_table[82])
 /* "proxy-authorization" */
-#define GRPC_MDSTR_PROXY_AUTHORIZATION (grpc_static_slice_table[81])
+#define GRPC_MDSTR_PROXY_AUTHORIZATION (grpc_static_slice_table[83])
 /* "range" */
-#define GRPC_MDSTR_RANGE (grpc_static_slice_table[82])
+#define GRPC_MDSTR_RANGE (grpc_static_slice_table[84])
 /* "referer" */
-#define GRPC_MDSTR_REFERER (grpc_static_slice_table[83])
+#define GRPC_MDSTR_REFERER (grpc_static_slice_table[85])
 /* "refresh" */
-#define GRPC_MDSTR_REFRESH (grpc_static_slice_table[84])
+#define GRPC_MDSTR_REFRESH (grpc_static_slice_table[86])
 /* "retry-after" */
-#define GRPC_MDSTR_RETRY_AFTER (grpc_static_slice_table[85])
+#define GRPC_MDSTR_RETRY_AFTER (grpc_static_slice_table[87])
 /* "server" */
-#define GRPC_MDSTR_SERVER (grpc_static_slice_table[86])
+#define GRPC_MDSTR_SERVER (grpc_static_slice_table[88])
 /* "set-cookie" */
-#define GRPC_MDSTR_SET_COOKIE (grpc_static_slice_table[87])
+#define GRPC_MDSTR_SET_COOKIE (grpc_static_slice_table[89])
 /* "strict-transport-security" */
-#define GRPC_MDSTR_STRICT_TRANSPORT_SECURITY (grpc_static_slice_table[88])
+#define GRPC_MDSTR_STRICT_TRANSPORT_SECURITY (grpc_static_slice_table[90])
 /* "transfer-encoding" */
-#define GRPC_MDSTR_TRANSFER_ENCODING (grpc_static_slice_table[89])
+#define GRPC_MDSTR_TRANSFER_ENCODING (grpc_static_slice_table[91])
 /* "vary" */
-#define GRPC_MDSTR_VARY (grpc_static_slice_table[90])
+#define GRPC_MDSTR_VARY (grpc_static_slice_table[92])
 /* "via" */
-#define GRPC_MDSTR_VIA (grpc_static_slice_table[91])
+#define GRPC_MDSTR_VIA (grpc_static_slice_table[93])
 /* "www-authenticate" */
-#define GRPC_MDSTR_WWW_AUTHENTICATE (grpc_static_slice_table[92])
+#define GRPC_MDSTR_WWW_AUTHENTICATE (grpc_static_slice_table[94])
 /* "identity,deflate" */
-#define GRPC_MDSTR_IDENTITY_COMMA_DEFLATE (grpc_static_slice_table[93])
+#define GRPC_MDSTR_IDENTITY_COMMA_DEFLATE (grpc_static_slice_table[95])
 /* "identity,gzip" */
-#define GRPC_MDSTR_IDENTITY_COMMA_GZIP (grpc_static_slice_table[94])
+#define GRPC_MDSTR_IDENTITY_COMMA_GZIP (grpc_static_slice_table[96])
 /* "deflate,gzip" */
-#define GRPC_MDSTR_DEFLATE_COMMA_GZIP (grpc_static_slice_table[95])
+#define GRPC_MDSTR_DEFLATE_COMMA_GZIP (grpc_static_slice_table[97])
 /* "identity,deflate,gzip" */
 #define GRPC_MDSTR_IDENTITY_COMMA_DEFLATE_COMMA_GZIP \
-  (grpc_static_slice_table[96])
+  (grpc_static_slice_table[98])
 
 extern const grpc_slice_refcount_vtable grpc_static_metadata_vtable;
 extern grpc_slice_refcount
@@ -255,7 +259,7 @@
 #define GRPC_STATIC_METADATA_INDEX(static_slice) \
   ((int)((static_slice).refcount - grpc_static_metadata_refcounts))
 
-#define GRPC_STATIC_MDELEM_COUNT 80
+#define GRPC_STATIC_MDELEM_COUNT 81
 extern grpc_mdelem_data grpc_static_mdelem_table[GRPC_STATIC_MDELEM_COUNT];
 extern uintptr_t grpc_static_mdelem_user_data[GRPC_STATIC_MDELEM_COUNT];
 /* "grpc-status": "0" */
@@ -426,78 +430,81 @@
 /* "lb-token": "" */
 #define GRPC_MDELEM_LB_TOKEN_EMPTY \
   (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[55], GRPC_MDELEM_STORAGE_STATIC))
+/* "lb-cost-bin": "" */
+#define GRPC_MDELEM_LB_COST_BIN_EMPTY \
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[56], GRPC_MDELEM_STORAGE_STATIC))
 /* "link": "" */
 #define GRPC_MDELEM_LINK_EMPTY \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[56], GRPC_MDELEM_STORAGE_STATIC))
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[57], GRPC_MDELEM_STORAGE_STATIC))
 /* "location": "" */
 #define GRPC_MDELEM_LOCATION_EMPTY \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[57], GRPC_MDELEM_STORAGE_STATIC))
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[58], GRPC_MDELEM_STORAGE_STATIC))
 /* "max-forwards": "" */
 #define GRPC_MDELEM_MAX_FORWARDS_EMPTY \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[58], GRPC_MDELEM_STORAGE_STATIC))
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[59], GRPC_MDELEM_STORAGE_STATIC))
 /* "proxy-authenticate": "" */
 #define GRPC_MDELEM_PROXY_AUTHENTICATE_EMPTY \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[59], GRPC_MDELEM_STORAGE_STATIC))
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[60], GRPC_MDELEM_STORAGE_STATIC))
 /* "proxy-authorization": "" */
 #define GRPC_MDELEM_PROXY_AUTHORIZATION_EMPTY \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[60], GRPC_MDELEM_STORAGE_STATIC))
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[61], GRPC_MDELEM_STORAGE_STATIC))
 /* "range": "" */
 #define GRPC_MDELEM_RANGE_EMPTY \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[61], GRPC_MDELEM_STORAGE_STATIC))
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[62], GRPC_MDELEM_STORAGE_STATIC))
 /* "referer": "" */
 #define GRPC_MDELEM_REFERER_EMPTY \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[62], GRPC_MDELEM_STORAGE_STATIC))
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[63], GRPC_MDELEM_STORAGE_STATIC))
 /* "refresh": "" */
 #define GRPC_MDELEM_REFRESH_EMPTY \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[63], GRPC_MDELEM_STORAGE_STATIC))
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[64], GRPC_MDELEM_STORAGE_STATIC))
 /* "retry-after": "" */
 #define GRPC_MDELEM_RETRY_AFTER_EMPTY \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[64], GRPC_MDELEM_STORAGE_STATIC))
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[65], GRPC_MDELEM_STORAGE_STATIC))
 /* "server": "" */
 #define GRPC_MDELEM_SERVER_EMPTY \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[65], GRPC_MDELEM_STORAGE_STATIC))
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[66], GRPC_MDELEM_STORAGE_STATIC))
 /* "set-cookie": "" */
 #define GRPC_MDELEM_SET_COOKIE_EMPTY \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[66], GRPC_MDELEM_STORAGE_STATIC))
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[67], GRPC_MDELEM_STORAGE_STATIC))
 /* "strict-transport-security": "" */
 #define GRPC_MDELEM_STRICT_TRANSPORT_SECURITY_EMPTY \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[67], GRPC_MDELEM_STORAGE_STATIC))
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[68], GRPC_MDELEM_STORAGE_STATIC))
 /* "transfer-encoding": "" */
 #define GRPC_MDELEM_TRANSFER_ENCODING_EMPTY \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[68], GRPC_MDELEM_STORAGE_STATIC))
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[69], GRPC_MDELEM_STORAGE_STATIC))
 /* "user-agent": "" */
 #define GRPC_MDELEM_USER_AGENT_EMPTY \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[69], GRPC_MDELEM_STORAGE_STATIC))
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[70], GRPC_MDELEM_STORAGE_STATIC))
 /* "vary": "" */
 #define GRPC_MDELEM_VARY_EMPTY \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[70], GRPC_MDELEM_STORAGE_STATIC))
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[71], GRPC_MDELEM_STORAGE_STATIC))
 /* "via": "" */
 #define GRPC_MDELEM_VIA_EMPTY \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[71], GRPC_MDELEM_STORAGE_STATIC))
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[72], GRPC_MDELEM_STORAGE_STATIC))
 /* "www-authenticate": "" */
 #define GRPC_MDELEM_WWW_AUTHENTICATE_EMPTY \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[72], GRPC_MDELEM_STORAGE_STATIC))
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[73], GRPC_MDELEM_STORAGE_STATIC))
 /* "grpc-accept-encoding": "identity" */
 #define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_IDENTITY \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[73], GRPC_MDELEM_STORAGE_STATIC))
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[74], GRPC_MDELEM_STORAGE_STATIC))
 /* "grpc-accept-encoding": "deflate" */
 #define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_DEFLATE \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[74], GRPC_MDELEM_STORAGE_STATIC))
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[75], GRPC_MDELEM_STORAGE_STATIC))
 /* "grpc-accept-encoding": "identity,deflate" */
 #define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_IDENTITY_COMMA_DEFLATE \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[75], GRPC_MDELEM_STORAGE_STATIC))
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[76], GRPC_MDELEM_STORAGE_STATIC))
 /* "grpc-accept-encoding": "gzip" */
 #define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_GZIP \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[76], GRPC_MDELEM_STORAGE_STATIC))
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[77], GRPC_MDELEM_STORAGE_STATIC))
 /* "grpc-accept-encoding": "identity,gzip" */
 #define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_IDENTITY_COMMA_GZIP \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[77], GRPC_MDELEM_STORAGE_STATIC))
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[78], GRPC_MDELEM_STORAGE_STATIC))
 /* "grpc-accept-encoding": "deflate,gzip" */
 #define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_DEFLATE_COMMA_GZIP \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[78], GRPC_MDELEM_STORAGE_STATIC))
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[79], GRPC_MDELEM_STORAGE_STATIC))
 /* "grpc-accept-encoding": "identity,deflate,gzip" */
 #define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_IDENTITY_COMMA_DEFLATE_COMMA_GZIP \
-  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[79], GRPC_MDELEM_STORAGE_STATIC))
+  (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[80], GRPC_MDELEM_STORAGE_STATIC))
 
 grpc_mdelem grpc_static_mdelem_for_static_strings(int a, int b);
 typedef enum {
@@ -512,6 +519,9 @@
   GRPC_BATCH_GRPC_PAYLOAD_BIN,
   GRPC_BATCH_GRPC_ENCODING,
   GRPC_BATCH_GRPC_ACCEPT_ENCODING,
+  GRPC_BATCH_GRPC_SERVER_STATS_BIN,
+  GRPC_BATCH_GRPC_TAGS_BIN,
+  GRPC_BATCH_GRPC_TRACE_BIN,
   GRPC_BATCH_CONTENT_TYPE,
   GRPC_BATCH_GRPC_INTERNAL_ENCODING_REQUEST,
   GRPC_BATCH_USER_AGENT,
@@ -534,6 +544,9 @@
     struct grpc_linked_mdelem *grpc_payload_bin;
     struct grpc_linked_mdelem *grpc_encoding;
     struct grpc_linked_mdelem *grpc_accept_encoding;
+    struct grpc_linked_mdelem *grpc_server_stats_bin;
+    struct grpc_linked_mdelem *grpc_tags_bin;
+    struct grpc_linked_mdelem *grpc_trace_bin;
     struct grpc_linked_mdelem *content_type;
     struct grpc_linked_mdelem *grpc_internal_encoding_request;
     struct grpc_linked_mdelem *user_agent;
diff --git a/src/core/plugin_registry/grpc_cronet_plugin_registry.c b/src/core/plugin_registry/grpc_cronet_plugin_registry.c
index c97f47b..907e5a0 100644
--- a/src/core/plugin_registry/grpc_cronet_plugin_registry.c
+++ b/src/core/plugin_registry/grpc_cronet_plugin_registry.c
@@ -33,16 +33,24 @@
 
 #include <grpc/grpc.h>
 
+extern void grpc_http_filters_init(void);
+extern void grpc_http_filters_shutdown(void);
 extern void grpc_chttp2_plugin_init(void);
 extern void grpc_chttp2_plugin_shutdown(void);
+extern void grpc_deadline_filter_init(void);
+extern void grpc_deadline_filter_shutdown(void);
 extern void grpc_client_channel_init(void);
 extern void grpc_client_channel_shutdown(void);
 extern void grpc_load_reporting_plugin_init(void);
 extern void grpc_load_reporting_plugin_shutdown(void);
 
 void grpc_register_built_in_plugins(void) {
+  grpc_register_plugin(grpc_http_filters_init,
+                       grpc_http_filters_shutdown);
   grpc_register_plugin(grpc_chttp2_plugin_init,
                        grpc_chttp2_plugin_shutdown);
+  grpc_register_plugin(grpc_deadline_filter_init,
+                       grpc_deadline_filter_shutdown);
   grpc_register_plugin(grpc_client_channel_init,
                        grpc_client_channel_shutdown);
   grpc_register_plugin(grpc_load_reporting_plugin_init,
diff --git a/src/core/plugin_registry/grpc_plugin_registry.c b/src/core/plugin_registry/grpc_plugin_registry.c
index 803a26b..25bda7a 100644
--- a/src/core/plugin_registry/grpc_plugin_registry.c
+++ b/src/core/plugin_registry/grpc_plugin_registry.c
@@ -33,8 +33,12 @@
 
 #include <grpc/grpc.h>
 
+extern void grpc_http_filters_init(void);
+extern void grpc_http_filters_shutdown(void);
 extern void grpc_chttp2_plugin_init(void);
 extern void grpc_chttp2_plugin_shutdown(void);
+extern void grpc_deadline_filter_init(void);
+extern void grpc_deadline_filter_shutdown(void);
 extern void grpc_client_channel_init(void);
 extern void grpc_client_channel_shutdown(void);
 extern void grpc_lb_policy_grpclb_init(void);
@@ -55,10 +59,16 @@
 extern void census_grpc_plugin_shutdown(void);
 extern void grpc_max_age_filter_init(void);
 extern void grpc_max_age_filter_shutdown(void);
+extern void grpc_message_size_filter_init(void);
+extern void grpc_message_size_filter_shutdown(void);
 
 void grpc_register_built_in_plugins(void) {
+  grpc_register_plugin(grpc_http_filters_init,
+                       grpc_http_filters_shutdown);
   grpc_register_plugin(grpc_chttp2_plugin_init,
                        grpc_chttp2_plugin_shutdown);
+  grpc_register_plugin(grpc_deadline_filter_init,
+                       grpc_deadline_filter_shutdown);
   grpc_register_plugin(grpc_client_channel_init,
                        grpc_client_channel_shutdown);
   grpc_register_plugin(grpc_lb_policy_grpclb_init,
@@ -79,4 +89,6 @@
                        census_grpc_plugin_shutdown);
   grpc_register_plugin(grpc_max_age_filter_init,
                        grpc_max_age_filter_shutdown);
+  grpc_register_plugin(grpc_message_size_filter_init,
+                       grpc_message_size_filter_shutdown);
 }
diff --git a/src/core/plugin_registry/grpc_unsecure_plugin_registry.c b/src/core/plugin_registry/grpc_unsecure_plugin_registry.c
index e65fc24..05d4771 100644
--- a/src/core/plugin_registry/grpc_unsecure_plugin_registry.c
+++ b/src/core/plugin_registry/grpc_unsecure_plugin_registry.c
@@ -33,8 +33,12 @@
 
 #include <grpc/grpc.h>
 
+extern void grpc_http_filters_init(void);
+extern void grpc_http_filters_shutdown(void);
 extern void grpc_chttp2_plugin_init(void);
 extern void grpc_chttp2_plugin_shutdown(void);
+extern void grpc_deadline_filter_init(void);
+extern void grpc_deadline_filter_shutdown(void);
 extern void grpc_client_channel_init(void);
 extern void grpc_client_channel_shutdown(void);
 extern void grpc_resolver_dns_ares_init(void);
@@ -55,10 +59,16 @@
 extern void census_grpc_plugin_shutdown(void);
 extern void grpc_max_age_filter_init(void);
 extern void grpc_max_age_filter_shutdown(void);
+extern void grpc_message_size_filter_init(void);
+extern void grpc_message_size_filter_shutdown(void);
 
 void grpc_register_built_in_plugins(void) {
+  grpc_register_plugin(grpc_http_filters_init,
+                       grpc_http_filters_shutdown);
   grpc_register_plugin(grpc_chttp2_plugin_init,
                        grpc_chttp2_plugin_shutdown);
+  grpc_register_plugin(grpc_deadline_filter_init,
+                       grpc_deadline_filter_shutdown);
   grpc_register_plugin(grpc_client_channel_init,
                        grpc_client_channel_shutdown);
   grpc_register_plugin(grpc_resolver_dns_ares_init,
@@ -79,4 +89,6 @@
                        census_grpc_plugin_shutdown);
   grpc_register_plugin(grpc_max_age_filter_init,
                        grpc_max_age_filter_shutdown);
+  grpc_register_plugin(grpc_message_size_filter_init,
+                       grpc_message_size_filter_shutdown);
 }
diff --git a/src/cpp/common/core_codegen.cc b/src/cpp/common/core_codegen.cc
index 43dffe7..0dd758e 100644
--- a/src/cpp/common/core_codegen.cc
+++ b/src/cpp/common/core_codegen.cc
@@ -54,9 +54,14 @@
 
 namespace grpc {
 
-grpc_completion_queue* CoreCodegen::grpc_completion_queue_create(
+grpc_completion_queue* CoreCodegen::grpc_completion_queue_create_for_next(
     void* reserved) {
-  return ::grpc_completion_queue_create(reserved);
+  return ::grpc_completion_queue_create_for_next(reserved);
+}
+
+grpc_completion_queue* CoreCodegen::grpc_completion_queue_create_for_pluck(
+    void* reserved) {
+  return ::grpc_completion_queue_create_for_pluck(reserved);
 }
 
 void CoreCodegen::grpc_completion_queue_destroy(grpc_completion_queue* cq) {
diff --git a/src/cpp/common/version_cc.cc b/src/cpp/common/version_cc.cc
index f5a0e41..72a4c4c 100644
--- a/src/cpp/common/version_cc.cc
+++ b/src/cpp/common/version_cc.cc
@@ -37,5 +37,5 @@
 #include <grpc++/grpc++.h>
 
 namespace grpc {
-grpc::string Version() { return "1.3.0-dev"; }
+grpc::string Version() { return "1.4.0-dev"; }
 }
diff --git a/src/cpp/server/server_builder.cc b/src/cpp/server/server_builder.cc
index 4eb4b5a..3a15afc 100644
--- a/src/cpp/server/server_builder.cc
+++ b/src/cpp/server/server_builder.cc
@@ -337,10 +337,7 @@
   }
 
   auto cqs_data = cqs_.empty() ? nullptr : &cqs_[0];
-  if (!server->Start(cqs_data, cqs_.size())) {
-    if (added_port) server->Shutdown();
-    return nullptr;
-  }
+  server->Start(cqs_data, cqs_.size());
 
   for (auto plugin = plugins_.begin(); plugin != plugins_.end(); plugin++) {
     (*plugin)->Finish(initializer);
diff --git a/src/cpp/server/server_cc.cc b/src/cpp/server/server_cc.cc
index ce173a1..62ded0d 100644
--- a/src/cpp/server/server_cc.cc
+++ b/src/cpp/server/server_cc.cc
@@ -124,6 +124,14 @@
   bool FinalizeResult(void** tag, bool* status) { return false; }
 };
 
+class DummyTag : public CompletionQueueTag {
+ public:
+  bool FinalizeResult(void** tag, bool* status) {
+    *status = true;
+    return true;
+  }
+};
+
 class Server::SyncRequest final : public CompletionQueueTag {
  public:
   SyncRequest(RpcServiceMethod* method, void* tag)
@@ -145,7 +153,7 @@
     grpc_metadata_array_destroy(&request_metadata_);
   }
 
-  void SetupRequest() { cq_ = grpc_completion_queue_create(nullptr); }
+  void SetupRequest() { cq_ = grpc_completion_queue_create_for_pluck(nullptr); }
 
   void TeardownRequest() {
     grpc_completion_queue_destroy(cq_);
@@ -213,10 +221,15 @@
           MethodHandler::HandlerParameter(&call_, &ctx_, request_payload_));
       global_callbacks->PostSynchronousRequest(&ctx_);
       request_payload_ = nullptr;
-      void* ignored_tag;
-      bool ignored_ok;
+
       cq_.Shutdown();
-      GPR_ASSERT(cq_.Next(&ignored_tag, &ignored_ok) == false);
+
+      CompletionQueueTag* op_tag = ctx_.GetCompletionOpTag();
+      cq_.TryPluck(op_tag, gpr_inf_future(GPR_CLOCK_REALTIME));
+
+      /* Ensure the cq_ is shutdown */
+      DummyTag ignored_tag;
+      GPR_ASSERT(cq_.Pluck(&ignored_tag) == false);
     }
 
    private:
@@ -490,11 +503,11 @@
                              ServerCredentials* creds) {
   GPR_ASSERT(!started_);
   int port = creds->AddPortToServer(addr, server_);
-  global_callbacks_->AddPort(this, port);
+  global_callbacks_->AddPort(this, addr, creds, port);
   return port;
 }
 
-bool Server::Start(ServerCompletionQueue** cqs, size_t num_cqs) {
+void Server::Start(ServerCompletionQueue** cqs, size_t num_cqs) {
   GPR_ASSERT(!started_);
   global_callbacks_->PreServerStart(this);
   started_ = true;
@@ -530,8 +543,6 @@
   for (auto it = sync_req_mgrs_.begin(); it != sync_req_mgrs_.end(); it++) {
     (*it)->Start();
   }
-
-  return true;
 }
 
 void Server::ShutdownInternal(gpr_timespec deadline) {
diff --git a/src/cpp/server/server_context.cc b/src/cpp/server/server_context.cc
index 3a408eb..33ad0ae 100644
--- a/src/cpp/server/server_context.cc
+++ b/src/cpp/server/server_context.cc
@@ -167,6 +167,10 @@
   call->PerformOps(completion_op_);
 }
 
+CompletionQueueTag* ServerContext::GetCompletionOpTag() {
+  return static_cast<CompletionQueueTag*>(completion_op_);
+}
+
 void ServerContext::AddInitialMetadata(const grpc::string& key,
                                        const grpc::string& value) {
   initial_metadata_.insert(std::make_pair(key, value));
@@ -225,17 +229,9 @@
 void ServerContext::SetLoadReportingCosts(
     const std::vector<grpc::string>& cost_data) {
   if (call_ == nullptr) return;
-  grpc_load_reporting_cost_context* cost_ctx =
-      static_cast<grpc_load_reporting_cost_context*>(
-          gpr_malloc(sizeof(*cost_ctx)));
-  cost_ctx->values_count = cost_data.size();
-  cost_ctx->values = static_cast<grpc_slice*>(
-      gpr_malloc(sizeof(*cost_ctx->values) * cost_ctx->values_count));
-  for (size_t i = 0; i < cost_ctx->values_count; ++i) {
-    cost_ctx->values[i] =
-        grpc_slice_from_copied_buffer(cost_data[i].data(), cost_data[i].size());
+  for (const auto& cost_datum : cost_data) {
+    AddTrailingMetadata(GRPC_LB_COST_MD_KEY, cost_datum);
   }
-  grpc_call_set_load_reporting_cost_context(call_, cost_ctx);
 }
 
 }  // namespace grpc
diff --git a/src/core/lib/channel/http_client_filter.h b/src/cpp/util/error_details.cc
similarity index 63%
copy from src/core/lib/channel/http_client_filter.h
copy to src/cpp/util/error_details.cc
index 9e6e106..8bba05a 100644
--- a/src/core/lib/channel/http_client_filter.h
+++ b/src/cpp/util/error_details.cc
@@ -1,5 +1,6 @@
 /*
- * Copyright 2015, Google Inc.
+ *
+ * Copyright 2017, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -30,18 +31,32 @@
  *
  */
 
-#ifndef GRPC_CORE_LIB_CHANNEL_HTTP_CLIENT_FILTER_H
-#define GRPC_CORE_LIB_CHANNEL_HTTP_CLIENT_FILTER_H
+#include <grpc++/support/error_details.h>
 
-#include "src/core/lib/channel/channel_stack.h"
+#include "src/proto/grpc/status/status.pb.h"
 
-/* Processes metadata on the client side for HTTP2 transports */
-extern const grpc_channel_filter grpc_http_client_filter;
+namespace grpc {
 
-/* Channel arg to override the http2 :scheme header */
-#define GRPC_ARG_HTTP2_SCHEME "grpc.http2_scheme"
+Status ExtractErrorDetails(const Status& from, ::google::rpc::Status* to) {
+  if (to == nullptr) {
+    return Status(StatusCode::FAILED_PRECONDITION, "");
+  }
+  if (!to->ParseFromString(from.error_details())) {
+    return Status(StatusCode::INVALID_ARGUMENT, "");
+  }
+  return Status::OK;
+}
 
-/* Channel arg to determine maximum size of payload eligable for GET request */
-#define GRPC_ARG_MAX_PAYLOAD_SIZE_FOR_GET "grpc.max_payload_size_for_get"
+Status SetErrorDetails(const ::google::rpc::Status& from, Status* to) {
+  if (to == nullptr) {
+    return Status(StatusCode::FAILED_PRECONDITION, "");
+  }
+  StatusCode code = StatusCode::UNKNOWN;
+  if (from.code() >= StatusCode::OK && from.code() <= StatusCode::DATA_LOSS) {
+    code = static_cast<StatusCode>(from.code());
+  }
+  *to = Status(code, from.message(), from.SerializeAsString());
+  return Status::OK;
+}
 
-#endif /* GRPC_CORE_LIB_CHANNEL_HTTP_CLIENT_FILTER_H */
+}  // namespace grpc
diff --git a/src/csharp/Grpc.Auth/project.json b/src/csharp/Grpc.Auth/project.json
deleted file mode 100644
index 370bf11..0000000
--- a/src/csharp/Grpc.Auth/project.json
+++ /dev/null
@@ -1,35 +0,0 @@
-{
-  "version": "1.3.0-dev",
-  "title": "gRPC C# Auth",
-  "authors": [ "Google Inc." ],
-  "copyright": "Copyright 2015, Google Inc.",
-  "packOptions": {
-    "summary": "Auth library for C# implementation of gRPC - an RPC library and framework",
-    "description": "Auth library for C# implementation of gRPC - an RPC library and framework. See project site for more info.",
-    "owners": [ "grpc-packages" ],
-    "licenseUrl": "https://github.com/grpc/grpc/blob/master/LICENSE",
-    "projectUrl": "https://github.com/grpc/grpc",
-    "requireLicenseAcceptance": false,
-    "tags": [ "gRPC RPC Protocol HTTP/2 Auth OAuth2" ],
-  },
-  "buildOptions": {
-    "define": [ "SIGNED" ],
-    "keyFile": "../keys/Grpc.snk",
-    "xmlDoc": true,
-    "compile": {
-      "includeFiles": [ "../Grpc.Core/Version.cs" ]
-    }
-  },
-  "dependencies": {
-    "Grpc.Core": "1.3.0-dev",
-    "Google.Apis.Auth": "1.21.0"
-  },
-  "frameworks": {
-    "net45": { },
-    "netstandard1.5": {
-      "dependencies": {
-        "NETStandard.Library": "1.6.0"
-      }
-    }
-  }
-}
diff --git a/src/csharp/Grpc.Core.Testing/project.json b/src/csharp/Grpc.Core.Testing/project.json
deleted file mode 100644
index 38d5fab..0000000
--- a/src/csharp/Grpc.Core.Testing/project.json
+++ /dev/null
@@ -1,39 +0,0 @@
-{
-  "version": "1.3.0-dev",
-  "title": "gRPC C# Core Testing",
-  "authors": [ "Google Inc." ],
-  "copyright": "Copyright 2017, Google Inc.",
-  "packOptions": {
-    "summary": "Testing support for gRPC C#",
-    "description": "Useful when testing code that uses gRPC.",
-    "owners": [ "grpc-packages" ],
-    "licenseUrl": "https://github.com/grpc/grpc/blob/master/LICENSE",
-    "projectUrl": "https://github.com/grpc/grpc",
-    "requireLicenseAcceptance": false,
-    "tags": [ "gRPC test testing" ]
-  },
-  "buildOptions": {
-    "define": [ "SIGNED" ],
-    "keyFile": "../keys/Grpc.snk",
-    "xmlDoc": true,
-    "compile": {
-      "includeFiles": [ "../Grpc.Core/Version.cs" ]
-    }
-  },
-  "dependencies": {
-    "Grpc.Core": "1.3.0-dev"
-  },
-  "frameworks": {
-    "net45": {
-      "frameworkAssemblies": {
-        "System.Runtime": "",
-        "System.IO": ""
-      }
-    },
-    "netstandard1.5": {
-      "dependencies": {
-        "NETStandard.Library": "1.6.0"
-      }
-    }
-  }
-}
diff --git a/src/csharp/Grpc.Core.Tests/Internal/CompletionQueueSafeHandleTest.cs b/src/csharp/Grpc.Core.Tests/Internal/CompletionQueueSafeHandleTest.cs
index e9ec59e..8649906 100644
--- a/src/csharp/Grpc.Core.Tests/Internal/CompletionQueueSafeHandleTest.cs
+++ b/src/csharp/Grpc.Core.Tests/Internal/CompletionQueueSafeHandleTest.cs
@@ -43,19 +43,19 @@
     public class CompletionQueueSafeHandleTest
     {
         [Test]
-        public void CreateAndDestroy()
+        public void CreateSyncAndDestroy()
         {
             GrpcEnvironment.AddRef();
-            var cq = CompletionQueueSafeHandle.Create();
+            var cq = CompletionQueueSafeHandle.CreateSync();
             cq.Dispose();
             GrpcEnvironment.ReleaseAsync().Wait();
         }
 
         [Test]
-        public void CreateAndShutdown()
+        public void CreateAsyncAndShutdown()
         {
-            GrpcEnvironment.AddRef();
-            var cq = CompletionQueueSafeHandle.Create();
+            var env = GrpcEnvironment.AddRef();
+            var cq = CompletionQueueSafeHandle.CreateAsync(new CompletionRegistry(env));
             cq.Shutdown();
             var ev = cq.Next();
             cq.Dispose();
diff --git a/src/csharp/Grpc.Core.Tests/PInvokeTest.cs b/src/csharp/Grpc.Core.Tests/PInvokeTest.cs
index d3735c7..d760717 100644
--- a/src/csharp/Grpc.Core.Tests/PInvokeTest.cs
+++ b/src/csharp/Grpc.Core.Tests/PInvokeTest.cs
@@ -53,7 +53,7 @@
         /// (~1.26us .NET Windows)
         /// </summary>
         [Test]
-        public void CompletionQueueCreateDestroyBenchmark()
+        public void CompletionQueueCreateSyncDestroyBenchmark()
         {
             GrpcEnvironment.AddRef();  // completion queue requires gRPC environment being initialized.
 
@@ -61,7 +61,7 @@
                 10, 10,
                 () =>
                 {
-                    CompletionQueueSafeHandle cq = CompletionQueueSafeHandle.Create();
+                    CompletionQueueSafeHandle cq = CompletionQueueSafeHandle.CreateSync();
                     cq.Dispose();
                 });
 
diff --git a/src/csharp/Grpc.Core/Internal/AsyncCall.cs b/src/csharp/Grpc.Core/Internal/AsyncCall.cs
index 1f738a3..f037b23 100644
--- a/src/csharp/Grpc.Core/Internal/AsyncCall.cs
+++ b/src/csharp/Grpc.Core/Internal/AsyncCall.cs
@@ -87,7 +87,7 @@
             var profiler = Profilers.ForCurrentThread();
 
             using (profiler.NewScope("AsyncCall.UnaryCall"))
-            using (CompletionQueueSafeHandle cq = CompletionQueueSafeHandle.Create())
+            using (CompletionQueueSafeHandle cq = CompletionQueueSafeHandle.CreateSync())
             {
                 byte[] payload = UnsafeSerialize(msg);
 
diff --git a/src/csharp/Grpc.Core/Internal/CompletionQueueSafeHandle.cs b/src/csharp/Grpc.Core/Internal/CompletionQueueSafeHandle.cs
index 6c9a319..577d704 100644
--- a/src/csharp/Grpc.Core/Internal/CompletionQueueSafeHandle.cs
+++ b/src/csharp/Grpc.Core/Internal/CompletionQueueSafeHandle.cs
@@ -51,14 +51,20 @@
         {
         }
 
-        public static CompletionQueueSafeHandle Create()
+        /// <summary>
+        /// Create a completion queue that can only be used for Pluck operations.
+        /// </summary>
+        public static CompletionQueueSafeHandle CreateSync()
         {
-            return Native.grpcsharp_completion_queue_create();
+            return Native.grpcsharp_completion_queue_create_sync();
         }
 
-        public static CompletionQueueSafeHandle Create(CompletionRegistry completionRegistry)
+        /// <summary>
+        /// Create a completion queue that can only be used for Next operations.
+        /// </summary>
+        public static CompletionQueueSafeHandle CreateAsync(CompletionRegistry completionRegistry)
         {
-            var cq = Native.grpcsharp_completion_queue_create();
+            var cq = Native.grpcsharp_completion_queue_create_async();
             cq.completionRegistry = completionRegistry;
             return cq;
         }
diff --git a/src/csharp/Grpc.Core/Internal/GrpcThreadPool.cs b/src/csharp/Grpc.Core/Internal/GrpcThreadPool.cs
index 25a6589..07fea81 100644
--- a/src/csharp/Grpc.Core/Internal/GrpcThreadPool.cs
+++ b/src/csharp/Grpc.Core/Internal/GrpcThreadPool.cs
@@ -197,7 +197,7 @@
             for (int i = 0; i < completionQueueCount; i++)
             {
                 var completionRegistry = new CompletionRegistry(environment);
-                list.Add(CompletionQueueSafeHandle.Create(completionRegistry));
+                list.Add(CompletionQueueSafeHandle.CreateAsync(completionRegistry));
             }
             return list.AsReadOnly();
         }
diff --git a/src/csharp/Grpc.Core/Internal/NativeMethods.cs b/src/csharp/Grpc.Core/Internal/NativeMethods.cs
index dd65f05..a98861a 100644
--- a/src/csharp/Grpc.Core/Internal/NativeMethods.cs
+++ b/src/csharp/Grpc.Core/Internal/NativeMethods.cs
@@ -115,7 +115,8 @@
 
         public readonly Delegates.grpcsharp_sizeof_grpc_event_delegate grpcsharp_sizeof_grpc_event;
 
-        public readonly Delegates.grpcsharp_completion_queue_create_delegate grpcsharp_completion_queue_create;
+        public readonly Delegates.grpcsharp_completion_queue_create_async_delegate grpcsharp_completion_queue_create_async;
+        public readonly Delegates.grpcsharp_completion_queue_create_sync_delegate grpcsharp_completion_queue_create_sync;
         public readonly Delegates.grpcsharp_completion_queue_shutdown_delegate grpcsharp_completion_queue_shutdown;
         public readonly Delegates.grpcsharp_completion_queue_next_delegate grpcsharp_completion_queue_next;
         public readonly Delegates.grpcsharp_completion_queue_pluck_delegate grpcsharp_completion_queue_pluck;
@@ -229,7 +230,8 @@
 
             this.grpcsharp_sizeof_grpc_event = GetMethodDelegate<Delegates.grpcsharp_sizeof_grpc_event_delegate>(library);
 
-            this.grpcsharp_completion_queue_create = GetMethodDelegate<Delegates.grpcsharp_completion_queue_create_delegate>(library);
+            this.grpcsharp_completion_queue_create_async = GetMethodDelegate<Delegates.grpcsharp_completion_queue_create_async_delegate>(library);
+            this.grpcsharp_completion_queue_create_sync = GetMethodDelegate<Delegates.grpcsharp_completion_queue_create_sync_delegate>(library);
             this.grpcsharp_completion_queue_shutdown = GetMethodDelegate<Delegates.grpcsharp_completion_queue_shutdown_delegate>(library);
             this.grpcsharp_completion_queue_next = GetMethodDelegate<Delegates.grpcsharp_completion_queue_next_delegate>(library);
             this.grpcsharp_completion_queue_pluck = GetMethodDelegate<Delegates.grpcsharp_completion_queue_pluck_delegate>(library);
@@ -383,7 +385,8 @@
 
             public delegate int grpcsharp_sizeof_grpc_event_delegate();
 
-            public delegate CompletionQueueSafeHandle grpcsharp_completion_queue_create_delegate();
+            public delegate CompletionQueueSafeHandle grpcsharp_completion_queue_create_async_delegate();
+            public delegate CompletionQueueSafeHandle grpcsharp_completion_queue_create_sync_delegate();
             public delegate void grpcsharp_completion_queue_shutdown_delegate(CompletionQueueSafeHandle cq);
             public delegate CompletionQueueEvent grpcsharp_completion_queue_next_delegate(CompletionQueueSafeHandle cq);
             public delegate CompletionQueueEvent grpcsharp_completion_queue_pluck_delegate(CompletionQueueSafeHandle cq, IntPtr tag);
diff --git a/src/csharp/Grpc.Core/Version.csproj.include b/src/csharp/Grpc.Core/Version.csproj.include
index ce9d0d2..6af2af1 100755
--- a/src/csharp/Grpc.Core/Version.csproj.include
+++ b/src/csharp/Grpc.Core/Version.csproj.include
@@ -1,7 +1,7 @@
 <!-- This file is generated -->
 <Project>
   <PropertyGroup>
-    <GrpcCsharpVersion>1.3.0-dev</GrpcCsharpVersion>
+    <GrpcCsharpVersion>1.4.0-dev</GrpcCsharpVersion>
     <GoogleProtobufVersion>3.2.0</GoogleProtobufVersion>
   </PropertyGroup>
 </Project>
diff --git a/src/csharp/Grpc.Core/VersionInfo.cs b/src/csharp/Grpc.Core/VersionInfo.cs
index 6012d90..2e55d9d 100644
--- a/src/csharp/Grpc.Core/VersionInfo.cs
+++ b/src/csharp/Grpc.Core/VersionInfo.cs
@@ -48,11 +48,11 @@
         /// <summary>
         /// Current <c>AssemblyFileVersion</c> of gRPC C# assemblies
         /// </summary>
-        public const string CurrentAssemblyFileVersion = "1.3.0.0";
+        public const string CurrentAssemblyFileVersion = "1.4.0.0";
 
         /// <summary>
         /// Current version of gRPC C#
         /// </summary>
-        public const string CurrentVersion = "1.3.0-dev";
+        public const string CurrentVersion = "1.4.0-dev";
     }
 }
diff --git a/src/csharp/Grpc.HealthCheck/project.json b/src/csharp/Grpc.HealthCheck/project.json
deleted file mode 100644
index e93d0bf..0000000
--- a/src/csharp/Grpc.HealthCheck/project.json
+++ /dev/null
@@ -1,35 +0,0 @@
-{
-  "version": "1.3.0-dev",
-  "title": "gRPC C# Healthchecking",
-  "authors": [ "Google Inc." ],
-  "copyright": "Copyright 2015, Google Inc.",
-  "packOptions": {
-    "summary": "Implementation of gRPC health service",
-    "description": "Example implementation of grpc.health.v1 service that can be used for health-checking.",
-    "owners": [ "grpc-packages" ],
-    "licenseUrl": "https://github.com/grpc/grpc/blob/master/LICENSE",
-    "projectUrl": "https://github.com/grpc/grpc",
-    "requireLicenseAcceptance": false,
-    "tags": [ "gRPC health check" ]
-  },
-  "buildOptions": {
-    "define": [ "SIGNED" ],
-    "keyFile": "../keys/Grpc.snk",
-    "xmlDoc": true,
-    "compile": {
-      "includeFiles": [ "../Grpc.Core/Version.cs" ]
-    }
-  },
-  "dependencies": {
-    "Grpc.Core": "1.3.0-dev",
-    "Google.Protobuf": "3.2.0"
-  },
-  "frameworks": {
-    "net45": {},
-    "netstandard1.5": {
-      "dependencies": {
-        "NETStandard.Library": "1.6.0"
-      }
-    }
-  }
-}
diff --git a/src/csharp/Grpc.Reflection/project.json b/src/csharp/Grpc.Reflection/project.json
deleted file mode 100644
index 014c78e..0000000
--- a/src/csharp/Grpc.Reflection/project.json
+++ /dev/null
@@ -1,35 +0,0 @@
-{
-  "version": "1.3.0-dev",
-  "title": "gRPC C# Reflection",
-  "authors": [ "Google Inc." ],
-  "copyright": "Copyright 2016, Google Inc.",
-  "packOptions": {
-    "summary": "Implementation of gRPC reflection service",
-    "description": "Provides information about services running on a gRPC C# server.",
-    "owners": [ "grpc-packages" ],
-    "licenseUrl": "https://github.com/grpc/grpc/blob/master/LICENSE",
-    "projectUrl": "https://github.com/grpc/grpc",
-    "requireLicenseAcceptance": false,
-    "tags": [ "gRPC reflection" ]
-  },
-  "buildOptions": {
-    "define": [ "SIGNED" ],
-    "keyFile": "../keys/Grpc.snk",
-    "xmlDoc": true,
-    "compile": {
-      "includeFiles": [ "../Grpc.Core/Version.cs" ]
-    }
-  },
-  "dependencies": {
-    "Grpc.Core": "1.3.0-dev",
-    "Google.Protobuf": "3.2.0"
-  },
-  "frameworks": {
-    "net45": {},
-    "netstandard1.5": {
-      "dependencies": {
-        "NETStandard.Library": "1.6.0"
-      }
-    }
-  }
-}
diff --git a/src/csharp/build_packages_dotnetcli.bat b/src/csharp/build_packages_dotnetcli.bat
index 7558ca6..673642e 100755
--- a/src/csharp/build_packages_dotnetcli.bat
+++ b/src/csharp/build_packages_dotnetcli.bat
@@ -28,7 +28,7 @@
 @rem OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 @rem Current package versions
-set VERSION=1.3.0-dev
+set VERSION=1.4.0-dev
 
 @rem Adjust the location of nuget.exe
 set NUGET=C:\nuget\nuget.exe
diff --git a/src/csharp/build_packages_dotnetcli.sh b/src/csharp/build_packages_dotnetcli.sh
index 2186bd3..ee923e3 100755
--- a/src/csharp/build_packages_dotnetcli.sh
+++ b/src/csharp/build_packages_dotnetcli.sh
@@ -70,7 +70,7 @@
 dotnet pack --configuration Release Grpc.HealthCheck --output ../../../artifacts
 dotnet pack --configuration Release Grpc.Reflection --output ../../../artifacts
 
-nuget pack Grpc.nuspec -Version "1.3.0-dev" -OutputDirectory ../../artifacts
-nuget pack Grpc.Tools.nuspec -Version "1.3.0-dev" -OutputDirectory ../../artifacts
+nuget pack Grpc.nuspec -Version "1.4.0-dev" -OutputDirectory ../../artifacts
+nuget pack Grpc.Tools.nuspec -Version "1.4.0-dev" -OutputDirectory ../../artifacts
 
 (cd ../../artifacts && zip csharp_nugets_dotnetcli.zip *.nupkg)
diff --git a/src/csharp/ext/grpc_csharp_ext.c b/src/csharp/ext/grpc_csharp_ext.c
index 491df4d..27de7bc 100644
--- a/src/csharp/ext/grpc_csharp_ext.c
+++ b/src/csharp/ext/grpc_csharp_ext.c
@@ -354,8 +354,13 @@
 /* Completion queue */
 
 GPR_EXPORT grpc_completion_queue *GPR_CALLTYPE
-grpcsharp_completion_queue_create(void) {
-  return grpc_completion_queue_create(NULL);
+grpcsharp_completion_queue_create_async(void) {
+  return grpc_completion_queue_create_for_next(NULL);
+}
+
+GPR_EXPORT grpc_completion_queue *GPR_CALLTYPE
+grpcsharp_completion_queue_create_sync(void) {
+  return grpc_completion_queue_create_for_pluck(NULL);
 }
 
 GPR_EXPORT void GPR_CALLTYPE
diff --git a/src/node/ext/call.cc b/src/node/ext/call.cc
index 244546d..bd60775 100644
--- a/src/node/ext/call.cc
+++ b/src/node/ext/call.cc
@@ -99,7 +99,6 @@
 
 bool CreateMetadataArray(Local<Object> metadata, grpc_metadata_array *array) {
   HandleScope scope;
-  grpc_metadata_array_init(array);
   Local<Array> keys = Nan::GetOwnPropertyNames(metadata).ToLocalChecked();
   for (unsigned int i = 0; i < keys->Length(); i++) {
     Local<String> current_key = Nan::To<String>(
@@ -111,18 +110,20 @@
     array->capacity += Local<Array>::Cast(value_array)->Length();
   }
   array->metadata = reinterpret_cast<grpc_metadata*>(
-      gpr_malloc(array->capacity * sizeof(grpc_metadata)));
+      gpr_zalloc(array->capacity * sizeof(grpc_metadata)));
   for (unsigned int i = 0; i < keys->Length(); i++) {
     Local<String> current_key(Nan::To<String>(keys->Get(i)).ToLocalChecked());
     Local<Array> values = Local<Array>::Cast(
         Nan::Get(metadata, current_key).ToLocalChecked());
-    grpc_slice key_slice = grpc_slice_intern(CreateSliceFromString(current_key));
+    grpc_slice key_slice = CreateSliceFromString(current_key);
+    grpc_slice key_intern_slice = grpc_slice_intern(key_slice);
+    grpc_slice_unref(key_slice);
     for (unsigned int j = 0; j < values->Length(); j++) {
       Local<Value> value = Nan::Get(values, j).ToLocalChecked();
       grpc_metadata *current = &array->metadata[array->count];
-      current->key = key_slice;
+      current->key = key_intern_slice;
       // Only allow binary headers for "-bin" keys
-      if (grpc_is_binary_header(key_slice)) {
+      if (grpc_is_binary_header(key_intern_slice)) {
         if (::node::Buffer::HasInstance(value)) {
           current->value = CreateSliceFromBuffer(value);
         } else {
@@ -142,6 +143,14 @@
   return true;
 }
 
+void DestroyMetadataArray(grpc_metadata_array *array) {
+  for (size_t i = 0; i < array->count; i++) {
+    // Don't unref keys because they are interned
+    grpc_slice_unref(array->metadata[i].value);
+  }
+  grpc_metadata_array_destroy(array);
+}
+
 Local<Value> ParseMetadata(const grpc_metadata_array *metadata_array) {
   EscapableHandleScope scope;
   grpc_metadata *metadata_elements = metadata_array->metadata;
@@ -179,6 +188,12 @@
 
 class SendMetadataOp : public Op {
  public:
+  SendMetadataOp() {
+    grpc_metadata_array_init(&send_metadata);
+  }
+  ~SendMetadataOp() {
+    DestroyMetadataArray(&send_metadata);
+  }
   Local<Value> GetNodeValue() const {
     EscapableHandleScope scope;
     return scope.Escape(Nan::True());
@@ -187,26 +202,29 @@
     if (!value->IsObject()) {
       return false;
     }
-    grpc_metadata_array array;
     MaybeLocal<Object> maybe_metadata = Nan::To<Object>(value);
     if (maybe_metadata.IsEmpty()) {
       return false;
     }
     if (!CreateMetadataArray(maybe_metadata.ToLocalChecked(),
-                             &array)) {
+                             &send_metadata)) {
       return false;
     }
-    out->data.send_initial_metadata.count = array.count;
-    out->data.send_initial_metadata.metadata = array.metadata;
+    out->data.send_initial_metadata.count = send_metadata.count;
+    out->data.send_initial_metadata.metadata = send_metadata.metadata;
     return true;
   }
   bool IsFinalOp() {
     return false;
   }
+  void OnComplete(bool success) {
+  }
  protected:
   std::string GetTypeString() const {
     return "send_metadata";
   }
+ private:
+  grpc_metadata_array send_metadata;
 };
 
 class SendMessageOp : public Op {
@@ -244,6 +262,8 @@
   bool IsFinalOp() {
     return false;
   }
+  void OnComplete(bool success) {
+  }
  protected:
   std::string GetTypeString() const {
     return "send_message";
@@ -264,6 +284,8 @@
   bool IsFinalOp() {
     return false;
   }
+  void OnComplete(bool success) {
+  }
  protected:
   std::string GetTypeString() const {
     return "client_close";
@@ -272,8 +294,12 @@
 
 class SendServerStatusOp : public Op {
  public:
+  SendServerStatusOp() {
+    grpc_metadata_array_init(&status_metadata);
+  }
   ~SendServerStatusOp() {
     grpc_slice_unref(details);
+    DestroyMetadataArray(&status_metadata);
   }
   Local<Value> GetNodeValue() const {
     EscapableHandleScope scope;
@@ -313,12 +339,13 @@
     }
     Local<String> details = Nan::To<String>(
         maybe_details.ToLocalChecked()).ToLocalChecked();
-    grpc_metadata_array array;
-    if (!CreateMetadataArray(metadata, &array)) {
+    if (!CreateMetadataArray(metadata, &status_metadata)) {
       return false;
     }
-    out->data.send_status_from_server.trailing_metadata_count = array.count;
-    out->data.send_status_from_server.trailing_metadata = array.metadata;
+    out->data.send_status_from_server.trailing_metadata_count =
+        status_metadata.count;
+    out->data.send_status_from_server.trailing_metadata =
+        status_metadata.metadata;
     out->data.send_status_from_server.status =
         static_cast<grpc_status_code>(code);
     this->details = CreateSliceFromString(details);
@@ -328,6 +355,8 @@
   bool IsFinalOp() {
     return true;
   }
+  void OnComplete(bool success) {
+  }
  protected:
   std::string GetTypeString() const {
     return "send_status";
@@ -335,6 +364,7 @@
 
  private:
   grpc_slice details;
+  grpc_metadata_array status_metadata;
 };
 
 class GetMetadataOp : public Op {
@@ -359,6 +389,8 @@
   bool IsFinalOp() {
     return false;
   }
+  void OnComplete(bool success) {
+  }
 
  protected:
   std::string GetTypeString() const {
@@ -391,6 +423,8 @@
   bool IsFinalOp() {
     return false;
   }
+  void OnComplete(bool success) {
+  }
 
  protected:
   std::string GetTypeString() const {
@@ -432,6 +466,8 @@
   bool IsFinalOp() {
     return true;
   }
+  void OnComplete(bool success) {
+  }
  protected:
   std::string GetTypeString() const {
     return "status";
@@ -456,6 +492,8 @@
   bool IsFinalOp() {
     return false;
   }
+  void OnComplete(bool success) {
+  }
 
  protected:
   std::string GetTypeString() const {
@@ -466,8 +504,10 @@
   int cancelled;
 };
 
-tag::tag(Callback *callback, OpVec *ops, Call *call) :
+tag::tag(Callback *callback, OpVec *ops, Call *call, Local<Value> call_value) :
     callback(callback), ops(ops), call(call){
+  HandleScope scope;
+  call_persist.Reset(call_value);
 }
 
 tag::~tag() {
@@ -475,36 +515,36 @@
   delete ops;
 }
 
-Local<Value> GetTagNodeValue(void *tag) {
-  EscapableHandleScope scope;
+void CompleteTag(void *tag, const char *error_message) {
+  HandleScope scope;
   struct tag *tag_struct = reinterpret_cast<struct tag *>(tag);
-  Local<Object> tag_obj = Nan::New<Object>();
-  for (vector<unique_ptr<Op> >::iterator it = tag_struct->ops->begin();
-       it != tag_struct->ops->end(); ++it) {
-    Op *op_ptr = it->get();
-    Nan::Set(tag_obj, op_ptr->GetOpType(), op_ptr->GetNodeValue());
+  Callback *callback = tag_struct->callback;
+  if (error_message == NULL) {
+    Local<Object> tag_obj = Nan::New<Object>();
+    for (vector<unique_ptr<Op> >::iterator it = tag_struct->ops->begin();
+         it != tag_struct->ops->end(); ++it) {
+      Op *op_ptr = it->get();
+      Nan::Set(tag_obj, op_ptr->GetOpType(), op_ptr->GetNodeValue());
+    }
+    Local<Value> argv[] = {Nan::Null(), tag_obj};
+    callback->Call(2, argv);
+  } else {
+    Local<Value> argv[] = {Nan::Error(error_message)};
+    callback->Call(1, argv);
   }
-  return scope.Escape(tag_obj);
-}
-
-Callback *GetTagCallback(void *tag) {
-  struct tag *tag_struct = reinterpret_cast<struct tag *>(tag);
-  return tag_struct->callback;
-}
-
-void CompleteTag(void *tag) {
-  struct tag *tag_struct = reinterpret_cast<struct tag *>(tag);
+  bool success = (error_message == NULL);
   bool is_final_op = false;
-  if (tag_struct->call == NULL) {
-    return;
-  }
   for (vector<unique_ptr<Op> >::iterator it = tag_struct->ops->begin();
        it != tag_struct->ops->end(); ++it) {
     Op *op_ptr = it->get();
+    op_ptr->OnComplete(success);
     if (op_ptr->IsFinalOp()) {
       is_final_op = true;
     }
   }
+  if (tag_struct->call == NULL) {
+    return;
+  }
   tag_struct->call->CompleteBatch(is_final_op);
 }
 
@@ -513,15 +553,20 @@
   delete tag_struct;
 }
 
+void Call::DestroyCall() {
+  if (this->wrapped_call != NULL) {
+    grpc_call_destroy(this->wrapped_call);
+    this->wrapped_call = NULL;
+  }
+}
+
 Call::Call(grpc_call *call) : wrapped_call(call),
                               pending_batches(0),
                               has_final_op_completed(false) {
 }
 
 Call::~Call() {
-  if (wrapped_call != NULL) {
-    grpc_call_destroy(wrapped_call);
-  }
+  DestroyCall();
 }
 
 void Call::Init(Local<Object> exports) {
@@ -568,12 +613,19 @@
   }
   this->pending_batches--;
   if (this->has_final_op_completed && this->pending_batches == 0) {
-    grpc_call_destroy(this->wrapped_call);
-    this->wrapped_call = NULL;
+    this->DestroyCall();
   }
 }
 
 NAN_METHOD(Call::New) {
+  /* Arguments:
+   * 0: Channel to make the call on
+   * 1: Method
+   * 2: Deadline
+   * 3: host
+   * 4: parent Call
+   * 5: propagation flags
+   */
   if (info.IsConstructCall()) {
     Call *call;
     if (info[0]->IsExternal()) {
@@ -618,25 +670,26 @@
       double deadline = Nan::To<double>(info[2]).FromJust();
       grpc_channel *wrapped_channel = channel->GetWrappedChannel();
       grpc_call *wrapped_call;
+      grpc_slice method = CreateSliceFromString(
+          Nan::To<String>(info[1]).ToLocalChecked());
       if (info[3]->IsString()) {
         grpc_slice *host = new grpc_slice;
         *host = CreateSliceFromString(
             Nan::To<String>(info[3]).ToLocalChecked());
         wrapped_call = grpc_channel_create_call(
             wrapped_channel, parent_call, propagate_flags,
-            GetCompletionQueue(), CreateSliceFromString(
-                Nan::To<String>(info[1]).ToLocalChecked()),
+            GetCompletionQueue(), method,
             host, MillisecondsToTimespec(deadline), NULL);
         delete host;
       } else if (info[3]->IsUndefined() || info[3]->IsNull()) {
         wrapped_call = grpc_channel_create_call(
             wrapped_channel, parent_call, propagate_flags,
-            GetCompletionQueue(), CreateSliceFromString(
-                Nan::To<String>(info[1]).ToLocalChecked()),
+            GetCompletionQueue(), method,
             NULL, MillisecondsToTimespec(deadline), NULL);
       } else {
         return Nan::ThrowTypeError("Call's fourth argument must be a string");
       }
+      grpc_slice_unref(method);
       call = new Call(wrapped_call);
       Nan::Set(info.This(), Nan::New("channel_").ToLocalChecked(),
                channel_object);
@@ -721,7 +774,7 @@
   Callback *callback = new Callback(callback_func);
   grpc_call_error error = grpc_call_start_batch(
       call->wrapped_call, &ops[0], nops, new struct tag(
-          callback, op_vector.release(), call), NULL);
+          callback, op_vector.release(), call, info.This()), NULL);
   if (error != GRPC_CALL_OK) {
     return Nan::ThrowError(nanErrorWithCode("startBatch failed", error));
   }
diff --git a/src/node/ext/call.h b/src/node/ext/call.h
index cffff00..340e326 100644
--- a/src/node/ext/call.h
+++ b/src/node/ext/call.h
@@ -58,6 +58,8 @@
 bool CreateMetadataArray(v8::Local<v8::Object> metadata,
                          grpc_metadata_array *array);
 
+void DestroyMetadataArray(grpc_metadata_array *array);
+
 /* Wrapper class for grpc_call structs. */
 class Call : public Nan::ObjectWrap {
  public:
@@ -76,6 +78,8 @@
   Call(const Call &);
   Call &operator=(const Call &);
 
+  void DestroyCall();
+
   static NAN_METHOD(New);
   static NAN_METHOD(StartBatch);
   static NAN_METHOD(Cancel);
@@ -102,6 +106,7 @@
   virtual ~Op();
   v8::Local<v8::Value> GetOpType() const;
   virtual bool IsFinalOp() = 0;
+  virtual void OnComplete(bool success) = 0;
 
  protected:
   virtual std::string GetTypeString() const = 0;
@@ -109,20 +114,19 @@
 
 typedef std::vector<unique_ptr<Op>> OpVec;
 struct tag {
-  tag(Nan::Callback *callback, OpVec *ops, Call *call);
+  tag(Nan::Callback *callback, OpVec *ops, Call *call,
+      v8::Local<v8::Value> call_value);
   ~tag();
   Nan::Callback *callback;
   OpVec *ops;
   Call *call;
+  Nan::Persistent<v8::Value, Nan::CopyablePersistentTraits<v8::Value>>
+      call_persist;
 };
 
-v8::Local<v8::Value> GetTagNodeValue(void *tag);
-
-Nan::Callback *GetTagCallback(void *tag);
-
 void DestroyTag(void *tag);
 
-void CompleteTag(void *tag);
+void CompleteTag(void *tag, const char *error_message);
 
 }  // namespace node
 }  // namespace grpc
diff --git a/src/node/ext/call_credentials.cc b/src/node/ext/call_credentials.cc
index afcc363..5bd4bdc 100644
--- a/src/node/ext/call_credentials.cc
+++ b/src/node/ext/call_credentials.cc
@@ -211,6 +211,7 @@
   Utf8String details_utf8_str(info[1]);
   char *details = *details_utf8_str;
   grpc_metadata_array array;
+  grpc_metadata_array_init(&array);
   Local<Object> callback_data = Nan::To<Object>(info[3]).ToLocalChecked();
   if (!CreateMetadataArray(Nan::To<Object>(info[2]).ToLocalChecked(),
                            &array)){
@@ -226,6 +227,7 @@
                Nan::New("user_data").ToLocalChecked()
                ).ToLocalChecked().As<External>()->Value();
   cb(user_data, array.metadata, array.count, code, details);
+  DestroyMetadataArray(&array);
 }
 
 NAUV_WORK_CB(SendPluginCallback) {
diff --git a/src/node/ext/channel.cc b/src/node/ext/channel.cc
index c795ff7..1263cc0 100644
--- a/src/node/ext/channel.cc
+++ b/src/node/ext/channel.cc
@@ -280,7 +280,7 @@
       channel->wrapped_channel, last_state, MillisecondsToTimespec(deadline),
       GetCompletionQueue(),
       new struct tag(callback,
-                     ops.release(), NULL));
+                     ops.release(), NULL, Nan::Null()));
   CompletionQueueNext();
 }
 
diff --git a/src/node/ext/completion_queue_threadpool.cc b/src/node/ext/completion_queue_threadpool.cc
index 1917074..72df5d1 100644
--- a/src/node/ext/completion_queue_threadpool.cc
+++ b/src/node/ext/completion_queue_threadpool.cc
@@ -34,14 +34,14 @@
 /* I don't like using #ifndef, but I don't see a better way to do this */
 #ifndef GRPC_UV
 
-#include <node.h>
 #include <nan.h>
+#include <node.h>
 
+#include "call.h"
+#include "completion_queue.h"
 #include "grpc/grpc.h"
 #include "grpc/support/log.h"
 #include "grpc/support/time.h"
-#include "completion_queue.h"
-#include "call.h"
 
 namespace grpc {
 namespace node {
@@ -111,8 +111,8 @@
 CompletionQueueAsyncWorker::~CompletionQueueAsyncWorker() {}
 
 void CompletionQueueAsyncWorker::Execute() {
-  result =
-      grpc_completion_queue_next(queue, gpr_inf_future(GPR_CLOCK_REALTIME), NULL);
+  result = grpc_completion_queue_next(queue, gpr_inf_future(GPR_CLOCK_REALTIME),
+                                      NULL);
   if (!result.success) {
     SetErrorMessage("The async function encountered an error");
   }
@@ -141,16 +141,14 @@
   Nan::HandleScope scope;
   current_threads = 0;
   waiting_next_calls = 0;
-  queue = grpc_completion_queue_create(NULL);
+  queue = grpc_completion_queue_create_for_next(NULL);
 }
 
 void CompletionQueueAsyncWorker::HandleOKCallback() {
   Nan::HandleScope scope;
   current_threads -= 1;
   TryAddWorker();
-  Nan::Callback *callback = GetTagCallback(result.tag);
-  Local<Value> argv[] = {Nan::Null(), GetTagNodeValue(result.tag)};
-  callback->Call(2, argv);
+  CompleteTag(result.tag, NULL);
 
   DestroyTag(result.tag);
 }
@@ -159,10 +157,7 @@
   Nan::HandleScope scope;
   current_threads -= 1;
   TryAddWorker();
-  Nan::Callback *callback = GetTagCallback(result.tag);
-  Local<Value> argv[] = {Nan::Error(ErrorMessage())};
-
-  callback->Call(1, argv);
+  CompleteTag(result.tag, ErrorMessage());
 
   DestroyTag(result.tag);
 }
@@ -173,9 +168,7 @@
   return CompletionQueueAsyncWorker::GetQueue();
 }
 
-void CompletionQueueNext() {
-  CompletionQueueAsyncWorker::Next();
-}
+void CompletionQueueNext() { CompletionQueueAsyncWorker::Next(); }
 
 void CompletionQueueInit(Local<Object> exports) {
   CompletionQueueAsyncWorker::Init(exports);
@@ -184,4 +177,4 @@
 }  // namespace node
 }  // namespace grpc
 
-#endif  /* GRPC_UV */
+#endif /* GRPC_UV */
diff --git a/src/node/ext/completion_queue_uv.cc b/src/node/ext/completion_queue_uv.cc
index 615973a..9b60911 100644
--- a/src/node/ext/completion_queue_uv.cc
+++ b/src/node/ext/completion_queue_uv.cc
@@ -33,10 +33,10 @@
 
 #ifdef GRPC_UV
 
-#include <uv.h>
-#include <node.h>
-#include <v8.h>
 #include <grpc/grpc.h>
+#include <node.h>
+#include <uv.h>
+#include <v8.h>
 
 #include "call.h"
 #include "completion_queue.h"
@@ -57,21 +57,17 @@
   grpc_event event;
   (void)handle;
   do {
-    event = grpc_completion_queue_next(
-        queue, gpr_inf_past(GPR_CLOCK_MONOTONIC), NULL);
+    event = grpc_completion_queue_next(queue, gpr_inf_past(GPR_CLOCK_MONOTONIC),
+                                       NULL);
 
     if (event.type == GRPC_OP_COMPLETE) {
-      Nan::Callback *callback = grpc::node::GetTagCallback(event.tag);
+      const char *error_message;
       if (event.success) {
-        Local<Value> argv[] = {Nan::Null(),
-                             grpc::node::GetTagNodeValue(event.tag)};
-        callback->Call(2, argv);
+        error_message = NULL;
       } else {
-        Local<Value> argv[] = {Nan::Error(
-            "The async function encountered an error")};
-        callback->Call(1, argv);
+        error_message = "The async function encountered an error";
       }
-      grpc::node::CompleteTag(event.tag);
+      CompleteTag(event.tag, error_message);
       grpc::node::DestroyTag(event.tag);
       pending_batches--;
       if (pending_batches == 0) {
@@ -81,9 +77,7 @@
   } while (event.type != GRPC_QUEUE_TIMEOUT);
 }
 
-grpc_completion_queue *GetCompletionQueue() {
-  return queue;
-}
+grpc_completion_queue *GetCompletionQueue() { return queue; }
 
 void CompletionQueueNext() {
   if (pending_batches == 0) {
@@ -94,7 +88,7 @@
 }
 
 void CompletionQueueInit(Local<Object> exports) {
-  queue = grpc_completion_queue_create(NULL);
+  queue = grpc_completion_queue_create_for_next(NULL);
   uv_prepare_init(uv_default_loop(), &prepare);
   pending_batches = 0;
 }
diff --git a/src/node/ext/node_grpc.cc b/src/node/ext/node_grpc.cc
index 95e273f..122e5e6 100644
--- a/src/node/ext/node_grpc.cc
+++ b/src/node/ext/node_grpc.cc
@@ -286,8 +286,10 @@
         "headerKeyIsLegal's argument must be a string");
   }
   Local<String> key = Nan::To<String>(info[0]).ToLocalChecked();
+  grpc_slice slice = CreateSliceFromString(key);
   info.GetReturnValue().Set(static_cast<bool>(
-      grpc_header_key_is_legal(CreateSliceFromString(key))));
+      grpc_header_key_is_legal(slice)));
+  grpc_slice_unref(slice);
 }
 
 NAN_METHOD(MetadataNonbinValueIsLegal) {
@@ -296,8 +298,10 @@
         "metadataNonbinValueIsLegal's argument must be a string");
   }
   Local<String> value = Nan::To<String>(info[0]).ToLocalChecked();
+  grpc_slice slice = CreateSliceFromString(value);
   info.GetReturnValue().Set(static_cast<bool>(
-      grpc_header_nonbin_value_is_legal(CreateSliceFromString(value))));
+      grpc_header_nonbin_value_is_legal(slice)));
+  grpc_slice_unref(slice);
 }
 
 NAN_METHOD(MetadataKeyIsBinary) {
@@ -306,8 +310,10 @@
         "metadataKeyIsLegal's argument must be a string");
   }
   Local<String> key = Nan::To<String>(info[0]).ToLocalChecked();
+  grpc_slice slice = CreateSliceFromString(key);
   info.GetReturnValue().Set(static_cast<bool>(
-      grpc_is_binary_header(CreateSliceFromString(key))));
+      grpc_is_binary_header(slice)));
+  grpc_slice_unref(slice);
 }
 
 static grpc_ssl_roots_override_result get_ssl_roots_override(
diff --git a/src/node/ext/server.cc b/src/node/ext/server.cc
index ccb55aa..5384305 100644
--- a/src/node/ext/server.cc
+++ b/src/node/ext/server.cc
@@ -117,6 +117,8 @@
   bool IsFinalOp() {
     return false;
   }
+  void OnComplete(bool success) {
+  }
 
   grpc_call *call;
   grpc_call_details details;
@@ -126,6 +128,34 @@
   std::string GetTypeString() const { return "new_call"; }
 };
 
+class TryShutdownOp: public Op {
+ public:
+  TryShutdownOp(Server *server, Local<Value> server_value) : server(server) {
+    server_persist.Reset(server_value);
+  }
+  Local<Value> GetNodeValue() const {
+    EscapableHandleScope scope;
+    return scope.Escape(Nan::New(server_persist));
+  }
+  bool ParseOp(Local<Value> value, grpc_op *out) {
+    return true;
+  }
+  bool IsFinalOp() {
+    return false;
+  }
+  void OnComplete(bool success) {
+    if (success) {
+      server->DestroyWrappedServer();
+    }
+  }
+ protected:
+  std::string GetTypeString() const { return "try_shutdown"; }
+ private:
+  Server *server;
+  Nan::Persistent<v8::Value, Nan::CopyablePersistentTraits<v8::Value>>
+      server_persist;
+};
+
 void Server::Init(Local<Object> exports) {
   HandleScope scope;
   Local<FunctionTemplate> tpl = Nan::New<FunctionTemplate>(New);
@@ -147,6 +177,13 @@
   return Nan::New(fun_tpl)->HasInstance(val);
 }
 
+void Server::DestroyWrappedServer() {
+  if (this->wrapped_server != NULL) {
+    grpc_server_destroy(this->wrapped_server);
+    this->wrapped_server = NULL;
+  }
+}
+
 NAN_METHOD(Server::New) {
   /* If this is not a constructor call, make a constructor call and return
      the result */
@@ -193,7 +230,7 @@
       GetCompletionQueue(),
       GetCompletionQueue(),
       new struct tag(new Callback(info[0].As<Function>()), ops.release(),
-                     NULL));
+                     NULL, Nan::Null()));
   if (error != GRPC_CALL_OK) {
     return Nan::ThrowError(nanErrorWithCode("requestCall failed", error));
   }
@@ -242,11 +279,19 @@
     return Nan::ThrowTypeError("tryShutdown can only be called on a Server");
   }
   Server *server = ObjectWrap::Unwrap<Server>(info.This());
+  if (server->wrapped_server == NULL) {
+    // Server is already shut down. Call callback immediately.
+    Nan::Callback callback(info[0].As<Function>());
+    callback.Call(0, {});
+    return;
+  }
+  TryShutdownOp *op = new TryShutdownOp(server, info.This());
   unique_ptr<OpVec> ops(new OpVec());
+  ops->push_back(unique_ptr<Op>(op));
   grpc_server_shutdown_and_notify(
       server->wrapped_server, GetCompletionQueue(),
       new struct tag(new Nan::Callback(info[0].As<Function>()), ops.release(),
-                     NULL));
+                     NULL, Nan::Null()));
   CompletionQueueNext();
 }
 
diff --git a/src/node/ext/server.h b/src/node/ext/server.h
index ab5fc21..c0f2e86 100644
--- a/src/node/ext/server.h
+++ b/src/node/ext/server.h
@@ -53,6 +53,8 @@
      JavaScript constructor */
   static bool HasInstance(v8::Local<v8::Value> val);
 
+  void DestroyWrappedServer();
+
  private:
   explicit Server(grpc_server *server);
   ~Server();
diff --git a/src/node/ext/server_generic.cc b/src/node/ext/server_generic.cc
index 0cf20f7..24573bd 100644
--- a/src/node/ext/server_generic.cc
+++ b/src/node/ext/server_generic.cc
@@ -35,8 +35,8 @@
 
 #include "server.h"
 
-#include <node.h>
 #include <nan.h>
+#include <node.h>
 #include "grpc/grpc.h"
 #include "grpc/support/time.h"
 
@@ -44,7 +44,7 @@
 namespace node {
 
 Server::Server(grpc_server *server) : wrapped_server(server) {
-  shutdown_queue = grpc_completion_queue_create(NULL);
+  shutdown_queue = grpc_completion_queue_create_for_pluck(NULL);
   grpc_server_register_non_listening_completion_queue(server, shutdown_queue,
                                                       NULL);
 }
diff --git a/src/node/ext/server_uv.cc b/src/node/ext/server_uv.cc
index c5e5ca9..7899383 100644
--- a/src/node/ext/server_uv.cc
+++ b/src/node/ext/server_uv.cc
@@ -67,7 +67,7 @@
   }
 
   Local<Value> GetNodeValue() const {
-    return Nan::New<External>(reinterpret_cast<void *>(server));
+    return Nan::Null();
   }
 
   bool ParseOp(Local<Value> value, grpc_op *out) {
@@ -76,6 +76,11 @@
   bool IsFinalOp() {
     return false;
   }
+  void OnComplete(bool success) {
+    /* Because cancel_all_calls was called, we assume that shutdown_and_notify
+       completes successfully */
+    grpc_server_destroy(server);
+  }
 
   grpc_server *server;
 
@@ -94,16 +99,10 @@
   if (!info[0]->IsNull()) {
     return Nan::ThrowError("forceShutdown failed somehow");
   }
-  MaybeLocal<Object> maybe_result = Nan::To<Object>(info[1]);
-  Local<Object> result = maybe_result.ToLocalChecked();
-  Local<Value> server_val = Nan::Get(
-      result, Nan::New("shutdown").ToLocalChecked()).ToLocalChecked();
-  Local<External> server_extern = server_val.As<External>();
-  grpc_server *server = reinterpret_cast<grpc_server *>(server_extern->Value());
-  grpc_server_destroy(server);
 }
 
 void Server::ShutdownServer() {
+  Nan::HandleScope scope;
   if (this->wrapped_server != NULL) {
     if (shutdown_callback == NULL) {
       Local<FunctionTemplate>callback_tpl =
@@ -118,7 +117,8 @@
 
     grpc_server_shutdown_and_notify(
         this->wrapped_server, GetCompletionQueue(),
-        new struct tag(new Callback(**shutdown_callback), ops.release(), NULL));
+        new struct tag(new Callback(**shutdown_callback), ops.release(), NULL,
+                       Nan::Null()));
     grpc_server_cancel_all_calls(this->wrapped_server);
     CompletionQueueNext();
     this->wrapped_server = NULL;
diff --git a/src/node/health_check/package.json b/src/node/health_check/package.json
index e218f5a..37c9b7a 100644
--- a/src/node/health_check/package.json
+++ b/src/node/health_check/package.json
@@ -1,6 +1,6 @@
 {
   "name": "grpc-health-check",
-  "version": "1.3.0-dev",
+  "version": "1.4.0-dev",
   "author": "Google Inc.",
   "description": "Health check service for use with gRPC",
   "repository": {
@@ -15,7 +15,7 @@
     }
   ],
   "dependencies": {
-    "grpc": "^1.3.0-dev",
+    "grpc": "^1.4.0-dev",
     "lodash": "^3.9.3",
     "google-protobuf": "^3.0.0"
   },
diff --git a/src/node/test/test_messages.proto b/src/node/test/test_messages.proto
index ae70f6e..43c213d 100644
--- a/src/node/test/test_messages.proto
+++ b/src/node/test/test_messages.proto
@@ -57,4 +57,4 @@
 
 message EnumValues {
   TestEnum enum_value = 1;
-}
\ No newline at end of file
+}
diff --git a/src/node/tools/package.json b/src/node/tools/package.json
index 3096c6e..a81aa87 100644
--- a/src/node/tools/package.json
+++ b/src/node/tools/package.json
@@ -1,6 +1,6 @@
 {
   "name": "grpc-tools",
-  "version": "1.3.0-dev",
+  "version": "1.4.0-dev",
   "author": "Google Inc.",
   "description": "Tools for developing with gRPC on Node.js",
   "homepage": "http://www.grpc.io/",
diff --git "a/src/objective-c/\041ProtoCompiler-gRPCPlugin.podspec" "b/src/objective-c/\041ProtoCompiler-gRPCPlugin.podspec"
index 2f41ad1..2f29058 100644
--- "a/src/objective-c/\041ProtoCompiler-gRPCPlugin.podspec"
+++ "b/src/objective-c/\041ProtoCompiler-gRPCPlugin.podspec"
@@ -42,7 +42,7 @@
   # exclamation mark ensures that other "regular" pods will be able to find it as it'll be installed
   # before them.
   s.name     = '!ProtoCompiler-gRPCPlugin'
-  v = '1.3.0-dev'
+  v = '1.4.0-dev'
   s.version  = v
   s.summary  = 'The gRPC ProtoC plugin generates Objective-C files from .proto services.'
   s.description = <<-DESC
diff --git a/src/objective-c/BoringSSL.podspec b/src/objective-c/BoringSSL.podspec
index 908bb0b..7880aad 100644
--- a/src/objective-c/BoringSSL.podspec
+++ b/src/objective-c/BoringSSL.podspec
@@ -31,7 +31,7 @@
 
 Pod::Spec.new do |s|
   s.name     = 'BoringSSL'
-  version = '8.0'
+  version = '8.1'
   s.version  = version
   s.summary  = 'BoringSSL is a fork of OpenSSL that is designed to meet Google’s needs.'
   # Adapted from the homepage:
@@ -69,8 +69,9 @@
 
   s.source = {
     :git => 'https://boringssl.googlesource.com/boringssl',
-    :tag => "version_for_cocoapods_#{version}",
-    # :commit => '4fec04b48406111cb88fdd8d196253adc54f7a31',
+    # Restore this version name hack in the next version!!
+    # :tag => "version_for_cocoapods_#{version}",
+    :tag => "version_for_cocoapods_8.0",
   }
 
   name = 'openssl'
@@ -95,7 +96,7 @@
   # The module map and umbrella header created automatically by Cocoapods don't work for C libraries
   # like this one. The following file, and a correct umbrella header, are created on the fly by the
   # `prepare_command` of this pod.
-  s.module_map = 'include/openssl/module.modulemap'
+  s.module_map = 'include/openssl/BoringSSL.modulemap'
 
   # We don't need to inhibit all warnings; only -Wno-shorten-64-to-32. But Cocoapods' linter doesn't
   # want that for some reason.
@@ -112,6 +113,7 @@
   s.subspec 'Interface' do |ss|
     ss.header_mappings_dir = 'include/openssl'
     ss.source_files = 'include/openssl/*.h'
+    ss.exclude_files = 'include/openssl/arm_arch.h'
   end
   s.subspec 'Implementation' do |ss|
     ss.header_mappings_dir = '.'
@@ -148,11 +150,6 @@
       #include "ssl.h"
       #include "crypto.h"
       #include "aes.h"
-      /* The following macros are defined by base.h. The latter is the first file included by the
-         other headers. */
-      #if defined(OPENSSL_ARM) || defined(OPENSSL_AARCH64)
-      #  include "arm_arch.h"
-      #endif
       #include "asn1.h"
       #include "asn1_mac.h"
       #include "asn1t.h"
@@ -186,7 +183,7 @@
       #include "x509.h"
       #include "x509v3.h"
     EOF
-    cat > include/openssl/module.modulemap <<EOF
+    cat > include/openssl/BoringSSL.modulemap <<EOF
       framework module openssl {
         umbrella header "umbrella.h"
         export *
diff --git a/src/objective-c/GRPCClient/private/GRPCCompletionQueue.m b/src/objective-c/GRPCClient/private/GRPCCompletionQueue.m
index 539b5ab..5ff77ea 100644
--- a/src/objective-c/GRPCClient/private/GRPCCompletionQueue.m
+++ b/src/objective-c/GRPCClient/private/GRPCCompletionQueue.m
@@ -48,7 +48,7 @@
 
 - (instancetype)init {
   if ((self = [super init])) {
-    _unmanagedQueue = grpc_completion_queue_create(NULL);
+    _unmanagedQueue = grpc_completion_queue_create_for_next(NULL);
 
     // This is for the following block to capture the pointer by value (instead
     // of retaining self and doing self->_unmanagedQueue). This is essential
diff --git a/src/objective-c/GRPCClient/private/version.h b/src/objective-c/GRPCClient/private/version.h
index 09155ee..c846f42 100644
--- a/src/objective-c/GRPCClient/private/version.h
+++ b/src/objective-c/GRPCClient/private/version.h
@@ -38,4 +38,4 @@
 // `tools/buildgen/generate_projects.sh`.
 
 
-#define GRPC_OBJC_VERSION_STRING @"1.3.0-dev"
+#define GRPC_OBJC_VERSION_STRING @"1.4.0-dev"
diff --git a/src/objective-c/tests/CoreCronetEnd2EndTests/CoreCronetEnd2EndTests.m b/src/objective-c/tests/CoreCronetEnd2EndTests/CoreCronetEnd2EndTests.m
index 3b44264..3dd2647 100644
--- a/src/objective-c/tests/CoreCronetEnd2EndTests/CoreCronetEnd2EndTests.m
+++ b/src/objective-c/tests/CoreCronetEnd2EndTests/CoreCronetEnd2EndTests.m
@@ -79,7 +79,8 @@
   gpr_join_host_port(&ffd->localaddr, "127.0.0.1", port);
 
   f.fixture_data = ffd;
-  f.cq = grpc_completion_queue_create(NULL);
+  f.cq = grpc_completion_queue_create_for_next(NULL);
+  f.shutdown_cq = grpc_completion_queue_create_for_pluck(NULL);
 
   return f;
 }
diff --git a/src/objective-c/tests/CronetUnitTests/CronetUnitTests.m b/src/objective-c/tests/CronetUnitTests/CronetUnitTests.m
index a76e454..6d94116 100644
--- a/src/objective-c/tests/CronetUnitTests/CronetUnitTests.m
+++ b/src/objective-c/tests/CronetUnitTests/CronetUnitTests.m
@@ -160,7 +160,7 @@
   int port = grpc_pick_unused_port_or_die();
   char *addr;
   gpr_join_host_port(&addr, "127.0.0.1", port);
-  grpc_completion_queue *cq = grpc_completion_queue_create(NULL);
+  grpc_completion_queue *cq = grpc_completion_queue_create_for_next(NULL);
   stream_engine *cronetEngine = [Cronet getGlobalEngine];
   grpc_channel *client =
       grpc_cronet_secure_channel_create(cronetEngine, addr, NULL, NULL);
@@ -295,7 +295,7 @@
   int port = grpc_pick_unused_port_or_die();
   char *addr;
   gpr_join_host_port(&addr, "127.0.0.1", port);
-  grpc_completion_queue *cq = grpc_completion_queue_create(NULL);
+  grpc_completion_queue *cq = grpc_completion_queue_create_for_next(NULL);
   stream_engine *cronetEngine = [Cronet getGlobalEngine];
   grpc_channel *client =
       grpc_cronet_secure_channel_create(cronetEngine, addr, args, NULL);
diff --git a/src/php/composer.json b/src/php/composer.json
index 2b14007..24c17c3 100644
--- a/src/php/composer.json
+++ b/src/php/composer.json
@@ -2,7 +2,7 @@
   "name": "grpc/grpc-dev",
   "description": "gRPC library for PHP - for Developement use only",
   "license": "BSD-3-Clause",
-  "version": "1.3.0",
+  "version": "1.4.0",
   "require": {
     "php": ">=5.5.0",
     "google/protobuf": "^v3.1.0"
diff --git a/src/php/ext/grpc/completion_queue.c b/src/php/ext/grpc/completion_queue.c
index 741204b..c75a524 100644
--- a/src/php/ext/grpc/completion_queue.c
+++ b/src/php/ext/grpc/completion_queue.c
@@ -38,13 +38,10 @@
 grpc_completion_queue *completion_queue;
 
 void grpc_php_init_completion_queue(TSRMLS_D) {
-  completion_queue = grpc_completion_queue_create(NULL);
+  completion_queue = grpc_completion_queue_create_for_pluck(NULL);
 }
 
 void grpc_php_shutdown_completion_queue(TSRMLS_D) {
   grpc_completion_queue_shutdown(completion_queue);
-  while (grpc_completion_queue_next(completion_queue,
-                                    gpr_inf_future(GPR_CLOCK_REALTIME),
-                                    NULL).type != GRPC_QUEUE_SHUTDOWN);
   grpc_completion_queue_destroy(completion_queue);
 }
diff --git a/src/proto/grpc/lb/v1/load_balancer.proto b/src/proto/grpc/lb/v1/load_balancer.proto
index 44a5150..a2502fb 100644
--- a/src/proto/grpc/lb/v1/load_balancer.proto
+++ b/src/proto/grpc/lb/v1/load_balancer.proto
@@ -45,6 +45,20 @@
   int32 nanos = 2;
 }
 
+message Timestamp {
+
+  // Represents seconds of UTC time since Unix epoch
+  // 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to
+  // 9999-12-31T23:59:59Z inclusive.
+  int64 seconds = 1;
+
+  // Non-negative fractions of a second at nanosecond resolution. Negative
+  // second values with fractions must still have non-negative nanos values
+  // that count forward in time. Must be from 0 to 999,999,999
+  // inclusive.
+  int32 nanos = 2;
+}
+
 service LoadBalancer {
   // Bidirectional rpc to get a list of servers.
   rpc BalanceLoad(stream LoadBalanceRequest)
@@ -63,22 +77,37 @@
 }
 
 message InitialLoadBalanceRequest {
-  // Name of load balanced service (IE, service.grpc.gslb.google.com). Its
+  // Name of load balanced service (IE, balancer.service.com)
   // length should be less than 256 bytes.
   string name = 1;
 }
 
 // Contains client level statistics that are useful to load balancing. Each
-// count should be reset to zero after reporting the stats.
+// count except the timestamp should be reset to zero after reporting the stats.
 message ClientStats {
-  // The total number of requests sent by the client since the last report.
-  int64 total_requests = 1;
+  // The timestamp of generating the report.
+  Timestamp timestamp = 1;
 
-  // The number of client rpc errors since the last report.
-  int64 client_rpc_errors = 2;
+  // The total number of RPCs that started.
+  int64 num_calls_started = 2;
 
-  // The number of dropped requests since the last report.
-  int64 dropped_requests = 3;
+  // The total number of RPCs that finished.
+  int64 num_calls_finished = 3;
+
+  // The total number of RPCs that were dropped by the client because of rate
+  // limiting.
+  int64 num_calls_finished_with_drop_for_rate_limiting = 4;
+
+  // The total number of RPCs that were dropped by the client because of load
+  // balancing.
+  int64 num_calls_finished_with_drop_for_load_balancing = 5;
+
+  // The total number of RPCs that failed to reach a server except dropped RPCs.
+  int64 num_calls_finished_with_client_failed_to_send = 6;
+
+  // The total number of RPCs that finished and are known to have been received
+  // by a server.
+  int64 num_calls_finished_known_received = 7;
 }
 
 message LoadBalanceResponse {
@@ -120,6 +149,10 @@
   Duration expiration_interval = 3;
 }
 
+// Contains server information. When none of the [drop_for_*] fields are true,
+// use the other fields. When drop_for_rate_limiting is true, ignore all other
+// fields. Use drop_for_load_balancing only when it is true and
+// drop_for_rate_limiting is false.
 message Server {
   // A resolved address for the server, serialized in network-byte-order. It may
   // either be an IPv4 or IPv6 address.
@@ -137,6 +170,10 @@
   string load_balance_token = 3;
 
   // Indicates whether this particular request should be dropped by the client
-  // when this server is chosen from the list.
-  bool drop_request = 4;
+  // for rate limiting.
+  bool drop_for_rate_limiting = 4;
+
+  // Indicates whether this particular request should be dropped by the client
+  // for load balancing.
+  bool drop_for_load_balancing = 5;
 }
diff --git a/tools/internal_ci/linux/grpc_master_sanitizers.cfg b/src/proto/grpc/status/BUILD
similarity index 81%
copy from tools/internal_ci/linux/grpc_master_sanitizers.cfg
copy to src/proto/grpc/status/BUILD
index a2a9407..c17f87e 100644
--- a/tools/internal_ci/linux/grpc_master_sanitizers.cfg
+++ b/src/proto/grpc/status/BUILD
@@ -27,13 +27,17 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-# Config file for the internal CI (in protobuf text format)
+licenses(["notice"])  # 3-clause BSD
 
-# Location of the continuous shell script in repository.
-build_file: "grpc/tools/internal_ci/linux/grpc_master_sanitizers.sh"
-timeout_mins: 1440
-action {
-  define_artifacts {
-    regex: "**/*sponge_log.xml"
-  }
-}
+package(default_visibility = ["//visibility:public"])
+
+load("//bazel:grpc_build_system.bzl", "grpc_proto_library")
+
+grpc_proto_library(
+    name = "status_proto",
+    srcs = ["status.proto"],
+    has_services = False,
+    well_known_protos = "@submodule_protobuf//:well_known_protos",
+)
+
+
diff --git a/src/proto/grpc/status/README b/src/proto/grpc/status/README
new file mode 100644
index 0000000..34e588e
--- /dev/null
+++ b/src/proto/grpc/status/README
@@ -0,0 +1,2 @@
+The status.proto file is copied from
+https://github.com/googleapis/googleapis/blob/master/google/rpc/status.proto.
diff --git a/src/proto/grpc/status/status.proto b/src/proto/grpc/status/status.proto
new file mode 100644
index 0000000..bc6097b
--- /dev/null
+++ b/src/proto/grpc/status/status.proto
@@ -0,0 +1,92 @@
+// Copyright 2016 Google Inc.
+//
+// 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.
+
+syntax = "proto3";
+
+package google.rpc;
+
+import "google/protobuf/any.proto";
+
+option go_package = "google.golang.org/genproto/googleapis/rpc/status;status";
+option java_multiple_files = true;
+option java_outer_classname = "StatusProto";
+option java_package = "com.google.rpc";
+option objc_class_prefix = "RPC";
+
+
+// The `Status` type defines a logical error model that is suitable for different
+// programming environments, including REST APIs and RPC APIs. It is used by
+// [gRPC](https://github.com/grpc). The error model is designed to be:
+//
+// - Simple to use and understand for most users
+// - Flexible enough to meet unexpected needs
+//
+// # Overview
+//
+// The `Status` message contains three pieces of data: error code, error message,
+// and error details. The error code should be an enum value of
+// [google.rpc.Code][google.rpc.Code], but it may accept additional error codes if needed.  The
+// error message should be a developer-facing English message that helps
+// developers *understand* and *resolve* the error. If a localized user-facing
+// error message is needed, put the localized message in the error details or
+// localize it in the client. The optional error details may contain arbitrary
+// information about the error. There is a predefined set of error detail types
+// in the package `google.rpc` which can be used for common error conditions.
+//
+// # Language mapping
+//
+// The `Status` message is the logical representation of the error model, but it
+// is not necessarily the actual wire format. When the `Status` message is
+// exposed in different client libraries and different wire protocols, it can be
+// mapped differently. For example, it will likely be mapped to some exceptions
+// in Java, but more likely mapped to some error codes in C.
+//
+// # Other uses
+//
+// The error model and the `Status` message can be used in a variety of
+// environments, either with or without APIs, to provide a
+// consistent developer experience across different environments.
+//
+// Example uses of this error model include:
+//
+// - Partial errors. If a service needs to return partial errors to the client,
+//     it may embed the `Status` in the normal response to indicate the partial
+//     errors.
+//
+// - Workflow errors. A typical workflow has multiple steps. Each step may
+//     have a `Status` message for error reporting purpose.
+//
+// - Batch operations. If a client uses batch request and batch response, the
+//     `Status` message should be used directly inside batch response, one for
+//     each error sub-response.
+//
+// - Asynchronous operations. If an API call embeds asynchronous operation
+//     results in its response, the status of those operations should be
+//     represented directly using the `Status` message.
+//
+// - Logging. If some API errors are stored in logs, the message `Status` could
+//     be used directly after any stripping needed for security/privacy reasons.
+message Status {
+  // The status code, which should be an enum value of [google.rpc.Code][google.rpc.Code].
+  int32 code = 1;
+
+  // A developer-facing error message, which should be in English. Any
+  // user-facing error message should be localized and sent in the
+  // [google.rpc.Status.details][google.rpc.Status.details] field, or localized by the client.
+  string message = 2;
+
+  // A list of messages that carry the error details.  There will be a
+  // common set of message types for APIs to use.
+  repeated google.protobuf.Any details = 3;
+}
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/completion_queue.pyx.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/completion_queue.pyx.pxi
index d8df6c2..34b2623 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/completion_queue.pyx.pxi
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/completion_queue.pyx.pxi
@@ -40,7 +40,7 @@
   def __cinit__(self):
     grpc_init()
     with nogil:
-      self.c_completion_queue = grpc_completion_queue_create(NULL)
+      self.c_completion_queue = grpc_completion_queue_create_for_next(NULL)
     self.is_shutting_down = False
     self.is_shutdown = False
 
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxi
index bbd7242..0b2bdef 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxi
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxi
@@ -309,7 +309,8 @@
   void grpc_init() nogil
   void grpc_shutdown() nogil
 
-  grpc_completion_queue *grpc_completion_queue_create(void *reserved) nogil
+  grpc_completion_queue *grpc_completion_queue_create_for_next(void *reserved) nogil
+
   grpc_event grpc_completion_queue_next(grpc_completion_queue *cq,
                                         gpr_timespec deadline,
                                         void *reserved) nogil
diff --git a/src/python/grpcio/grpc_core_dependencies.py b/src/python/grpcio/grpc_core_dependencies.py
index 0d0a5fb..16bb32b 100644
--- a/src/python/grpcio/grpc_core_dependencies.py
+++ b/src/python/grpcio/grpc_core_dependencies.py
@@ -80,15 +80,10 @@
   'src/core/lib/channel/channel_args.c',
   'src/core/lib/channel/channel_stack.c',
   'src/core/lib/channel/channel_stack_builder.c',
-  'src/core/lib/channel/compress_filter.c',
   'src/core/lib/channel/connected_channel.c',
-  'src/core/lib/channel/deadline_filter.c',
   'src/core/lib/channel/handshaker.c',
   'src/core/lib/channel/handshaker_factory.c',
   'src/core/lib/channel/handshaker_registry.c',
-  'src/core/lib/channel/http_client_filter.c',
-  'src/core/lib/channel/http_server_filter.c',
-  'src/core/lib/channel/message_size_filter.c',
   'src/core/lib/compression/compression.c',
   'src/core/lib/compression/message_compress.c',
   'src/core/lib/debug/trace.c',
@@ -216,6 +211,7 @@
   'src/core/ext/transport/chttp2/transport/hpack_encoder.c',
   'src/core/ext/transport/chttp2/transport/hpack_parser.c',
   'src/core/ext/transport/chttp2/transport/hpack_table.c',
+  'src/core/ext/transport/chttp2/transport/http2_settings.c',
   'src/core/ext/transport/chttp2/transport/huffsyms.c',
   'src/core/ext/transport/chttp2/transport/incoming_metadata.c',
   'src/core/ext/transport/chttp2/transport/parsing.c',
@@ -224,6 +220,10 @@
   'src/core/ext/transport/chttp2/transport/varint.c',
   'src/core/ext/transport/chttp2/transport/writing.c',
   'src/core/ext/transport/chttp2/alpn/alpn.c',
+  'src/core/ext/filters/http/client/http_client_filter.c',
+  'src/core/ext/filters/http/http_filters_plugin.c',
+  'src/core/ext/filters/http/message_compress/message_compress_filter.c',
+  'src/core/ext/filters/http/server/http_server_filter.c',
   'src/core/lib/http/httpcli_security_connector.c',
   'src/core/lib/security/context/security_context.c',
   'src/core/lib/security/credentials/composite/composite_credentials.c',
@@ -273,6 +273,7 @@
   'src/core/ext/filters/client_channel/subchannel.c',
   'src/core/ext/filters/client_channel/subchannel_index.c',
   'src/core/ext/filters/client_channel/uri_parser.c',
+  'src/core/ext/filters/deadline/deadline_filter.c',
   'src/core/ext/transport/chttp2/client/chttp2_connector.c',
   'src/core/ext/transport/chttp2/server/insecure/server_chttp2.c',
   'src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c',
@@ -309,6 +310,7 @@
   'src/core/ext/census/trace_context.c',
   'src/core/ext/census/tracing.c',
   'src/core/ext/filters/max_age/max_age_filter.c',
+  'src/core/ext/filters/message_size/message_size_filter.c',
   'src/core/plugin_registry/grpc_plugin_registry.c',
   'src/boringssl/err_data.c',
   'third_party/boringssl/crypto/aes/aes.c',
diff --git a/src/python/grpcio/grpc_version.py b/src/python/grpcio/grpc_version.py
index 267d848..ea4bc7b 100644
--- a/src/python/grpcio/grpc_version.py
+++ b/src/python/grpcio/grpc_version.py
@@ -29,4 +29,4 @@
 
 # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio/grpc_version.py.template`!!!
 
-VERSION='1.3.0.dev0'
+VERSION='1.4.0.dev0'
diff --git a/src/python/grpcio_health_checking/grpc_version.py b/src/python/grpcio_health_checking/grpc_version.py
index 4ff5e26..26aa555 100644
--- a/src/python/grpcio_health_checking/grpc_version.py
+++ b/src/python/grpcio_health_checking/grpc_version.py
@@ -29,4 +29,4 @@
 
 # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_health_checking/grpc_version.py.template`!!!
 
-VERSION='1.3.0.dev0'
+VERSION='1.4.0.dev0'
diff --git a/src/python/grpcio_reflection/grpc_reflection/v1alpha/reflection.py b/src/python/grpcio_reflection/grpc_reflection/v1alpha/reflection.py
index c58cb3e..cd896f3 100644
--- a/src/python/grpcio_reflection/grpc_reflection/v1alpha/reflection.py
+++ b/src/python/grpcio_reflection/grpc_reflection/v1alpha/reflection.py
@@ -56,7 +56,7 @@
             file_descriptor_proto=(serialized_proto,)),)
 
 
-class ReflectionServicer(reflection_pb2.ServerReflectionServicer):
+class ReflectionServicer(reflection_pb2_grpc.ServerReflectionServicer):
     """Servicer handling RPCs for service statuses."""
 
     def __init__(self, service_names, pool=None):
diff --git a/src/python/grpcio_reflection/grpc_version.py b/src/python/grpcio_reflection/grpc_version.py
index 8ffc08c..978d6b4 100644
--- a/src/python/grpcio_reflection/grpc_version.py
+++ b/src/python/grpcio_reflection/grpc_version.py
@@ -29,4 +29,4 @@
 
 # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_reflection/grpc_version.py.template`!!!
 
-VERSION='1.3.0.dev0'
+VERSION='1.4.0.dev0'
diff --git a/src/python/grpcio_tests/grpc_version.py b/src/python/grpcio_tests/grpc_version.py
index ba82dce..5f0b084 100644
--- a/src/python/grpcio_tests/grpc_version.py
+++ b/src/python/grpcio_tests/grpc_version.py
@@ -29,4 +29,4 @@
 
 # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_tests/grpc_version.py.template`!!!
 
-VERSION='1.3.0.dev0'
+VERSION='1.4.0.dev0'
diff --git a/src/ruby/ext/grpc/rb_channel.c b/src/ruby/ext/grpc/rb_channel.c
index 1c20c88..05f7160 100644
--- a/src/ruby/ext/grpc/rb_channel.c
+++ b/src/ruby/ext/grpc/rb_channel.c
@@ -351,7 +351,7 @@
     parent_call = grpc_rb_get_wrapped_call(parent);
   }
 
-  cq = grpc_completion_queue_create(NULL);
+  cq = grpc_completion_queue_create_for_pluck(NULL);
   TypedData_Get_Struct(self, grpc_rb_channel, &grpc_channel_data_type, wrapper);
   ch = wrapper->wrapped;
   if (ch == NULL) {
@@ -522,7 +522,7 @@
  * TODO(apolcyn) remove this when core handles new RPCs on dead connections.
  */
 static void start_poll_channels_loop() {
-  channel_polling_cq = grpc_completion_queue_create(NULL);
+  channel_polling_cq = grpc_completion_queue_create_for_next(NULL);
   gpr_mu_init(&global_connection_polling_mu);
   abort_channel_polling = 0;
   rb_thread_create(run_poll_channels_loop, NULL);
diff --git a/src/ruby/ext/grpc/rb_grpc_imports.generated.c b/src/ruby/ext/grpc/rb_grpc_imports.generated.c
index 063f921..f189e88 100644
--- a/src/ruby/ext/grpc/rb_grpc_imports.generated.c
+++ b/src/ruby/ext/grpc/rb_grpc_imports.generated.c
@@ -110,7 +110,6 @@
 grpc_channel_create_registered_call_type grpc_channel_create_registered_call_import;
 grpc_call_start_batch_type grpc_call_start_batch_import;
 grpc_call_get_peer_type grpc_call_get_peer_import;
-grpc_call_set_load_reporting_cost_context_type grpc_call_set_load_reporting_cost_context_import;
 grpc_census_call_set_context_type grpc_census_call_set_context_import;
 grpc_census_call_get_context_type grpc_census_call_get_context_import;
 grpc_channel_get_target_type grpc_channel_get_target_import;
@@ -407,7 +406,6 @@
   grpc_channel_create_registered_call_import = (grpc_channel_create_registered_call_type) GetProcAddress(library, "grpc_channel_create_registered_call");
   grpc_call_start_batch_import = (grpc_call_start_batch_type) GetProcAddress(library, "grpc_call_start_batch");
   grpc_call_get_peer_import = (grpc_call_get_peer_type) GetProcAddress(library, "grpc_call_get_peer");
-  grpc_call_set_load_reporting_cost_context_import = (grpc_call_set_load_reporting_cost_context_type) GetProcAddress(library, "grpc_call_set_load_reporting_cost_context");
   grpc_census_call_set_context_import = (grpc_census_call_set_context_type) GetProcAddress(library, "grpc_census_call_set_context");
   grpc_census_call_get_context_import = (grpc_census_call_get_context_type) GetProcAddress(library, "grpc_census_call_get_context");
   grpc_channel_get_target_import = (grpc_channel_get_target_type) GetProcAddress(library, "grpc_channel_get_target");
diff --git a/src/ruby/ext/grpc/rb_grpc_imports.generated.h b/src/ruby/ext/grpc/rb_grpc_imports.generated.h
index f5dcd68..dcdc806 100644
--- a/src/ruby/ext/grpc/rb_grpc_imports.generated.h
+++ b/src/ruby/ext/grpc/rb_grpc_imports.generated.h
@@ -233,7 +233,7 @@
 typedef grpc_completion_queue *(*grpc_completion_queue_create_for_pluck_type)(void *reserved);
 extern grpc_completion_queue_create_for_pluck_type grpc_completion_queue_create_for_pluck_import;
 #define grpc_completion_queue_create_for_pluck grpc_completion_queue_create_for_pluck_import
-typedef grpc_completion_queue *(*grpc_completion_queue_create_type)(void *reserved);
+typedef grpc_completion_queue *(*grpc_completion_queue_create_type)(const grpc_completion_queue_factory *factory, const grpc_completion_queue_attributes *attributes, void *reserved);
 extern grpc_completion_queue_create_type grpc_completion_queue_create_import;
 #define grpc_completion_queue_create grpc_completion_queue_create_import
 typedef grpc_event(*grpc_completion_queue_next_type)(grpc_completion_queue *cq, gpr_timespec deadline, void *reserved);
@@ -281,9 +281,6 @@
 typedef char *(*grpc_call_get_peer_type)(grpc_call *call);
 extern grpc_call_get_peer_type grpc_call_get_peer_import;
 #define grpc_call_get_peer grpc_call_get_peer_import
-typedef void(*grpc_call_set_load_reporting_cost_context_type)(grpc_call *call, struct grpc_load_reporting_cost_context *context);
-extern grpc_call_set_load_reporting_cost_context_type grpc_call_set_load_reporting_cost_context_import;
-#define grpc_call_set_load_reporting_cost_context grpc_call_set_load_reporting_cost_context_import
 typedef void(*grpc_census_call_set_context_type)(grpc_call *call, struct census_context *context);
 extern grpc_census_call_set_context_type grpc_census_call_set_context_import;
 #define grpc_census_call_set_context grpc_census_call_set_context_import
diff --git a/src/ruby/ext/grpc/rb_server.c b/src/ruby/ext/grpc/rb_server.c
index 7b2f5774..ef57d5b 100644
--- a/src/ruby/ext/grpc/rb_server.c
+++ b/src/ruby/ext/grpc/rb_server.c
@@ -37,15 +37,15 @@
 #include "rb_server.h"
 
 #include <grpc/grpc.h>
-#include <grpc/support/atm.h>
 #include <grpc/grpc_security.h>
+#include <grpc/support/atm.h>
 #include <grpc/support/log.h>
+#include "rb_byte_buffer.h"
 #include "rb_call.h"
 #include "rb_channel_args.h"
 #include "rb_completion_queue.h"
-#include "rb_server_credentials.h"
-#include "rb_byte_buffer.h"
 #include "rb_grpc.h"
+#include "rb_server_credentials.h"
 
 /* grpc_rb_cServer is the ruby class that proxies grpc_server. */
 static VALUE grpc_rb_cServer = Qnil;
@@ -93,9 +93,8 @@
   };
   svr = (grpc_rb_server *)p;
 
-  deadline = gpr_time_add(
-      gpr_now(GPR_CLOCK_REALTIME),
-      gpr_time_from_seconds(2, GPR_TIMESPAN));
+  deadline = gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
+                          gpr_time_from_seconds(2, GPR_TIMESPAN));
 
   destroy_server(svr, deadline);
 
@@ -104,13 +103,15 @@
 
 static const rb_data_type_t grpc_rb_server_data_type = {
     "grpc_server",
-    {GRPC_RB_GC_NOT_MARKED, grpc_rb_server_free, GRPC_RB_MEMSIZE_UNAVAILABLE,
+    {GRPC_RB_GC_NOT_MARKED,
+     grpc_rb_server_free,
+     GRPC_RB_MEMSIZE_UNAVAILABLE,
      {NULL, NULL}},
     NULL,
     NULL,
 #ifdef RUBY_TYPED_FREE_IMMEDIATELY
-    /* It is unsafe to specify RUBY_TYPED_FREE_IMMEDIATELY because the free function would block
-     * and we might want to unlock GVL
+    /* It is unsafe to specify RUBY_TYPED_FREE_IMMEDIATELY because the free
+     * function would block and we might want to unlock GVL
      * TODO(yugui) Unlock GVL?
      */
     0,
@@ -131,7 +132,7 @@
 
   Initializes server instances. */
 static VALUE grpc_rb_server_init(VALUE self, VALUE channel_args) {
-  grpc_completion_queue *cq = grpc_completion_queue_create(NULL);
+  grpc_completion_queue *cq = grpc_completion_queue_create_for_pluck(NULL);
   grpc_rb_server *wrapper = NULL;
   grpc_server *srv = NULL;
   grpc_channel_args args;
@@ -163,7 +164,7 @@
 
 /* grpc_request_call_stack_init ensures the request_call_stack is properly
  * initialized */
-static void grpc_request_call_stack_init(request_call_stack* st) {
+static void grpc_request_call_stack_init(request_call_stack *st) {
   MEMZERO(st, request_call_stack, 1);
   grpc_metadata_array_init(&st->md_ary);
   grpc_call_details_init(&st->details);
@@ -171,7 +172,7 @@
 
 /* grpc_request_call_stack_cleanup ensures the request_call_stack is properly
  * cleaned up */
-static void grpc_request_call_stack_cleanup(request_call_stack* st) {
+static void grpc_request_call_stack_cleanup(request_call_stack *st) {
   grpc_metadata_array_destroy(&st->md_ary);
   grpc_call_details_destroy(&st->details);
 }
@@ -187,8 +188,9 @@
   grpc_call_error err;
   request_call_stack st;
   VALUE result;
-  void *tag = (void*)&st;
-  grpc_completion_queue *call_queue = grpc_completion_queue_create(NULL);
+  void *tag = (void *)&st;
+  grpc_completion_queue *call_queue =
+      grpc_completion_queue_create_for_pluck(NULL);
   gpr_timespec deadline;
 
   TypedData_Get_Struct(self, grpc_rb_server, &grpc_rb_server_data_type, s);
@@ -199,9 +201,8 @@
   grpc_request_call_stack_init(&st);
   /* call grpc_server_request_call, then wait for it to complete using
    * pluck_event */
-  err = grpc_server_request_call(
-      s->wrapped, &call, &st.details, &st.md_ary,
-      call_queue, s->queue, tag);
+  err = grpc_server_request_call(s->wrapped, &call, &st.details, &st.md_ary,
+                                 call_queue, s->queue, tag);
   if (err != GRPC_CALL_OK) {
     grpc_request_call_stack_cleanup(&st);
     rb_raise(grpc_rb_eCallError,
@@ -218,8 +219,6 @@
     return Qnil;
   }
 
-
-
   /* build the NewServerRpc struct result */
   deadline = gpr_convert_clock_type(st.details.deadline, GPR_CLOCK_REALTIME);
   result = rb_struct_new(
@@ -299,8 +298,7 @@
     return Qnil;
   } else if (TYPE(rb_creds) == T_SYMBOL) {
     if (id_insecure_server != SYM2ID(rb_creds)) {
-      rb_raise(rb_eTypeError,
-               "bad creds symbol, want :this_port_is_insecure");
+      rb_raise(rb_eTypeError, "bad creds symbol, want :this_port_is_insecure");
       return Qnil;
     }
     recvd_port =
@@ -312,9 +310,8 @@
     }
   } else {
     creds = grpc_rb_get_wrapped_server_credentials(rb_creds);
-    recvd_port =
-        grpc_server_add_secure_http2_port(s->wrapped, StringValueCStr(port),
-                                          creds);
+    recvd_port = grpc_server_add_secure_http2_port(
+        s->wrapped, StringValueCStr(port), creds);
     if (recvd_port == 0) {
       rb_raise(rb_eRuntimeError,
                "could not add secure port %s to server, not sure why",
@@ -333,18 +330,17 @@
 
   /* Provides a ruby constructor and support for dup/clone. */
   rb_define_method(grpc_rb_cServer, "initialize", grpc_rb_server_init, 1);
-  rb_define_method(grpc_rb_cServer, "initialize_copy",
-                   grpc_rb_cannot_init_copy, 1);
+  rb_define_method(grpc_rb_cServer, "initialize_copy", grpc_rb_cannot_init_copy,
+                   1);
 
   /* Add the server methods. */
-  rb_define_method(grpc_rb_cServer, "request_call",
-                   grpc_rb_server_request_call, 0);
+  rb_define_method(grpc_rb_cServer, "request_call", grpc_rb_server_request_call,
+                   0);
   rb_define_method(grpc_rb_cServer, "start", grpc_rb_server_start, 0);
   rb_define_method(grpc_rb_cServer, "destroy", grpc_rb_server_destroy, -1);
   rb_define_alias(grpc_rb_cServer, "close", "destroy");
   rb_define_method(grpc_rb_cServer, "add_http2_port",
-                   grpc_rb_server_add_http2_port,
-                   2);
+                   grpc_rb_server_add_http2_port, 2);
   id_at = rb_intern("at");
   id_insecure_server = rb_intern("this_port_is_insecure");
 }
diff --git a/src/ruby/lib/grpc/version.rb b/src/ruby/lib/grpc/version.rb
index 9901158..f30dff3 100644
--- a/src/ruby/lib/grpc/version.rb
+++ b/src/ruby/lib/grpc/version.rb
@@ -29,5 +29,5 @@
 
 # GRPC contains the General RPC module.
 module GRPC
-  VERSION = '1.3.0.dev'
+  VERSION = '1.4.0.dev'
 end
diff --git a/src/ruby/tools/version.rb b/src/ruby/tools/version.rb
index 632c010..1f8d4af 100644
--- a/src/ruby/tools/version.rb
+++ b/src/ruby/tools/version.rb
@@ -29,6 +29,6 @@
 
 module GRPC
   module Tools
-    VERSION = '1.3.0.dev'
+    VERSION = '1.4.0.dev'
   end
 end
diff --git a/templates/CMakeLists.txt.template b/templates/CMakeLists.txt.template
index cf69f0c..c647ea5 100644
--- a/templates/CMakeLists.txt.template
+++ b/templates/CMakeLists.txt.template
@@ -212,6 +212,7 @@
     if(NOT PROTOBUF_ROOT_DIR)
       set(PROTOBUF_ROOT_DIR <%text>${CMAKE_CURRENT_SOURCE_DIR}</%text>/third_party/protobuf)
     endif()
+    set(PROTOBUF_WELLKNOWN_IMPORT_DIR <%text>${PROTOBUF_ROOT_DIR}</%text>/src)
     if(EXISTS "<%text>${PROTOBUF_ROOT_DIR}</%text>/cmake/CMakeLists.txt")
       set(protobuf_MSVC_STATIC_RUNTIME OFF CACHE BOOL "Link static runtime libraries")
       add_subdirectory(<%text>${PROTOBUF_ROOT_DIR}</%text>/cmake third_party/protobuf)
@@ -244,6 +245,7 @@
       find_package(Protobuf MODULE)
       set(_gRPC_FIND_PROTOBUF "if(NOT Protobuf_FOUND)\n  find_package(Protobuf)\nendif()")
     endif()
+    set(PROTOBUF_WELLKNOWN_IMPORT_DIR /usr/local/include)
   endif()
 
   if("<%text>${gRPC_SSL_PROVIDER}</%text>" STREQUAL "module")
@@ -346,7 +348,7 @@
       return()
     endif()
 
-    set(_protobuf_include_path -I .)
+    set(_protobuf_include_path -I . -I <%text>${PROTOBUF_WELLKNOWN_IMPORT_DIR}</%text>)
     foreach(FIL <%text>${ARGN}</%text>)
       get_filename_component(ABS_FIL <%text>${FIL}</%text> ABSOLUTE)
       get_filename_component(FIL_WE <%text>${FIL}</%text> NAME_WE)
diff --git a/templates/Makefile.template b/templates/Makefile.template
index 8f61a8b..1e6ca93 100644
--- a/templates/Makefile.template
+++ b/templates/Makefile.template
@@ -1609,7 +1609,7 @@
   ifeq ($(SYSTEM),Darwin)
   	$(Q) ${ld} ${ldflags} -L$(LIBDIR)/$(CONFIG) -install_name $(SHARED_PREFIX)${lib.name}$(SHARED_VERSION_${lang_to_var[lib.language]}).$(SHARED_EXT_${lang_to_var[lib.language]}) -dynamiclib -o ${out_libbase}.$(SHARED_EXT_${lang_to_var[lib.language]}) ${common}${link_libs}
   else
-  	$(Q) ${ld} ${ldflags} -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,lib${lib.name}.so.${settings.core_version.major} -o ${out_libbase}.$(SHARED_EXT_${lang_to_var[lib.language]}) ${common}${link_libs}
+  	$(Q) ${ld} ${ldflags} -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,lib${lib.name}.so.${settings.get(lang_to_var[lib.language].lower() + '_version').major} -o ${out_libbase}.$(SHARED_EXT_${lang_to_var[lib.language]}) ${common}${link_libs}
   	$(Q) ln -sf $(SHARED_PREFIX)${lib.name}$(SHARED_VERSION_${lang_to_var[lib.language]}).$(SHARED_EXT_${lang_to_var[lib.language]}) ${out_libbase}.so.${settings.get(lang_to_var[lib.language].lower() + '_version').major}
   	$(Q) ln -sf $(SHARED_PREFIX)${lib.name}$(SHARED_VERSION_${lang_to_var[lib.language]}).$(SHARED_EXT_${lang_to_var[lib.language]}) ${out_libbase}.so
   endif
diff --git a/test/core/bad_client/bad_client.c b/test/core/bad_client/bad_client.c
index 9a566e6..8dbc5aa 100644
--- a/test/core/bad_client/bad_client.c
+++ b/test/core/bad_client/bad_client.c
@@ -40,9 +40,9 @@
 #include <grpc/support/sync.h>
 #include <grpc/support/thd.h>
 
+#include "src/core/ext/filters/http/server/http_server_filter.h"
 #include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
 #include "src/core/lib/channel/channel_stack.h"
-#include "src/core/lib/channel/http_server_filter.h"
 #include "src/core/lib/iomgr/endpoint_pair.h"
 #include "src/core/lib/slice/slice_internal.h"
 #include "src/core/lib/support/murmur_hash.h"
@@ -104,6 +104,7 @@
   grpc_slice_buffer outgoing;
   grpc_closure done_write_closure;
   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+  grpc_completion_queue *shutdown_cq;
 
   hex = gpr_dump(client_payload, client_payload_length,
                  GPR_DUMP_HEX | GPR_DUMP_ASCII);
@@ -121,7 +122,7 @@
 
   /* Create server, completion events */
   a.server = grpc_server_create(NULL, NULL);
-  a.cq = grpc_completion_queue_create(NULL);
+  a.cq = grpc_completion_queue_create_for_next(NULL);
   gpr_event_init(&a.done_thd);
   gpr_event_init(&a.done_write);
   a.validator = server_validator;
@@ -194,10 +195,13 @@
     grpc_endpoint_destroy(&exec_ctx, sfd.client);
     grpc_exec_ctx_finish(&exec_ctx);
   }
-  grpc_server_shutdown_and_notify(a.server, a.cq, NULL);
+
+  shutdown_cq = grpc_completion_queue_create_for_pluck(NULL);
+  grpc_server_shutdown_and_notify(a.server, shutdown_cq, NULL);
   GPR_ASSERT(grpc_completion_queue_pluck(
-                 a.cq, NULL, grpc_timeout_seconds_to_deadline(1), NULL)
+                 shutdown_cq, NULL, grpc_timeout_seconds_to_deadline(1), NULL)
                  .type == GRPC_OP_COMPLETE);
+  grpc_completion_queue_destroy(shutdown_cq);
   grpc_server_destroy(a.server);
   grpc_completion_queue_destroy(a.cq);
   grpc_slice_buffer_destroy_internal(&exec_ctx, &outgoing);
diff --git a/test/core/bad_ssl/bad_ssl_test.c b/test/core/bad_ssl/bad_ssl_test.c
index bd85585..b961ffa 100644
--- a/test/core/bad_ssl/bad_ssl_test.c
+++ b/test/core/bad_ssl/bad_ssl_test.c
@@ -61,7 +61,7 @@
   grpc_status_code status;
   grpc_call_error error;
   gpr_timespec deadline = grpc_timeout_seconds_to_deadline(5);
-  grpc_completion_queue *cq = grpc_completion_queue_create(NULL);
+  grpc_completion_queue *cq = grpc_completion_queue_create_for_next(NULL);
   cq_verifier *cqv = cq_verifier_create(cq);
 
   grpc_op ops[6];
diff --git a/test/core/bad_ssl/server_common.c b/test/core/bad_ssl/server_common.c
index 6a4313e..0ec1467 100644
--- a/test/core/bad_ssl/server_common.c
+++ b/test/core/bad_ssl/server_common.c
@@ -66,7 +66,9 @@
   grpc_call *s = NULL;
   grpc_call_details call_details;
   grpc_metadata_array request_metadata_recv;
-  grpc_completion_queue *cq = grpc_completion_queue_create(NULL);
+
+  grpc_completion_queue *cq = grpc_completion_queue_create_for_next(NULL);
+  grpc_completion_queue *shutdown_cq;
 
   grpc_call_details_init(&call_details);
   grpc_metadata_array_init(&request_metadata_recv);
@@ -82,10 +84,13 @@
   while (!shutdown_finished) {
     if (got_sigint && !shutdown_started) {
       gpr_log(GPR_INFO, "Shutting down due to SIGINT");
-      grpc_server_shutdown_and_notify(server, cq, NULL);
-      GPR_ASSERT(grpc_completion_queue_pluck(
-                     cq, NULL, grpc_timeout_seconds_to_deadline(5), NULL)
-                     .type == GRPC_OP_COMPLETE);
+      shutdown_cq = grpc_completion_queue_create_for_pluck(NULL);
+      grpc_server_shutdown_and_notify(server, shutdown_cq, NULL);
+      GPR_ASSERT(
+          grpc_completion_queue_pluck(shutdown_cq, NULL,
+                                      grpc_timeout_seconds_to_deadline(5), NULL)
+              .type == GRPC_OP_COMPLETE);
+      grpc_completion_queue_destroy(shutdown_cq);
       grpc_completion_queue_shutdown(cq);
       shutdown_started = 1;
     }
diff --git a/test/core/channel/minimal_stack_is_minimal_test.c b/test/core/channel/minimal_stack_is_minimal_test.c
new file mode 100644
index 0000000..bac94cb
--- /dev/null
+++ b/test/core/channel/minimal_stack_is_minimal_test.c
@@ -0,0 +1,232 @@
+/*
+ *
+ * Copyright 2017, 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.
+ *
+ */
+
+/*******************************************************************************
+ * This test verifies that various stack configurations result in the set of
+ * filters that we expect.
+ *
+ * This is akin to a golden-file test, and suffers the same disadvantages and
+ * advantages: it reflects that the code as written has not been modified - and
+ * valid code modifications WILL break this test and it will need updating.
+ *
+ * The intent therefore is to allow code reviewers to more easily catch changes
+ * that perturb the generated list of channel filters in different
+ * configurations and assess whether such a change is correct and desirable.
+ */
+
+#include <grpc/grpc.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/string_util.h>
+#include <string.h>
+
+#include "src/core/lib/channel/channel_stack_builder.h"
+#include "src/core/lib/support/string.h"
+#include "src/core/lib/surface/channel_init.h"
+#include "src/core/lib/surface/channel_stack_type.h"
+#include "src/core/lib/transport/transport_impl.h"
+#include "test/core/util/test_config.h"
+
+// use CHECK_STACK instead
+static int check_stack(const char *file, int line, const char *transport_name,
+                       grpc_channel_args *init_args,
+                       grpc_channel_stack_type channel_stack_type, ...);
+
+// arguments: const char *transport_name   - the name of the transport type to
+//                                           simulate
+//            grpc_channel_args *init_args - channel args to pass down
+//            grpc_channel_stack_type channel_stack_type - the archetype of
+//                                           channel stack to create
+//            variadic arguments - the (in-order) expected list of channel
+//                                 filters to instantiate, terminated with NULL
+#define CHECK_STACK(...) check_stack(__FILE__, __LINE__, __VA_ARGS__)
+
+int main(int argc, char **argv) {
+  grpc_test_init(argc, argv);
+  grpc_init();
+  int errors = 0;
+
+  // tests with a minimal stack
+  grpc_arg minimal_stack_arg = {.type = GRPC_ARG_INTEGER,
+                                .key = GRPC_ARG_MINIMAL_STACK,
+                                .value.integer = 1};
+  grpc_channel_args minimal_stack_args = {.num_args = 1,
+                                          .args = &minimal_stack_arg};
+  errors += CHECK_STACK("unknown", &minimal_stack_args,
+                        GRPC_CLIENT_DIRECT_CHANNEL, "connected", NULL);
+  errors += CHECK_STACK("unknown", &minimal_stack_args, GRPC_CLIENT_SUBCHANNEL,
+                        "connected", NULL);
+  errors += CHECK_STACK("unknown", &minimal_stack_args, GRPC_SERVER_CHANNEL,
+                        "server", "connected", NULL);
+  errors +=
+      CHECK_STACK("chttp2", &minimal_stack_args, GRPC_CLIENT_DIRECT_CHANNEL,
+                  "http-client", "connected", NULL);
+  errors += CHECK_STACK("chttp2", &minimal_stack_args, GRPC_CLIENT_SUBCHANNEL,
+                        "http-client", "connected", NULL);
+  errors += CHECK_STACK("chttp2", &minimal_stack_args, GRPC_SERVER_CHANNEL,
+                        "server", "http-server", "connected", NULL);
+  errors += CHECK_STACK(NULL, &minimal_stack_args, GRPC_CLIENT_CHANNEL,
+                        "client-channel", NULL);
+
+  // tests with a default stack
+  errors += CHECK_STACK("unknown", NULL, GRPC_CLIENT_DIRECT_CHANNEL,
+                        "message_size", "deadline", "connected", NULL);
+  errors += CHECK_STACK("unknown", NULL, GRPC_CLIENT_SUBCHANNEL, "message_size",
+                        "connected", NULL);
+  errors += CHECK_STACK("unknown", NULL, GRPC_SERVER_CHANNEL, "server",
+                        "message_size", "deadline", "connected", NULL);
+  errors +=
+      CHECK_STACK("chttp2", NULL, GRPC_CLIENT_DIRECT_CHANNEL, "message_size",
+                  "deadline", "http-client", "compress", "connected", NULL);
+  errors += CHECK_STACK("chttp2", NULL, GRPC_CLIENT_SUBCHANNEL, "message_size",
+                        "http-client", "compress", "connected", NULL);
+  errors +=
+      CHECK_STACK("chttp2", NULL, GRPC_SERVER_CHANNEL, "server", "message_size",
+                  "deadline", "http-server", "compress", "connected", NULL);
+  errors +=
+      CHECK_STACK(NULL, NULL, GRPC_CLIENT_CHANNEL, "client-channel", NULL);
+
+  GPR_ASSERT(errors == 0);
+  grpc_shutdown();
+  return 0;
+}
+
+/*******************************************************************************
+ * End of tests definitions, start of test infrastructure
+ */
+
+static int check_stack(const char *file, int line, const char *transport_name,
+                       grpc_channel_args *init_args,
+                       grpc_channel_stack_type channel_stack_type, ...) {
+  // create dummy channel stack
+  grpc_channel_stack_builder *builder = grpc_channel_stack_builder_create();
+  grpc_transport_vtable fake_transport_vtable = {.name = transport_name};
+  grpc_transport fake_transport = {.vtable = &fake_transport_vtable};
+  grpc_channel_stack_builder_set_target(builder, "foo.test.google.fr");
+  grpc_channel_args *channel_args = grpc_channel_args_copy(init_args);
+  if (transport_name != NULL) {
+    grpc_channel_stack_builder_set_transport(builder, &fake_transport);
+  }
+  {
+    grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+    grpc_channel_stack_builder_set_channel_arguments(&exec_ctx, builder,
+                                                     channel_args);
+    GPR_ASSERT(
+        grpc_channel_init_create_stack(&exec_ctx, builder, channel_stack_type));
+    grpc_exec_ctx_finish(&exec_ctx);
+  }
+
+  // build up our expectation list
+  gpr_strvec v;
+  gpr_strvec_init(&v);
+  va_list args;
+  va_start(args, channel_stack_type);
+  for (;;) {
+    char *a = va_arg(args, char *);
+    if (a == NULL) break;
+    if (v.count != 0) gpr_strvec_add(&v, gpr_strdup(", "));
+    gpr_strvec_add(&v, gpr_strdup(a));
+  }
+  va_end(args);
+  char *expect = gpr_strvec_flatten(&v, NULL);
+  gpr_strvec_destroy(&v);
+
+  // build up our "got" list
+  gpr_strvec_init(&v);
+  grpc_channel_stack_builder_iterator *it =
+      grpc_channel_stack_builder_create_iterator_at_first(builder);
+  while (grpc_channel_stack_builder_move_next(it)) {
+    const char *name = grpc_channel_stack_builder_iterator_filter_name(it);
+    if (name == NULL) continue;
+    if (v.count != 0) gpr_strvec_add(&v, gpr_strdup(", "));
+    gpr_strvec_add(&v, gpr_strdup(name));
+  }
+  char *got = gpr_strvec_flatten(&v, NULL);
+  gpr_strvec_destroy(&v);
+  grpc_channel_stack_builder_iterator_destroy(it);
+
+  // figure out result, log if there's an error
+  int result = 0;
+  if (0 != strcmp(got, expect)) {
+    gpr_strvec_init(&v);
+    gpr_strvec_add(&v, gpr_strdup("{"));
+    for (size_t i = 0; i < channel_args->num_args; i++) {
+      if (i > 0) gpr_strvec_add(&v, gpr_strdup(", "));
+      gpr_strvec_add(&v, gpr_strdup(channel_args->args[i].key));
+      gpr_strvec_add(&v, gpr_strdup("="));
+      switch (channel_args->args[i].type) {
+        case GRPC_ARG_INTEGER: {
+          char *tmp;
+          gpr_asprintf(&tmp, "%d", channel_args->args[i].value.integer);
+          gpr_strvec_add(&v, tmp);
+          break;
+        }
+        case GRPC_ARG_STRING:
+          gpr_strvec_add(&v, gpr_strdup(channel_args->args[i].value.string));
+          break;
+        case GRPC_ARG_POINTER: {
+          char *tmp;
+          gpr_asprintf(&tmp, "%p", channel_args->args[i].value.pointer.p);
+          gpr_strvec_add(&v, tmp);
+          break;
+        }
+      }
+    }
+    gpr_strvec_add(&v, gpr_strdup("}"));
+    char *args_str = gpr_strvec_flatten(&v, NULL);
+    gpr_strvec_destroy(&v);
+
+    gpr_log(file, line, GPR_LOG_SEVERITY_ERROR,
+            "**************************************************");
+    gpr_log(file, line, GPR_LOG_SEVERITY_ERROR,
+            "FAILED transport=%s; stack_type=%s; channel_args=%s:",
+            transport_name, grpc_channel_stack_type_string(channel_stack_type),
+            args_str);
+    gpr_log(file, line, GPR_LOG_SEVERITY_ERROR, "EXPECTED: %s", expect);
+    gpr_log(file, line, GPR_LOG_SEVERITY_ERROR, "GOT:      %s", got);
+    result = 1;
+
+    gpr_free(args_str);
+  }
+
+  gpr_free(got);
+  gpr_free(expect);
+
+  {
+    grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+    grpc_channel_stack_builder_destroy(&exec_ctx, builder);
+    grpc_channel_args_destroy(&exec_ctx, channel_args);
+    grpc_exec_ctx_finish(&exec_ctx);
+  }
+
+  return result;
+}
diff --git a/test/core/client_channel/lb_policies_test.c b/test/core/client_channel/lb_policies_test.c
index e03492f..3c8e6dd 100644
--- a/test/core/client_channel/lb_policies_test.c
+++ b/test/core/client_channel/lb_policies_test.c
@@ -59,6 +59,7 @@
   grpc_server **servers;
   grpc_call **server_calls;
   grpc_completion_queue *cq;
+  grpc_completion_queue *shutdown_cq;
   char **servers_hostports;
   grpc_metadata_array *request_metadata_recv;
 } servers_fixture;
@@ -146,10 +147,10 @@
 static void kill_server(const servers_fixture *f, size_t i) {
   gpr_log(GPR_INFO, "KILLING SERVER %" PRIuPTR, i);
   GPR_ASSERT(f->servers[i] != NULL);
-  grpc_server_shutdown_and_notify(f->servers[i], f->cq, tag(10000));
-  GPR_ASSERT(
-      grpc_completion_queue_pluck(f->cq, tag(10000), n_millis_time(5000), NULL)
-          .type == GRPC_OP_COMPLETE);
+  grpc_server_shutdown_and_notify(f->servers[i], f->shutdown_cq, tag(10000));
+  GPR_ASSERT(grpc_completion_queue_pluck(f->shutdown_cq, tag(10000),
+                                         n_millis_time(5000), NULL)
+                 .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->servers[i]);
   f->servers[i] = NULL;
 }
@@ -196,7 +197,8 @@
   /* Create servers. */
   f->servers = gpr_malloc(sizeof(grpc_server *) * num_servers);
   f->servers_hostports = gpr_malloc(sizeof(char *) * num_servers);
-  f->cq = grpc_completion_queue_create(NULL);
+  f->cq = grpc_completion_queue_create_for_next(NULL);
+  f->shutdown_cq = grpc_completion_queue_create_for_pluck(NULL);
   for (i = 0; i < num_servers; i++) {
     grpc_metadata_array_init(&f->request_metadata_recv[i]);
     gpr_join_host_port(&f->servers_hostports[i], server_host,
@@ -212,8 +214,8 @@
   /* Destroy server. */
   for (i = 0; i < f->num_servers; i++) {
     if (f->servers[i] == NULL) continue;
-    grpc_server_shutdown_and_notify(f->servers[i], f->cq, tag(10000));
-    GPR_ASSERT(grpc_completion_queue_pluck(f->cq, tag(10000),
+    grpc_server_shutdown_and_notify(f->servers[i], f->shutdown_cq, tag(10000));
+    GPR_ASSERT(grpc_completion_queue_pluck(f->shutdown_cq, tag(10000),
                                            n_millis_time(5000), NULL)
                    .type == GRPC_OP_COMPLETE);
     grpc_server_destroy(f->servers[i]);
@@ -221,6 +223,7 @@
   grpc_completion_queue_shutdown(f->cq);
   drain_cq(f->cq);
   grpc_completion_queue_destroy(f->cq);
+  grpc_completion_queue_destroy(f->shutdown_cq);
 
   gpr_free(f->servers);
 
diff --git a/test/core/client_channel/parse_address_test.c b/test/core/client_channel/parse_address_test.c
index 629cdb0..802e41e 100644
--- a/test/core/client_channel/parse_address_test.c
+++ b/test/core/client_channel/parse_address_test.c
@@ -47,12 +47,12 @@
 
 #ifdef GRPC_HAVE_UNIX_SOCKET
 
-static void test_parse_unix(const char *uri_text, const char *pathname) {
+static void test_grpc_parse_unix(const char *uri_text, const char *pathname) {
   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
   grpc_uri *uri = grpc_uri_parse(&exec_ctx, uri_text, 0);
   grpc_resolved_address addr;
 
-  GPR_ASSERT(1 == parse_unix(uri, &addr));
+  GPR_ASSERT(1 == grpc_parse_unix(uri, &addr));
   struct sockaddr_un *addr_un = (struct sockaddr_un *)addr.addr;
   GPR_ASSERT(AF_UNIX == addr_un->sun_family);
   GPR_ASSERT(0 == strcmp(addr_un->sun_path, pathname));
@@ -63,18 +63,18 @@
 
 #else /* GRPC_HAVE_UNIX_SOCKET */
 
-static void test_parse_unix(const char *uri_text, const char *pathname) {}
+static void test_grpc_parse_unix(const char *uri_text, const char *pathname) {}
 
 #endif /* GRPC_HAVE_UNIX_SOCKET */
 
-static void test_parse_ipv4(const char *uri_text, const char *host,
-                            unsigned short port) {
+static void test_grpc_parse_ipv4(const char *uri_text, const char *host,
+                                 unsigned short port) {
   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
   grpc_uri *uri = grpc_uri_parse(&exec_ctx, uri_text, 0);
   grpc_resolved_address addr;
   char ntop_buf[INET_ADDRSTRLEN];
 
-  GPR_ASSERT(1 == parse_ipv4(uri, &addr));
+  GPR_ASSERT(1 == grpc_parse_ipv4(uri, &addr));
   struct sockaddr_in *addr_in = (struct sockaddr_in *)addr.addr;
   GPR_ASSERT(AF_INET == addr_in->sin_family);
   GPR_ASSERT(NULL != grpc_inet_ntop(AF_INET, &addr_in->sin_addr, ntop_buf,
@@ -86,14 +86,14 @@
   grpc_exec_ctx_finish(&exec_ctx);
 }
 
-static void test_parse_ipv6(const char *uri_text, const char *host,
-                            unsigned short port, uint32_t scope_id) {
+static void test_grpc_parse_ipv6(const char *uri_text, const char *host,
+                                 unsigned short port, uint32_t scope_id) {
   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
   grpc_uri *uri = grpc_uri_parse(&exec_ctx, uri_text, 0);
   grpc_resolved_address addr;
   char ntop_buf[INET6_ADDRSTRLEN];
 
-  GPR_ASSERT(1 == parse_ipv6(uri, &addr));
+  GPR_ASSERT(1 == grpc_parse_ipv6(uri, &addr));
   struct sockaddr_in6 *addr_in6 = (struct sockaddr_in6 *)addr.addr;
   GPR_ASSERT(AF_INET6 == addr_in6->sin6_family);
   GPR_ASSERT(NULL != grpc_inet_ntop(AF_INET6, &addr_in6->sin6_addr, ntop_buf,
@@ -109,8 +109,8 @@
 int main(int argc, char **argv) {
   grpc_test_init(argc, argv);
 
-  test_parse_unix("unix:/path/name", "/path/name");
-  test_parse_ipv4("ipv4:192.0.2.1:12345", "192.0.2.1", 12345);
-  test_parse_ipv6("ipv6:[2001:db8::1]:12345", "2001:db8::1", 12345, 0);
-  test_parse_ipv6("ipv6:[2001:db8::1%252]:12345", "2001:db8::1", 12345, 2);
+  test_grpc_parse_unix("unix:/path/name", "/path/name");
+  test_grpc_parse_ipv4("ipv4:192.0.2.1:12345", "192.0.2.1", 12345);
+  test_grpc_parse_ipv6("ipv6:[2001:db8::1]:12345", "2001:db8::1", 12345, 0);
+  test_grpc_parse_ipv6("ipv6:[2001:db8::1%252]:12345", "2001:db8::1", 12345, 2);
 }
diff --git a/test/core/client_channel/resolvers/BUILD b/test/core/client_channel/resolvers/BUILD
index af37072..e8361cd 100644
--- a/test/core/client_channel/resolvers/BUILD
+++ b/test/core/client_channel/resolvers/BUILD
@@ -32,20 +32,48 @@
 cc_test(
     name = "dns_resolver_connectivity_test",
     srcs = ["dns_resolver_connectivity_test.c"],
-    deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util"],
-    copts = ['-std=c99']
+    copts = ["-std=c99"],
+    deps = [
+        "//:gpr",
+        "//:grpc",
+        "//test/core/util:gpr_test_util",
+        "//test/core/util:grpc_test_util",
+    ],
 )
 
 cc_test(
     name = "dns_resolver_test",
     srcs = ["dns_resolver_test.c"],
-    deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util"],
-    copts = ['-std=c99']
+    copts = ["-std=c99"],
+    deps = [
+        "//:gpr",
+        "//:grpc",
+        "//test/core/util:gpr_test_util",
+        "//test/core/util:grpc_test_util",
+    ],
 )
 
 cc_test(
     name = "sockaddr_resolver_test",
     srcs = ["sockaddr_resolver_test.c"],
-    deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util"],
-    copts = ['-std=c99']
+    copts = ["-std=c99"],
+    deps = [
+        "//:gpr",
+        "//:grpc",
+        "//test/core/util:gpr_test_util",
+        "//test/core/util:grpc_test_util",
+    ],
+)
+
+cc_test(
+    name = "fake_resolver_test",
+    srcs = ["fake_resolver_test.c"],
+    copts = ["-std=c99"],
+    deps = [
+        "//:gpr",
+        "//:grpc",
+        "//test/core/end2end:fake_resolver",
+        "//test/core/util:gpr_test_util",
+        "//test/core/util:grpc_test_util",
+    ],
 )
diff --git a/test/core/client_channel/resolvers/fake_resolver_test.c b/test/core/client_channel/resolvers/fake_resolver_test.c
new file mode 100644
index 0000000..861918f
--- /dev/null
+++ b/test/core/client_channel/resolvers/fake_resolver_test.c
@@ -0,0 +1,187 @@
+/*
+ *
+ * Copyright 2017, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
+
+#include "src/core/ext/filters/client_channel/lb_policy_factory.h"
+#include "src/core/ext/filters/client_channel/parse_address.h"
+#include "src/core/ext/filters/client_channel/resolver_registry.h"
+#include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/iomgr/combiner.h"
+#include "src/core/lib/security/credentials/fake/fake_credentials.h"
+
+#include "test/core/end2end/fake_resolver.h"
+#include "test/core/util/test_config.h"
+
+static grpc_resolver *build_fake_resolver(
+    grpc_exec_ctx *exec_ctx, grpc_combiner *combiner,
+    grpc_fake_resolver_response_generator *response_generator) {
+  grpc_resolver_factory *factory = grpc_resolver_factory_lookup("test");
+  grpc_arg generator_arg =
+      grpc_fake_resolver_response_generator_arg(response_generator);
+  grpc_resolver_args args;
+  memset(&args, 0, sizeof(args));
+  grpc_channel_args channel_args = {1, &generator_arg};
+  args.args = &channel_args;
+  args.combiner = combiner;
+  grpc_resolver *resolver =
+      grpc_resolver_factory_create_resolver(exec_ctx, factory, &args);
+  grpc_resolver_factory_unref(factory);
+  return resolver;
+}
+
+typedef struct on_resolution_arg {
+  grpc_channel_args *resolver_result;
+  grpc_channel_args *expected_resolver_result;
+  bool was_called;
+} on_resolution_arg;
+
+void on_resolution_cb(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
+  on_resolution_arg *res = arg;
+  res->was_called = true;
+  // We only check the addresses channel arg because that's the only one
+  // explicitly set by the test via
+  // grpc_fake_resolver_response_generator_set_response.
+  const grpc_lb_addresses *actual_lb_addresses =
+      grpc_lb_addresses_find_channel_arg(res->resolver_result);
+  const grpc_lb_addresses *expected_lb_addresses =
+      grpc_lb_addresses_find_channel_arg(res->expected_resolver_result);
+  GPR_ASSERT(
+      grpc_lb_addresses_cmp(actual_lb_addresses, expected_lb_addresses) == 0);
+  grpc_channel_args_destroy(exec_ctx, res->resolver_result);
+  grpc_channel_args_destroy(exec_ctx, res->expected_resolver_result);
+}
+
+static void test_fake_resolver() {
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+  grpc_combiner *combiner = grpc_combiner_create(NULL);
+  // Create resolver.
+  grpc_fake_resolver_response_generator *response_generator =
+      grpc_fake_resolver_response_generator_create();
+  grpc_resolver *resolver =
+      build_fake_resolver(&exec_ctx, combiner, response_generator);
+  GPR_ASSERT(resolver != NULL);
+
+  // Setup expectations.
+  grpc_uri *uris[] = {grpc_uri_parse(&exec_ctx, "ipv4:10.2.1.1:1234", true),
+                      grpc_uri_parse(&exec_ctx, "ipv4:127.0.0.1:4321", true)};
+  char *balancer_names[] = {"name1", "name2"};
+  const bool is_balancer[] = {true, false};
+  grpc_lb_addresses *addresses = grpc_lb_addresses_create(3, NULL);
+  for (size_t i = 0; i < GPR_ARRAY_SIZE(uris); ++i) {
+    grpc_lb_addresses_set_address_from_uri(
+        addresses, i, uris[i], is_balancer[i], balancer_names[i], NULL);
+    grpc_uri_destroy(uris[i]);
+  }
+  const grpc_arg addresses_arg =
+      grpc_lb_addresses_create_channel_arg(addresses);
+  grpc_channel_args *results =
+      grpc_channel_args_copy_and_add(NULL, &addresses_arg, 1);
+  grpc_lb_addresses_destroy(&exec_ctx, addresses);
+  on_resolution_arg on_res_arg;
+  memset(&on_res_arg, 0, sizeof(on_res_arg));
+  on_res_arg.expected_resolver_result = results;
+  grpc_closure *on_resolution = grpc_closure_create(
+      on_resolution_cb, &on_res_arg, grpc_combiner_scheduler(combiner, false));
+
+  // Set resolver results and trigger first resolution. on_resolution_cb
+  // performs the checks.
+  grpc_fake_resolver_response_generator_set_response(
+      &exec_ctx, response_generator, results);
+  grpc_resolver_next_locked(&exec_ctx, resolver, &on_res_arg.resolver_result,
+                            on_resolution);
+  grpc_exec_ctx_flush(&exec_ctx);
+  GPR_ASSERT(on_res_arg.was_called);
+
+  // Setup update.
+  grpc_uri *uris_update[] = {
+      grpc_uri_parse(&exec_ctx, "ipv4:192.168.1.0:31416", true)};
+  char *balancer_names_update[] = {"name3"};
+  const bool is_balancer_update[] = {false};
+  grpc_lb_addresses *addresses_update = grpc_lb_addresses_create(1, NULL);
+  for (size_t i = 0; i < GPR_ARRAY_SIZE(uris_update); ++i) {
+    grpc_lb_addresses_set_address_from_uri(addresses_update, i, uris_update[i],
+                                           is_balancer_update[i],
+                                           balancer_names_update[i], NULL);
+    grpc_uri_destroy(uris_update[i]);
+  }
+
+  grpc_arg addresses_update_arg =
+      grpc_lb_addresses_create_channel_arg(addresses_update);
+  grpc_channel_args *results_update =
+      grpc_channel_args_copy_and_add(NULL, &addresses_update_arg, 1);
+  grpc_lb_addresses_destroy(&exec_ctx, addresses_update);
+
+  // Setup expectations for the update.
+  on_resolution_arg on_res_arg_update;
+  memset(&on_res_arg_update, 0, sizeof(on_res_arg_update));
+  on_res_arg_update.expected_resolver_result = results_update;
+  on_resolution = grpc_closure_create(on_resolution_cb, &on_res_arg_update,
+                                      grpc_combiner_scheduler(combiner, false));
+
+  // Set updated resolver results and trigger a second resolution.
+  grpc_fake_resolver_response_generator_set_response(
+      &exec_ctx, response_generator, results_update);
+  grpc_resolver_next_locked(&exec_ctx, resolver,
+                            &on_res_arg_update.resolver_result, on_resolution);
+  grpc_exec_ctx_flush(&exec_ctx);
+  GPR_ASSERT(on_res_arg.was_called);
+
+  // Requesting a new resolution without re-senting the response shouldn't
+  // trigger the resolution callback.
+  memset(&on_res_arg, 0, sizeof(on_res_arg));
+  grpc_resolver_next_locked(&exec_ctx, resolver, &on_res_arg.resolver_result,
+                            on_resolution);
+  grpc_exec_ctx_flush(&exec_ctx);
+  GPR_ASSERT(!on_res_arg.was_called);
+
+  GRPC_COMBINER_UNREF(&exec_ctx, combiner, "test_fake_resolver");
+  GRPC_RESOLVER_UNREF(&exec_ctx, resolver, "test_fake_resolver");
+  grpc_exec_ctx_finish(&exec_ctx);
+  grpc_fake_resolver_response_generator_unref(response_generator);
+}
+
+int main(int argc, char **argv) {
+  grpc_test_init(argc, argv);
+  grpc_fake_resolver_init();  // Registers the "test" scheme.
+  grpc_init();
+
+  test_fake_resolver();
+
+  grpc_shutdown();
+  return 0;
+}
diff --git a/test/core/end2end/BUILD b/test/core/end2end/BUILD
index 0cef7aa..ffea1cc 100644
--- a/test/core/end2end/BUILD
+++ b/test/core/end2end/BUILD
@@ -32,49 +32,66 @@
 load(":generate_tests.bzl", "grpc_end2end_tests")
 
 cc_library(
-  name = 'cq_verifier',
-  srcs = ['cq_verifier.c'],
-  hdrs = ['cq_verifier.h'],
-  deps = ['//:gpr', '//:grpc', '//test/core/util:grpc_test_util'],
-  copts = ['-std=c99'],
-  visibility = ["//test:__subpackages__"],
+    name = "cq_verifier",
+    srcs = ["cq_verifier.c"],
+    hdrs = ["cq_verifier.h"],
+    copts = ["-std=c99"],
+    visibility = ["//test:__subpackages__"],
+    deps = [
+        "//:gpr",
+        "//:grpc",
+        "//test/core/util:grpc_test_util",
+    ],
 )
 
 cc_library(
-  name = 'ssl_test_data',
-  visibility = ["//test:__subpackages__"],
-  hdrs = ['data/ssl_test_data.h'],
-  copts = ['-std=c99'],
-  srcs = [
-    "data/client_certs.c",
-    "data/server1_cert.c",
-    "data/server1_key.c",
-    "data/test_root_cert.c",
-  ]
+    name = "ssl_test_data",
+    srcs = [
+        "data/client_certs.c",
+        "data/server1_cert.c",
+        "data/server1_key.c",
+        "data/test_root_cert.c",
+    ],
+    hdrs = ["data/ssl_test_data.h"],
+    copts = ["-std=c99"],
+    visibility = ["//test:__subpackages__"],
 )
 
 cc_library(
-  name = 'fake_resolver',
-  hdrs = ['fake_resolver.h'],
-  srcs = ['fake_resolver.c'],
-  copts = ['-std=c99'],
-  deps = ['//:gpr', '//:grpc', '//test/core/util:grpc_test_util']
+    name = "fake_resolver",
+    srcs = ["fake_resolver.c"],
+    hdrs = ["fake_resolver.h"],
+    copts = ["-std=c99"],
+    visibility = ["//test:__subpackages__"],
+    deps = [
+        "//:gpr",
+        "//:grpc",
+        "//test/core/util:grpc_test_util",
+    ],
 )
 
 cc_library(
-  name = 'http_proxy',
-  hdrs = ['fixtures/http_proxy_fixture.h'],
-  srcs = ['fixtures/http_proxy_fixture.c'],
-  copts = ['-std=c99'],
-  deps = ['//:gpr', '//:grpc', '//test/core/util:grpc_test_util']
+    name = "http_proxy",
+    srcs = ["fixtures/http_proxy_fixture.c"],
+    hdrs = ["fixtures/http_proxy_fixture.h"],
+    copts = ["-std=c99"],
+    deps = [
+        "//:gpr",
+        "//:grpc",
+        "//test/core/util:grpc_test_util",
+    ],
 )
 
 cc_library(
-  name = 'proxy',
-  hdrs = ['fixtures/proxy.h'],
-  srcs = ['fixtures/proxy.c'],
-  copts = ['-std=c99'],
-  deps = ['//:gpr', '//:grpc', '//test/core/util:grpc_test_util']
+    name = "proxy",
+    srcs = ["fixtures/proxy.c"],
+    hdrs = ["fixtures/proxy.h"],
+    copts = ["-std=c99"],
+    deps = [
+        "//:gpr",
+        "//:grpc",
+        "//test/core/util:grpc_test_util",
+    ],
 )
 
 grpc_end2end_tests()
diff --git a/test/core/end2end/bad_server_response_test.c b/test/core/end2end/bad_server_response_test.c
index c37a292..1537caf 100644
--- a/test/core/end2end/bad_server_response_test.c
+++ b/test/core/end2end/bad_server_response_test.c
@@ -178,7 +178,7 @@
   cq_verifier *cqv;
   grpc_slice details;
 
-  state.cq = grpc_completion_queue_create(NULL);
+  state.cq = grpc_completion_queue_create_for_next(NULL);
   cqv = cq_verifier_create(state.cq);
   gpr_join_host_port(&state.target, "127.0.0.1", target_port);
   state.channel = grpc_insecure_channel_create(state.target, NULL, NULL);
diff --git a/test/core/end2end/connection_refused_test.c b/test/core/end2end/connection_refused_test.c
index 6ded12a..7fecadb 100644
--- a/test/core/end2end/connection_refused_test.c
+++ b/test/core/end2end/connection_refused_test.c
@@ -68,7 +68,7 @@
 
   grpc_metadata_array_init(&trailing_metadata_recv);
 
-  cq = grpc_completion_queue_create(NULL);
+  cq = grpc_completion_queue_create_for_next(NULL);
   cqv = cq_verifier_create(cq);
 
   /* if using service config, create channel args */
diff --git a/test/core/end2end/dualstack_socket_test.c b/test/core/end2end/dualstack_socket_test.c
index 3623bd7..c61ea6d 100644
--- a/test/core/end2end/dualstack_socket_test.c
+++ b/test/core/end2end/dualstack_socket_test.c
@@ -76,6 +76,7 @@
   grpc_channel *client;
   grpc_server *server;
   grpc_completion_queue *cq;
+  grpc_completion_queue *shutdown_cq;
   grpc_call *c;
   grpc_call *s;
   cq_verifier *cqv;
@@ -107,7 +108,7 @@
   grpc_call_details_init(&call_details);
 
   /* Create server. */
-  cq = grpc_completion_queue_create(NULL);
+  cq = grpc_completion_queue_create_for_next(NULL);
   server = grpc_server_create(NULL, NULL);
   grpc_server_register_completion_queue(server, cq, NULL);
   GPR_ASSERT((got_port = grpc_server_add_insecure_http2_port(
@@ -259,11 +260,14 @@
   grpc_channel_destroy(client);
 
   /* Destroy server. */
-  grpc_server_shutdown_and_notify(server, cq, tag(1000));
-  GPR_ASSERT(grpc_completion_queue_pluck(
-                 cq, tag(1000), grpc_timeout_seconds_to_deadline(5), NULL)
+  shutdown_cq = grpc_completion_queue_create_for_pluck(NULL);
+  grpc_server_shutdown_and_notify(server, shutdown_cq, tag(1000));
+  GPR_ASSERT(grpc_completion_queue_pluck(shutdown_cq, tag(1000),
+                                         grpc_timeout_seconds_to_deadline(5),
+                                         NULL)
                  .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(server);
+  grpc_completion_queue_destroy(shutdown_cq);
   grpc_completion_queue_shutdown(cq);
   drain_cq(cq);
   grpc_completion_queue_destroy(cq);
diff --git a/test/core/end2end/end2end_tests.h b/test/core/end2end/end2end_tests.h
index cdb26a6..4d98bdd 100644
--- a/test/core/end2end/end2end_tests.h
+++ b/test/core/end2end/end2end_tests.h
@@ -53,6 +53,7 @@
 
 struct grpc_end2end_test_fixture {
   grpc_completion_queue *cq;
+  grpc_completion_queue *shutdown_cq;
   grpc_server *server;
   grpc_channel *client;
   void *fixture_data;
diff --git a/test/core/end2end/fake_resolver.c b/test/core/end2end/fake_resolver.c
index 1c7dd13..6a71c20 100644
--- a/test/core/end2end/fake_resolver.c
+++ b/test/core/end2end/fake_resolver.c
@@ -32,6 +32,7 @@
 // This is similar to the sockaddr resolver, except that it supports a
 // bunch of query args that are useful for dependency injection in tests.
 
+#include <limits.h>
 #include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -46,12 +47,18 @@
 #include "src/core/ext/filters/client_channel/parse_address.h"
 #include "src/core/ext/filters/client_channel/resolver_registry.h"
 #include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/iomgr/combiner.h"
 #include "src/core/lib/iomgr/resolve_address.h"
 #include "src/core/lib/iomgr/unix_sockets_posix.h"
 #include "src/core/lib/slice/slice_internal.h"
 #include "src/core/lib/slice/slice_string_helpers.h"
 #include "src/core/lib/support/string.h"
 
+#include "test/core/end2end/fake_resolver.h"
+
+#define GRPC_ARG_FAKE_RESOLVER_RESPONSE_GENERATOR \
+  "grpc.fake_resolver.response_generator"
+
 //
 // fake_resolver
 //
@@ -62,12 +69,11 @@
 
   // passed-in parameters
   grpc_channel_args* channel_args;
-  grpc_lb_addresses* addresses;
 
-  // mutex guarding the rest of the state
-  gpr_mu mu;
-  // have we published?
-  bool published;
+  // If not NULL, the next set of resolution results to be returned to
+  // grpc_resolver_next_locked()'s closure.
+  grpc_channel_args* next_results;
+
   // pending next completion, or NULL
   grpc_closure* next_completion;
   // target result address for next completion
@@ -76,60 +82,137 @@
 
 static void fake_resolver_destroy(grpc_exec_ctx* exec_ctx, grpc_resolver* gr) {
   fake_resolver* r = (fake_resolver*)gr;
-  gpr_mu_destroy(&r->mu);
+  grpc_channel_args_destroy(exec_ctx, r->next_results);
   grpc_channel_args_destroy(exec_ctx, r->channel_args);
-  grpc_lb_addresses_destroy(exec_ctx, r->addresses);
   gpr_free(r);
 }
 
-static void fake_resolver_shutdown(grpc_exec_ctx* exec_ctx,
-                                   grpc_resolver* resolver) {
+static void fake_resolver_shutdown_locked(grpc_exec_ctx* exec_ctx,
+                                          grpc_resolver* resolver) {
   fake_resolver* r = (fake_resolver*)resolver;
-  gpr_mu_lock(&r->mu);
   if (r->next_completion != NULL) {
     *r->target_result = NULL;
     grpc_closure_sched(exec_ctx, r->next_completion, GRPC_ERROR_NONE);
     r->next_completion = NULL;
   }
-  gpr_mu_unlock(&r->mu);
 }
 
 static void fake_resolver_maybe_finish_next_locked(grpc_exec_ctx* exec_ctx,
                                                    fake_resolver* r) {
-  if (r->next_completion != NULL && !r->published) {
-    r->published = true;
-    grpc_arg arg = grpc_lb_addresses_create_channel_arg(r->addresses);
+  if (r->next_completion != NULL && r->next_results != NULL) {
     *r->target_result =
-        grpc_channel_args_copy_and_add(r->channel_args, &arg, 1);
+        grpc_channel_args_merge(r->channel_args, r->next_results);
+    grpc_channel_args_destroy(exec_ctx, r->next_results);
     grpc_closure_sched(exec_ctx, r->next_completion, GRPC_ERROR_NONE);
     r->next_completion = NULL;
+    r->next_results = NULL;
   }
 }
 
-static void fake_resolver_channel_saw_error(grpc_exec_ctx* exec_ctx,
-                                            grpc_resolver* resolver) {
+static void fake_resolver_channel_saw_error_locked(grpc_exec_ctx* exec_ctx,
+                                                   grpc_resolver* resolver) {
   fake_resolver* r = (fake_resolver*)resolver;
-  gpr_mu_lock(&r->mu);
-  r->published = false;
   fake_resolver_maybe_finish_next_locked(exec_ctx, r);
-  gpr_mu_unlock(&r->mu);
 }
 
-static void fake_resolver_next(grpc_exec_ctx* exec_ctx, grpc_resolver* resolver,
-                               grpc_channel_args** target_result,
-                               grpc_closure* on_complete) {
+static void fake_resolver_next_locked(grpc_exec_ctx* exec_ctx,
+                                      grpc_resolver* resolver,
+                                      grpc_channel_args** target_result,
+                                      grpc_closure* on_complete) {
   fake_resolver* r = (fake_resolver*)resolver;
-  gpr_mu_lock(&r->mu);
   GPR_ASSERT(!r->next_completion);
   r->next_completion = on_complete;
   r->target_result = target_result;
   fake_resolver_maybe_finish_next_locked(exec_ctx, r);
-  gpr_mu_unlock(&r->mu);
 }
 
 static const grpc_resolver_vtable fake_resolver_vtable = {
-    fake_resolver_destroy, fake_resolver_shutdown,
-    fake_resolver_channel_saw_error, fake_resolver_next};
+    fake_resolver_destroy, fake_resolver_shutdown_locked,
+    fake_resolver_channel_saw_error_locked, fake_resolver_next_locked};
+
+struct grpc_fake_resolver_response_generator {
+  fake_resolver* resolver;  // Set by the fake_resolver constructor to itself.
+  grpc_channel_args* next_response;
+  gpr_refcount refcount;
+};
+
+grpc_fake_resolver_response_generator*
+grpc_fake_resolver_response_generator_create() {
+  grpc_fake_resolver_response_generator* generator =
+      gpr_zalloc(sizeof(*generator));
+  gpr_ref_init(&generator->refcount, 1);
+  return generator;
+}
+
+grpc_fake_resolver_response_generator*
+grpc_fake_resolver_response_generator_ref(
+    grpc_fake_resolver_response_generator* generator) {
+  gpr_ref(&generator->refcount);
+  return generator;
+}
+
+void grpc_fake_resolver_response_generator_unref(
+    grpc_fake_resolver_response_generator* generator) {
+  if (gpr_unref(&generator->refcount)) {
+    gpr_free(generator);
+  }
+}
+
+static void set_response_cb(grpc_exec_ctx* exec_ctx, void* arg,
+                            grpc_error* error) {
+  grpc_fake_resolver_response_generator* generator = arg;
+  fake_resolver* r = generator->resolver;
+  if (r->next_results != NULL) {
+    grpc_channel_args_destroy(exec_ctx, r->next_results);
+  }
+  r->next_results = generator->next_response;
+  fake_resolver_maybe_finish_next_locked(exec_ctx, r);
+}
+
+void grpc_fake_resolver_response_generator_set_response(
+    grpc_exec_ctx* exec_ctx, grpc_fake_resolver_response_generator* generator,
+    grpc_channel_args* next_response) {
+  GPR_ASSERT(generator->resolver != NULL);
+  generator->next_response = grpc_channel_args_copy(next_response);
+  grpc_closure_sched(
+      exec_ctx,
+      grpc_closure_create(
+          set_response_cb, generator,
+          grpc_combiner_scheduler(generator->resolver->base.combiner, false)),
+      GRPC_ERROR_NONE);
+}
+
+static void* response_generator_arg_copy(void* p) {
+  return grpc_fake_resolver_response_generator_ref(p);
+}
+
+static void response_generator_arg_destroy(grpc_exec_ctx* exec_ctx, void* p) {
+  grpc_fake_resolver_response_generator_unref(p);
+}
+
+static int response_generator_cmp(void* a, void* b) { return GPR_ICMP(a, b); }
+
+static const grpc_arg_pointer_vtable response_generator_arg_vtable = {
+    response_generator_arg_copy, response_generator_arg_destroy,
+    response_generator_cmp};
+
+grpc_arg grpc_fake_resolver_response_generator_arg(
+    grpc_fake_resolver_response_generator* generator) {
+  grpc_arg arg;
+  arg.type = GRPC_ARG_POINTER;
+  arg.key = GRPC_ARG_FAKE_RESOLVER_RESPONSE_GENERATOR;
+  arg.value.pointer.p = generator;
+  arg.value.pointer.vtable = &response_generator_arg_vtable;
+  return arg;
+}
+
+grpc_fake_resolver_response_generator*
+grpc_fake_resolver_get_response_generator(const grpc_channel_args* args) {
+  const grpc_arg* arg =
+      grpc_channel_args_find(args, GRPC_ARG_FAKE_RESOLVER_RESPONSE_GENERATOR);
+  if (arg == NULL || arg->type != GRPC_ARG_POINTER) return NULL;
+  return arg->value.pointer.p;
+}
 
 //
 // fake_resolver_factory
@@ -139,81 +222,15 @@
 
 static void fake_resolver_factory_unref(grpc_resolver_factory* factory) {}
 
-static void do_nothing(void* ignored) {}
-
 static grpc_resolver* fake_resolver_create(grpc_exec_ctx* exec_ctx,
                                            grpc_resolver_factory* factory,
                                            grpc_resolver_args* args) {
-  if (0 != strcmp(args->uri->authority, "")) {
-    gpr_log(GPR_ERROR, "authority based uri's not supported by the %s scheme",
-            args->uri->scheme);
-    return NULL;
-  }
-  // Get lb_enabled arg.  Anything other than "0" is interpreted as true.
-  const char* lb_enabled_qpart =
-      grpc_uri_get_query_arg(args->uri, "lb_enabled");
-  const bool lb_enabled =
-      lb_enabled_qpart != NULL && strcmp("0", lb_enabled_qpart) != 0;
-
-  // Get the balancer's names.
-  const char* balancer_names =
-      grpc_uri_get_query_arg(args->uri, "balancer_names");
-  grpc_slice_buffer balancer_names_parts;
-  grpc_slice_buffer_init(&balancer_names_parts);
-  if (balancer_names != NULL) {
-    const grpc_slice balancer_names_slice =
-        grpc_slice_from_copied_string(balancer_names);
-    grpc_slice_split(balancer_names_slice, ",", &balancer_names_parts);
-    grpc_slice_unref(balancer_names_slice);
-  }
-
-  // Construct addresses.
-  grpc_slice path_slice =
-      grpc_slice_new(args->uri->path, strlen(args->uri->path), do_nothing);
-  grpc_slice_buffer path_parts;
-  grpc_slice_buffer_init(&path_parts);
-  grpc_slice_split(path_slice, ",", &path_parts);
-  if (balancer_names_parts.count > 0 &&
-      path_parts.count != balancer_names_parts.count) {
-    gpr_log(GPR_ERROR,
-            "Balancer names present but mismatched with number of addresses: "
-            "%lu balancer names != %lu addresses",
-            (unsigned long)balancer_names_parts.count,
-            (unsigned long)path_parts.count);
-    return NULL;
-  }
-  grpc_lb_addresses* addresses =
-      grpc_lb_addresses_create(path_parts.count, NULL /* user_data_vtable */);
-  bool errors_found = false;
-  for (size_t i = 0; i < addresses->num_addresses; i++) {
-    grpc_uri ith_uri = *args->uri;
-    char* part_str = grpc_slice_to_c_string(path_parts.slices[i]);
-    ith_uri.path = part_str;
-    if (!parse_ipv4(&ith_uri, &addresses->addresses[i].address)) {
-      errors_found = true;
-    }
-    gpr_free(part_str);
-    if (errors_found) break;
-    addresses->addresses[i].is_balancer = lb_enabled;
-    addresses->addresses[i].balancer_name =
-        balancer_names_parts.count > 0
-            ? grpc_dump_slice(balancer_names_parts.slices[i], GPR_DUMP_ASCII)
-            : NULL;
-  }
-  grpc_slice_buffer_destroy_internal(exec_ctx, &path_parts);
-  grpc_slice_buffer_destroy_internal(exec_ctx, &balancer_names_parts);
-  grpc_slice_unref(path_slice);
-  if (errors_found) {
-    grpc_lb_addresses_destroy(exec_ctx, addresses);
-    return NULL;
-  }
-  // Instantiate resolver.
-  fake_resolver* r = gpr_malloc(sizeof(fake_resolver));
-  memset(r, 0, sizeof(*r));
+  fake_resolver* r = gpr_zalloc(sizeof(*r));
   r->channel_args = grpc_channel_args_copy(args->args);
-  r->addresses = addresses;
-  gpr_mu_init(&r->mu);
   grpc_resolver_init(&r->base, &fake_resolver_vtable, args->combiner);
+  grpc_fake_resolver_response_generator* response_generator =
+      grpc_fake_resolver_get_response_generator(args->args);
+  if (response_generator != NULL) response_generator->resolver = r;
   return &r->base;
 }
 
diff --git a/test/core/end2end/fake_resolver.h b/test/core/end2end/fake_resolver.h
index 7a30347..447289a 100644
--- a/test/core/end2end/fake_resolver.h
+++ b/test/core/end2end/fake_resolver.h
@@ -32,8 +32,42 @@
 #ifndef GRPC_TEST_CORE_END2END_FAKE_RESOLVER_H
 #define GRPC_TEST_CORE_END2END_FAKE_RESOLVER_H
 
+#include "src/core/ext/filters/client_channel/lb_policy_factory.h"
+#include "src/core/ext/filters/client_channel/uri_parser.h"
+#include "src/core/lib/channel/channel_args.h"
+
 #include "test/core/util/test_config.h"
 
 void grpc_fake_resolver_init();
 
+// Instances of \a grpc_fake_resolver_response_generator are passed to the
+// fake resolver in a channel argument (see \a
+// grpc_fake_resolver_response_generator_arg) in order to inject and trigger
+// custom resolutions. See also \a
+// grpc_fake_resolver_response_generator_set_response.
+typedef struct grpc_fake_resolver_response_generator
+    grpc_fake_resolver_response_generator;
+grpc_fake_resolver_response_generator*
+grpc_fake_resolver_response_generator_create();
+
+// Instruct the fake resolver associated with the \a response_generator instance
+// to trigger a new resolution for \a uri and \a args.
+void grpc_fake_resolver_response_generator_set_response(
+    grpc_exec_ctx* exec_ctx, grpc_fake_resolver_response_generator* generator,
+    grpc_channel_args* next_response);
+
+// Return a \a grpc_arg for a \a grpc_fake_resolver_response_generator instance.
+grpc_arg grpc_fake_resolver_response_generator_arg(
+    grpc_fake_resolver_response_generator* generator);
+// Return the \a grpc_fake_resolver_response_generator instance in \a args or
+// NULL.
+grpc_fake_resolver_response_generator*
+grpc_fake_resolver_get_response_generator(const grpc_channel_args* args);
+
+grpc_fake_resolver_response_generator*
+grpc_fake_resolver_response_generator_ref(
+    grpc_fake_resolver_response_generator* generator);
+void grpc_fake_resolver_response_generator_unref(
+    grpc_fake_resolver_response_generator* generator);
+
 #endif /* GRPC_TEST_CORE_END2END_FAKE_RESOLVER_H */
diff --git a/test/core/end2end/fixtures/h2_census.c b/test/core/end2end/fixtures/h2_census.c
index 97b27b2..e8af03a 100644
--- a/test/core/end2end/fixtures/h2_census.c
+++ b/test/core/end2end/fixtures/h2_census.c
@@ -42,10 +42,10 @@
 #include <grpc/support/thd.h>
 #include <grpc/support/useful.h>
 #include "src/core/ext/filters/client_channel/client_channel.h"
+#include "src/core/ext/filters/http/server/http_server_filter.h"
 #include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/channel/connected_channel.h"
-#include "src/core/lib/channel/http_server_filter.h"
 #include "src/core/lib/surface/channel.h"
 #include "src/core/lib/surface/server.h"
 #include "test/core/util/port.h"
@@ -65,7 +65,8 @@
   gpr_join_host_port(&ffd->localaddr, "localhost", port);
 
   f.fixture_data = ffd;
-  f.cq = grpc_completion_queue_create(NULL);
+  f.cq = grpc_completion_queue_create_for_next(NULL);
+  f.shutdown_cq = grpc_completion_queue_create_for_pluck(NULL);
 
   return f;
 }
diff --git a/test/core/end2end/fixtures/h2_compress.c b/test/core/end2end/fixtures/h2_compress.c
index 8aec94d..49fcd9e 100644
--- a/test/core/end2end/fixtures/h2_compress.c
+++ b/test/core/end2end/fixtures/h2_compress.c
@@ -42,10 +42,10 @@
 #include <grpc/support/thd.h>
 #include <grpc/support/useful.h>
 #include "src/core/ext/filters/client_channel/client_channel.h"
+#include "src/core/ext/filters/http/server/http_server_filter.h"
 #include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/channel/connected_channel.h"
-#include "src/core/lib/channel/http_server_filter.h"
 #include "src/core/lib/surface/channel.h"
 #include "src/core/lib/surface/server.h"
 #include "test/core/util/port.h"
@@ -69,7 +69,8 @@
 
   memset(&f, 0, sizeof(f));
   f.fixture_data = ffd;
-  f.cq = grpc_completion_queue_create(NULL);
+  f.cq = grpc_completion_queue_create_for_next(NULL);
+  f.shutdown_cq = grpc_completion_queue_create_for_pluck(NULL);
 
   return f;
 }
diff --git a/test/core/end2end/fixtures/h2_fakesec.c b/test/core/end2end/fixtures/h2_fakesec.c
index c974791..5969b11 100644
--- a/test/core/end2end/fixtures/h2_fakesec.c
+++ b/test/core/end2end/fixtures/h2_fakesec.c
@@ -60,7 +60,8 @@
   gpr_join_host_port(&ffd->localaddr, "localhost", port);
 
   f.fixture_data = ffd;
-  f.cq = grpc_completion_queue_create(NULL);
+  f.cq = grpc_completion_queue_create_for_next(NULL);
+  f.shutdown_cq = grpc_completion_queue_create_for_pluck(NULL);
 
   return f;
 }
diff --git a/test/core/end2end/fixtures/h2_fd.c b/test/core/end2end/fixtures/h2_fd.c
index 223fadc..53888db 100644
--- a/test/core/end2end/fixtures/h2_fd.c
+++ b/test/core/end2end/fixtures/h2_fd.c
@@ -70,7 +70,8 @@
   grpc_end2end_test_fixture f;
   memset(&f, 0, sizeof(f));
   f.fixture_data = fixture_data;
-  f.cq = grpc_completion_queue_create(NULL);
+  f.cq = grpc_completion_queue_create_for_next(NULL);
+  f.shutdown_cq = grpc_completion_queue_create_for_pluck(NULL);
 
   create_sockets(fixture_data->fd_pair);
 
diff --git a/test/core/end2end/fixtures/h2_full+pipe.c b/test/core/end2end/fixtures/h2_full+pipe.c
index 0191e59..cee48af 100644
--- a/test/core/end2end/fixtures/h2_full+pipe.c
+++ b/test/core/end2end/fixtures/h2_full+pipe.c
@@ -47,9 +47,9 @@
 #include <grpc/support/thd.h>
 #include <grpc/support/useful.h>
 #include "src/core/ext/filters/client_channel/client_channel.h"
+#include "src/core/ext/filters/http/server/http_server_filter.h"
 #include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
 #include "src/core/lib/channel/connected_channel.h"
-#include "src/core/lib/channel/http_server_filter.h"
 #include "src/core/lib/iomgr/wakeup_fd_posix.h"
 #include "src/core/lib/surface/channel.h"
 #include "src/core/lib/surface/server.h"
@@ -70,7 +70,8 @@
   gpr_join_host_port(&ffd->localaddr, "localhost", port);
 
   f.fixture_data = ffd;
-  f.cq = grpc_completion_queue_create(NULL);
+  f.cq = grpc_completion_queue_create_for_next(NULL);
+  f.shutdown_cq = grpc_completion_queue_create_for_pluck(NULL);
 
   return f;
 }
diff --git a/test/core/end2end/fixtures/h2_full+trace.c b/test/core/end2end/fixtures/h2_full+trace.c
index 9dbb27f..57047bc 100644
--- a/test/core/end2end/fixtures/h2_full+trace.c
+++ b/test/core/end2end/fixtures/h2_full+trace.c
@@ -47,9 +47,9 @@
 #include <grpc/support/thd.h>
 #include <grpc/support/useful.h>
 #include "src/core/ext/filters/client_channel/client_channel.h"
+#include "src/core/ext/filters/http/server/http_server_filter.h"
 #include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
 #include "src/core/lib/channel/connected_channel.h"
-#include "src/core/lib/channel/http_server_filter.h"
 #include "src/core/lib/support/env.h"
 #include "src/core/lib/surface/channel.h"
 #include "src/core/lib/surface/server.h"
@@ -70,7 +70,8 @@
   gpr_join_host_port(&ffd->localaddr, "localhost", port);
 
   f.fixture_data = ffd;
-  f.cq = grpc_completion_queue_create(NULL);
+  f.cq = grpc_completion_queue_create_for_next(NULL);
+  f.shutdown_cq = grpc_completion_queue_create_for_pluck(NULL);
 
   return f;
 }
diff --git a/test/core/end2end/fixtures/h2_full.c b/test/core/end2end/fixtures/h2_full.c
index 49c62b3..f18d314 100644
--- a/test/core/end2end/fixtures/h2_full.c
+++ b/test/core/end2end/fixtures/h2_full.c
@@ -42,9 +42,9 @@
 #include <grpc/support/thd.h>
 #include <grpc/support/useful.h>
 #include "src/core/ext/filters/client_channel/client_channel.h"
+#include "src/core/ext/filters/http/server/http_server_filter.h"
 #include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
 #include "src/core/lib/channel/connected_channel.h"
-#include "src/core/lib/channel/http_server_filter.h"
 #include "src/core/lib/surface/channel.h"
 #include "src/core/lib/surface/server.h"
 #include "test/core/util/port.h"
@@ -64,7 +64,8 @@
   gpr_join_host_port(&ffd->localaddr, "localhost", port);
 
   f.fixture_data = ffd;
-  f.cq = grpc_completion_queue_create(NULL);
+  f.cq = grpc_completion_queue_create_for_next(NULL);
+  f.shutdown_cq = grpc_completion_queue_create_for_pluck(NULL);
 
   return f;
 }
diff --git a/test/core/end2end/fixtures/h2_http_proxy.c b/test/core/end2end/fixtures/h2_http_proxy.c
index 62c4355..aec874b 100644
--- a/test/core/end2end/fixtures/h2_http_proxy.c
+++ b/test/core/end2end/fixtures/h2_http_proxy.c
@@ -43,9 +43,9 @@
 #include <grpc/support/thd.h>
 #include <grpc/support/useful.h>
 #include "src/core/ext/filters/client_channel/client_channel.h"
+#include "src/core/ext/filters/http/server/http_server_filter.h"
 #include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
 #include "src/core/lib/channel/connected_channel.h"
-#include "src/core/lib/channel/http_server_filter.h"
 #include "src/core/lib/support/env.h"
 #include "src/core/lib/surface/channel.h"
 #include "src/core/lib/surface/server.h"
@@ -69,7 +69,8 @@
   ffd->proxy = grpc_end2end_http_proxy_create();
 
   f.fixture_data = ffd;
-  f.cq = grpc_completion_queue_create(NULL);
+  f.cq = grpc_completion_queue_create_for_next(NULL);
+  f.shutdown_cq = grpc_completion_queue_create_for_pluck(NULL);
 
   return f;
 }
diff --git a/test/core/end2end/fixtures/h2_load_reporting.c b/test/core/end2end/fixtures/h2_load_reporting.c
index 79f26ed..8e9c885 100644
--- a/test/core/end2end/fixtures/h2_load_reporting.c
+++ b/test/core/end2end/fixtures/h2_load_reporting.c
@@ -42,11 +42,11 @@
 #include <grpc/support/thd.h>
 #include <grpc/support/useful.h>
 #include "src/core/ext/filters/client_channel/client_channel.h"
+#include "src/core/ext/filters/http/server/http_server_filter.h"
 #include "src/core/ext/filters/load_reporting/load_reporting.h"
 #include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/channel/connected_channel.h"
-#include "src/core/lib/channel/http_server_filter.h"
 #include "src/core/lib/surface/channel.h"
 #include "src/core/lib/surface/server.h"
 #include "test/core/util/port.h"
@@ -67,7 +67,8 @@
   gpr_join_host_port(&ffd->localaddr, "localhost", port);
 
   f.fixture_data = ffd;
-  f.cq = grpc_completion_queue_create(NULL);
+  f.cq = grpc_completion_queue_create_for_next(NULL);
+  f.shutdown_cq = grpc_completion_queue_create_for_pluck(NULL);
 
   return f;
 }
diff --git a/test/core/end2end/fixtures/h2_oauth2.c b/test/core/end2end/fixtures/h2_oauth2.c
index 3351652..c94f1f6 100644
--- a/test/core/end2end/fixtures/h2_oauth2.c
+++ b/test/core/end2end/fixtures/h2_oauth2.c
@@ -113,7 +113,8 @@
   gpr_join_host_port(&ffd->localaddr, "localhost", port);
 
   f.fixture_data = ffd;
-  f.cq = grpc_completion_queue_create(NULL);
+  f.cq = grpc_completion_queue_create_for_next(NULL);
+  f.shutdown_cq = grpc_completion_queue_create_for_pluck(NULL);
 
   return f;
 }
diff --git a/test/core/end2end/fixtures/h2_proxy.c b/test/core/end2end/fixtures/h2_proxy.c
index a10738f..3d33d58 100644
--- a/test/core/end2end/fixtures/h2_proxy.c
+++ b/test/core/end2end/fixtures/h2_proxy.c
@@ -42,9 +42,9 @@
 #include <grpc/support/thd.h>
 #include <grpc/support/useful.h>
 #include "src/core/ext/filters/client_channel/client_channel.h"
+#include "src/core/ext/filters/http/server/http_server_filter.h"
 #include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
 #include "src/core/lib/channel/connected_channel.h"
-#include "src/core/lib/channel/http_server_filter.h"
 #include "src/core/lib/surface/channel.h"
 #include "src/core/lib/surface/server.h"
 #include "test/core/end2end/fixtures/proxy.h"
@@ -79,7 +79,8 @@
   ffd->proxy = grpc_end2end_proxy_create(&proxy_def, client_args, server_args);
 
   f.fixture_data = ffd;
-  f.cq = grpc_completion_queue_create(NULL);
+  f.cq = grpc_completion_queue_create_for_next(NULL);
+  f.shutdown_cq = grpc_completion_queue_create_for_pluck(NULL);
 
   return f;
 }
diff --git a/test/core/end2end/fixtures/h2_sockpair+trace.c b/test/core/end2end/fixtures/h2_sockpair+trace.c
index 424241c..f3e1220 100644
--- a/test/core/end2end/fixtures/h2_sockpair+trace.c
+++ b/test/core/end2end/fixtures/h2_sockpair+trace.c
@@ -46,11 +46,11 @@
 #include <grpc/support/thd.h>
 #include <grpc/support/useful.h>
 #include "src/core/ext/filters/client_channel/client_channel.h"
+#include "src/core/ext/filters/http/client/http_client_filter.h"
+#include "src/core/ext/filters/http/message_compress/message_compress_filter.h"
+#include "src/core/ext/filters/http/server/http_server_filter.h"
 #include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
-#include "src/core/lib/channel/compress_filter.h"
 #include "src/core/lib/channel/connected_channel.h"
-#include "src/core/lib/channel/http_client_filter.h"
-#include "src/core/lib/channel/http_server_filter.h"
 #include "src/core/lib/iomgr/endpoint_pair.h"
 #include "src/core/lib/iomgr/iomgr.h"
 #include "src/core/lib/support/env.h"
@@ -94,7 +94,8 @@
   grpc_end2end_test_fixture f;
   memset(&f, 0, sizeof(f));
   f.fixture_data = sfd;
-  f.cq = grpc_completion_queue_create(NULL);
+  f.cq = grpc_completion_queue_create_for_next(NULL);
+  f.shutdown_cq = grpc_completion_queue_create_for_pluck(NULL);
 
   *sfd = grpc_iomgr_create_endpoint_pair("fixture", NULL);
 
diff --git a/test/core/end2end/fixtures/h2_sockpair.c b/test/core/end2end/fixtures/h2_sockpair.c
index fe8d766..4e60d03 100644
--- a/test/core/end2end/fixtures/h2_sockpair.c
+++ b/test/core/end2end/fixtures/h2_sockpair.c
@@ -41,11 +41,11 @@
 #include <grpc/support/thd.h>
 #include <grpc/support/useful.h>
 #include "src/core/ext/filters/client_channel/client_channel.h"
+#include "src/core/ext/filters/http/client/http_client_filter.h"
+#include "src/core/ext/filters/http/message_compress/message_compress_filter.h"
+#include "src/core/ext/filters/http/server/http_server_filter.h"
 #include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
-#include "src/core/lib/channel/compress_filter.h"
 #include "src/core/lib/channel/connected_channel.h"
-#include "src/core/lib/channel/http_client_filter.h"
-#include "src/core/lib/channel/http_server_filter.h"
 #include "src/core/lib/iomgr/endpoint_pair.h"
 #include "src/core/lib/iomgr/iomgr.h"
 #include "src/core/lib/surface/channel.h"
@@ -88,7 +88,8 @@
   grpc_end2end_test_fixture f;
   memset(&f, 0, sizeof(f));
   f.fixture_data = sfd;
-  f.cq = grpc_completion_queue_create(NULL);
+  f.cq = grpc_completion_queue_create_for_next(NULL);
+  f.shutdown_cq = grpc_completion_queue_create_for_pluck(NULL);
 
   *sfd = grpc_iomgr_create_endpoint_pair("fixture", NULL);
 
diff --git a/test/core/end2end/fixtures/h2_sockpair_1byte.c b/test/core/end2end/fixtures/h2_sockpair_1byte.c
index 04174fa..8714266 100644
--- a/test/core/end2end/fixtures/h2_sockpair_1byte.c
+++ b/test/core/end2end/fixtures/h2_sockpair_1byte.c
@@ -41,11 +41,11 @@
 #include <grpc/support/thd.h>
 #include <grpc/support/useful.h>
 #include "src/core/ext/filters/client_channel/client_channel.h"
+#include "src/core/ext/filters/http/client/http_client_filter.h"
+#include "src/core/ext/filters/http/message_compress/message_compress_filter.h"
+#include "src/core/ext/filters/http/server/http_server_filter.h"
 #include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
-#include "src/core/lib/channel/compress_filter.h"
 #include "src/core/lib/channel/connected_channel.h"
-#include "src/core/lib/channel/http_client_filter.h"
-#include "src/core/lib/channel/http_server_filter.h"
 #include "src/core/lib/iomgr/endpoint_pair.h"
 #include "src/core/lib/iomgr/iomgr.h"
 #include "src/core/lib/surface/channel.h"
@@ -88,7 +88,8 @@
   grpc_end2end_test_fixture f;
   memset(&f, 0, sizeof(f));
   f.fixture_data = sfd;
-  f.cq = grpc_completion_queue_create(NULL);
+  f.cq = grpc_completion_queue_create_for_next(NULL);
+  f.shutdown_cq = grpc_completion_queue_create_for_pluck(NULL);
 
   grpc_arg a[] = {{.key = GRPC_ARG_TCP_READ_CHUNK_SIZE,
                    .type = GRPC_ARG_INTEGER,
diff --git a/test/core/end2end/fixtures/h2_ssl.c b/test/core/end2end/fixtures/h2_ssl.c
index cf44cd0..c6a1ca0 100644
--- a/test/core/end2end/fixtures/h2_ssl.c
+++ b/test/core/end2end/fixtures/h2_ssl.c
@@ -64,7 +64,8 @@
   gpr_join_host_port(&ffd->localaddr, "localhost", port);
 
   f.fixture_data = ffd;
-  f.cq = grpc_completion_queue_create(NULL);
+  f.cq = grpc_completion_queue_create_for_next(NULL);
+  f.shutdown_cq = grpc_completion_queue_create_for_pluck(NULL);
 
   return f;
 }
diff --git a/test/core/end2end/fixtures/h2_ssl_cert.c b/test/core/end2end/fixtures/h2_ssl_cert.c
index f62331e..7aa0e16 100644
--- a/test/core/end2end/fixtures/h2_ssl_cert.c
+++ b/test/core/end2end/fixtures/h2_ssl_cert.c
@@ -67,7 +67,8 @@
   gpr_join_host_port(&ffd->localaddr, "localhost", port);
 
   f.fixture_data = ffd;
-  f.cq = grpc_completion_queue_create(NULL);
+  f.cq = grpc_completion_queue_create_for_next(NULL);
+  f.shutdown_cq = grpc_completion_queue_create_for_pluck(NULL);
 
   return f;
 }
@@ -289,9 +290,10 @@
 
 static void shutdown_server(grpc_end2end_test_fixture *f) {
   if (!f->server) return;
-  grpc_server_shutdown_and_notify(f->server, f->cq, tag(1000));
-  GPR_ASSERT(grpc_completion_queue_pluck(
-                 f->cq, tag(1000), grpc_timeout_seconds_to_deadline(5), NULL)
+  grpc_server_shutdown_and_notify(f->server, f->shutdown_cq, tag(1000));
+  GPR_ASSERT(grpc_completion_queue_pluck(f->shutdown_cq, tag(1000),
+                                         grpc_timeout_seconds_to_deadline(5),
+                                         NULL)
                  .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
@@ -310,6 +312,7 @@
   grpc_completion_queue_shutdown(f->cq);
   drain_cq(f->cq);
   grpc_completion_queue_destroy(f->cq);
+  grpc_completion_queue_destroy(f->shutdown_cq);
 }
 
 static void simple_request_body(grpc_end2end_test_fixture f,
diff --git a/test/core/end2end/fixtures/h2_ssl_proxy.c b/test/core/end2end/fixtures/h2_ssl_proxy.c
index 740b075..9a6c9f5 100644
--- a/test/core/end2end/fixtures/h2_ssl_proxy.c
+++ b/test/core/end2end/fixtures/h2_ssl_proxy.c
@@ -100,7 +100,8 @@
   ffd->proxy = grpc_end2end_proxy_create(&proxy_def, client_args, server_args);
 
   f.fixture_data = ffd;
-  f.cq = grpc_completion_queue_create(NULL);
+  f.cq = grpc_completion_queue_create_for_next(NULL);
+  f.shutdown_cq = grpc_completion_queue_create_for_pluck(NULL);
 
   return f;
 }
diff --git a/test/core/end2end/fixtures/h2_uds.c b/test/core/end2end/fixtures/h2_uds.c
index 7bde69d..de1b8eb 100644
--- a/test/core/end2end/fixtures/h2_uds.c
+++ b/test/core/end2end/fixtures/h2_uds.c
@@ -45,9 +45,9 @@
 #include <grpc/support/thd.h>
 #include <grpc/support/useful.h>
 #include "src/core/ext/filters/client_channel/client_channel.h"
+#include "src/core/ext/filters/http/server/http_server_filter.h"
 #include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
 #include "src/core/lib/channel/connected_channel.h"
-#include "src/core/lib/channel/http_server_filter.h"
 #include "src/core/lib/support/string.h"
 #include "src/core/lib/surface/channel.h"
 #include "src/core/lib/surface/server.h"
@@ -70,7 +70,8 @@
                unique++);
 
   f.fixture_data = ffd;
-  f.cq = grpc_completion_queue_create(NULL);
+  f.cq = grpc_completion_queue_create_for_next(NULL);
+  f.shutdown_cq = grpc_completion_queue_create_for_pluck(NULL);
 
   return f;
 }
diff --git a/test/core/end2end/fixtures/proxy.c b/test/core/end2end/fixtures/proxy.c
index cee053e..b8b1e5c 100644
--- a/test/core/end2end/fixtures/proxy.c
+++ b/test/core/end2end/fixtures/proxy.c
@@ -104,7 +104,7 @@
   gpr_log(GPR_DEBUG, "PROXY ADDR:%s BACKEND:%s", proxy->proxy_port,
           proxy->server_port);
 
-  proxy->cq = grpc_completion_queue_create(NULL);
+  proxy->cq = grpc_completion_queue_create_for_next(NULL);
   proxy->server = def->create_server(proxy->proxy_port, server_args);
   proxy->client = def->create_client(proxy->server_port, client_args);
 
diff --git a/test/core/end2end/fuzzers/api_fuzzer.c b/test/core/end2end/fuzzers/api_fuzzer.c
index a0acf5b..83c82ba 100644
--- a/test/core/end2end/fuzzers/api_fuzzer.c
+++ b/test/core/end2end/fuzzers/api_fuzzer.c
@@ -735,7 +735,7 @@
   g_active_call = new_call(NULL, ROOT);
   g_resource_quota = grpc_resource_quota_create("api_fuzzer");
 
-  grpc_completion_queue *cq = grpc_completion_queue_create(NULL);
+  grpc_completion_queue *cq = grpc_completion_queue_create_for_next(NULL);
 
   while (!is_eof(&inp) || g_channel != NULL || g_server != NULL ||
          pending_channel_watches > 0 || pending_pings > 0 ||
@@ -932,6 +932,9 @@
         }
         uint32_t propagation_mask = read_uint32(&inp);
         grpc_slice method = read_string_like_slice(&inp);
+        if (GRPC_SLICE_LENGTH(method) == 0) {
+          ok = false;
+        }
         grpc_slice host = read_string_like_slice(&inp);
         gpr_timespec deadline =
             gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
@@ -967,7 +970,7 @@
           break;
         }
         grpc_op *ops = gpr_malloc(sizeof(grpc_op) * num_ops);
-        memset(ops, 0, sizeof(grpc_op) * num_ops);
+        if (num_ops > 0) memset(ops, 0, sizeof(grpc_op) * num_ops);
         bool ok = true;
         size_t i;
         grpc_op *op;
diff --git a/test/core/end2end/fuzzers/api_fuzzer_corpus/clusterfuzz-testcase-5867145026076672 b/test/core/end2end/fuzzers/api_fuzzer_corpus/clusterfuzz-testcase-5867145026076672
new file mode 100644
index 0000000..3fd5427
--- /dev/null
+++ b/test/core/end2end/fuzzers/api_fuzzer_corpus/clusterfuzz-testcase-5867145026076672
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer.c b/test/core/end2end/fuzzers/client_fuzzer.c
index e7e7dbe..bc322e4 100644
--- a/test/core/end2end/fuzzers/client_fuzzer.c
+++ b/test/core/end2end/fuzzers/client_fuzzer.c
@@ -65,7 +65,7 @@
       grpc_mock_endpoint_create(discard_write, resource_quota);
   grpc_resource_quota_unref_internal(&exec_ctx, resource_quota);
 
-  grpc_completion_queue *cq = grpc_completion_queue_create(NULL);
+  grpc_completion_queue *cq = grpc_completion_queue_create_for_next(NULL);
   grpc_transport *transport =
       grpc_create_chttp2_transport(&exec_ctx, NULL, mock_endpoint, 1);
   grpc_chttp2_transport_start_reading(&exec_ctx, transport, NULL);
diff --git a/test/core/end2end/fuzzers/hpack.dictionary b/test/core/end2end/fuzzers/hpack.dictionary
index 6b96785..2bb9de3 100644
--- a/test/core/end2end/fuzzers/hpack.dictionary
+++ b/test/core/end2end/fuzzers/hpack.dictionary
@@ -10,14 +10,15 @@
 "\x10grpc-payload-bin"
 "\x0Dgrpc-encoding"
 "\x14grpc-accept-encoding"
+"\x15grpc-server-stats-bin"
+"\x0Dgrpc-tags-bin"
+"\x0Egrpc-trace-bin"
 "\x0Ccontent-type"
 "\x1Egrpc-internal-encoding-request"
 "\x0Auser-agent"
 "\x04host"
 "\x08lb-token"
 "\x0Cgrpc-timeout"
-"\x10grpc-tracing-bin"
-"\x0Egrpc-stats-bin"
 "\x00"
 "\x13grpc.wait_for_ready"
 "\x0Cgrpc.timeout"
@@ -76,6 +77,7 @@
 "\x08if-range"
 "\x13if-unmodified-since"
 "\x0Dlast-modified"
+"\x0Blb-cost-bin"
 "\x04link"
 "\x08location"
 "\x0Cmax-forwards"
@@ -152,6 +154,7 @@
 "\x00\x13if-unmodified-since\x00"
 "\x00\x0Dlast-modified\x00"
 "\x00\x08lb-token\x00"
+"\x00\x0Blb-cost-bin\x00"
 "\x00\x04link\x00"
 "\x00\x08location\x00"
 "\x00\x0Cmax-forwards\x00"
diff --git a/test/core/end2end/fuzzers/server_fuzzer.c b/test/core/end2end/fuzzers/server_fuzzer.c
index 186542d..97b436c 100644
--- a/test/core/end2end/fuzzers/server_fuzzer.c
+++ b/test/core/end2end/fuzzers/server_fuzzer.c
@@ -67,7 +67,7 @@
       grpc_slice_from_copied_buffer((const char *)data, size));
 
   grpc_server *server = grpc_server_create(NULL, NULL);
-  grpc_completion_queue *cq = grpc_completion_queue_create(NULL);
+  grpc_completion_queue *cq = grpc_completion_queue_create_for_next(NULL);
   grpc_server_register_completion_queue(server, cq, NULL);
   // TODO(ctiller): add registered methods (one for POST, one for PUT)
   // void *registered_method =
diff --git a/test/core/end2end/fuzzers/server_fuzzer_corpus/clusterfuzz-testcase-5595941564317696 b/test/core/end2end/fuzzers/server_fuzzer_corpus/clusterfuzz-testcase-5595941564317696
new file mode 100644
index 0000000..335ce87
--- /dev/null
+++ b/test/core/end2end/fuzzers/server_fuzzer_corpus/clusterfuzz-testcase-5595941564317696
Binary files differ
diff --git a/test/core/end2end/goaway_server_test.c b/test/core/end2end/goaway_server_test.c
index 22d93b3..a028fb7 100644
--- a/test/core/end2end/goaway_server_test.c
+++ b/test/core/end2end/goaway_server_test.c
@@ -129,7 +129,7 @@
   grpc_metadata_array_init(&request_metadata2);
   grpc_call_details_init(&request_details2);
 
-  cq = grpc_completion_queue_create(NULL);
+  cq = grpc_completion_queue_create_for_next(NULL);
   cqv = cq_verifier_create(cq);
 
   /* reserve two ports */
diff --git a/test/core/end2end/invalid_call_argument_test.c b/test/core/end2end/invalid_call_argument_test.c
index bfd8e6f..e89e597 100644
--- a/test/core/end2end/invalid_call_argument_test.c
+++ b/test/core/end2end/invalid_call_argument_test.c
@@ -75,7 +75,7 @@
   grpc_metadata_array_init(&g_state.initial_metadata_recv);
   grpc_metadata_array_init(&g_state.trailing_metadata_recv);
   g_state.deadline = grpc_timeout_seconds_to_deadline(2);
-  g_state.cq = grpc_completion_queue_create(NULL);
+  g_state.cq = grpc_completion_queue_create_for_next(NULL);
   g_state.cqv = cq_verifier_create(g_state.cq);
   g_state.details = grpc_empty_slice();
   memset(g_state.ops, 0, sizeof(g_state.ops));
@@ -125,6 +125,7 @@
 }
 
 static void cleanup_test() {
+  grpc_completion_queue *shutdown_cq;
   grpc_call_destroy(g_state.call);
   cq_verifier_destroy(g_state.cqv);
   grpc_channel_destroy(g_state.chan);
@@ -133,12 +134,14 @@
   grpc_metadata_array_destroy(&g_state.trailing_metadata_recv);
 
   if (!g_state.is_client) {
+    shutdown_cq = grpc_completion_queue_create_for_pluck(NULL);
     grpc_call_destroy(g_state.server_call);
-    grpc_server_shutdown_and_notify(g_state.server, g_state.cq, tag(1000));
-    GPR_ASSERT(grpc_completion_queue_pluck(g_state.cq, tag(1000),
+    grpc_server_shutdown_and_notify(g_state.server, shutdown_cq, tag(1000));
+    GPR_ASSERT(grpc_completion_queue_pluck(shutdown_cq, tag(1000),
                                            grpc_timeout_seconds_to_deadline(5),
                                            NULL)
                    .type == GRPC_OP_COMPLETE);
+    grpc_completion_queue_destroy(shutdown_cq);
     grpc_server_destroy(g_state.server);
     grpc_call_details_destroy(&g_state.call_details);
     grpc_metadata_array_destroy(&g_state.server_initial_metadata_recv);
diff --git a/test/core/end2end/multiple_server_queues_test.c b/test/core/end2end/multiple_server_queues_test.c
index 5e2eaf4..4696ecd 100644
--- a/test/core/end2end/multiple_server_queues_test.c
+++ b/test/core/end2end/multiple_server_queues_test.c
@@ -37,27 +37,50 @@
 int main(int argc, char **argv) {
   grpc_completion_queue *cq1;
   grpc_completion_queue *cq2;
+  grpc_completion_queue *cq3;
+  grpc_completion_queue_attributes attr;
+
   grpc_server *server;
 
   grpc_test_init(argc, argv);
   grpc_init();
-  cq1 = grpc_completion_queue_create(NULL);
-  cq2 = grpc_completion_queue_create(NULL);
+
+  attr.version = 1;
+  attr.cq_completion_type = GRPC_CQ_NEXT;
+  attr.cq_polling_type = GRPC_CQ_DEFAULT_POLLING;
+  cq1 = grpc_completion_queue_create(
+      grpc_completion_queue_factory_lookup(&attr), &attr, NULL);
+
+  attr.cq_polling_type = GRPC_CQ_NON_LISTENING;
+  cq2 = grpc_completion_queue_create(
+      grpc_completion_queue_factory_lookup(&attr), &attr, NULL);
+
+  attr.cq_polling_type = GRPC_CQ_NON_POLLING;
+  cq3 = grpc_completion_queue_create(
+      grpc_completion_queue_factory_lookup(&attr), &attr, NULL);
+
   server = grpc_server_create(NULL, NULL);
   grpc_server_register_completion_queue(server, cq1, NULL);
   grpc_server_add_insecure_http2_port(server, "[::]:0");
   grpc_server_register_completion_queue(server, cq2, NULL);
+  grpc_server_register_completion_queue(server, cq3, NULL);
+
   grpc_server_start(server);
   grpc_server_shutdown_and_notify(server, cq2, NULL);
   grpc_completion_queue_next(cq2, gpr_inf_future(GPR_CLOCK_REALTIME),
                              NULL); /* cue queue hang */
   grpc_completion_queue_shutdown(cq1);
   grpc_completion_queue_shutdown(cq2);
+  grpc_completion_queue_shutdown(cq3);
+
   grpc_completion_queue_next(cq1, gpr_inf_future(GPR_CLOCK_REALTIME), NULL);
   grpc_completion_queue_next(cq2, gpr_inf_future(GPR_CLOCK_REALTIME), NULL);
+  grpc_completion_queue_next(cq3, gpr_inf_future(GPR_CLOCK_REALTIME), NULL);
+
   grpc_server_destroy(server);
   grpc_completion_queue_destroy(cq1);
   grpc_completion_queue_destroy(cq2);
+  grpc_completion_queue_destroy(cq3);
   grpc_shutdown();
   return 0;
 }
diff --git a/test/core/end2end/no_server_test.c b/test/core/end2end/no_server_test.c
index 26d26d8..dd18b0c 100644
--- a/test/core/end2end/no_server_test.c
+++ b/test/core/end2end/no_server_test.c
@@ -59,7 +59,7 @@
 
   grpc_metadata_array_init(&trailing_metadata_recv);
 
-  cq = grpc_completion_queue_create(NULL);
+  cq = grpc_completion_queue_create_for_next(NULL);
   cqv = cq_verifier_create(cq);
 
   /* create a call, channel to a non existant server */
diff --git a/test/core/end2end/tests/authority_not_supported.c b/test/core/end2end/tests/authority_not_supported.c
index 192a20d..f9298f1 100644
--- a/test/core/end2end/tests/authority_not_supported.c
+++ b/test/core/end2end/tests/authority_not_supported.c
@@ -74,9 +74,10 @@
 
 static void shutdown_server(grpc_end2end_test_fixture *f) {
   if (!f->server) return;
-  grpc_server_shutdown_and_notify(f->server, f->cq, tag(1000));
-  GPR_ASSERT(grpc_completion_queue_pluck(
-                 f->cq, tag(1000), grpc_timeout_seconds_to_deadline(5), NULL)
+  grpc_server_shutdown_and_notify(f->server, f->shutdown_cq, tag(1000));
+  GPR_ASSERT(grpc_completion_queue_pluck(f->shutdown_cq, tag(1000),
+                                         grpc_timeout_seconds_to_deadline(5),
+                                         NULL)
                  .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
@@ -95,6 +96,7 @@
   grpc_completion_queue_shutdown(f->cq);
   drain_cq(f->cq);
   grpc_completion_queue_destroy(f->cq);
+  grpc_completion_queue_destroy(f->shutdown_cq);
 }
 
 /* Request/response with metadata and payload.*/
diff --git a/test/core/end2end/tests/bad_hostname.c b/test/core/end2end/tests/bad_hostname.c
index c63c9c7..72a44d0 100644
--- a/test/core/end2end/tests/bad_hostname.c
+++ b/test/core/end2end/tests/bad_hostname.c
@@ -76,9 +76,10 @@
 
 static void shutdown_server(grpc_end2end_test_fixture *f) {
   if (!f->server) return;
-  grpc_server_shutdown_and_notify(f->server, f->cq, tag(1000));
-  GPR_ASSERT(grpc_completion_queue_pluck(
-                 f->cq, tag(1000), grpc_timeout_seconds_to_deadline(5), NULL)
+  grpc_server_shutdown_and_notify(f->server, f->shutdown_cq, tag(1000));
+  GPR_ASSERT(grpc_completion_queue_pluck(f->shutdown_cq, tag(1000),
+                                         grpc_timeout_seconds_to_deadline(5),
+                                         NULL)
                  .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
@@ -97,6 +98,7 @@
   grpc_completion_queue_shutdown(f->cq);
   drain_cq(f->cq);
   grpc_completion_queue_destroy(f->cq);
+  grpc_completion_queue_destroy(f->shutdown_cq);
 }
 
 static void simple_request_body(grpc_end2end_test_fixture f) {
diff --git a/test/core/end2end/tests/bad_ping.c b/test/core/end2end/tests/bad_ping.c
index 01a6aea..38cd1df 100644
--- a/test/core/end2end/tests/bad_ping.c
+++ b/test/core/end2end/tests/bad_ping.c
@@ -75,6 +75,7 @@
   grpc_completion_queue_shutdown(f->cq);
   drain_cq(f->cq);
   grpc_completion_queue_destroy(f->cq);
+  grpc_completion_queue_destroy(f->shutdown_cq);
 }
 
 static void test_bad_ping(grpc_end2end_test_config config) {
diff --git a/test/core/end2end/tests/binary_metadata.c b/test/core/end2end/tests/binary_metadata.c
index 9cb17c9..2bddd05 100644
--- a/test/core/end2end/tests/binary_metadata.c
+++ b/test/core/end2end/tests/binary_metadata.c
@@ -74,9 +74,10 @@
 
 static void shutdown_server(grpc_end2end_test_fixture *f) {
   if (!f->server) return;
-  grpc_server_shutdown_and_notify(f->server, f->cq, tag(1000));
-  GPR_ASSERT(grpc_completion_queue_pluck(
-                 f->cq, tag(1000), grpc_timeout_seconds_to_deadline(5), NULL)
+  grpc_server_shutdown_and_notify(f->server, f->shutdown_cq, tag(1000));
+  GPR_ASSERT(grpc_completion_queue_pluck(f->shutdown_cq, tag(1000),
+                                         grpc_timeout_seconds_to_deadline(5),
+                                         NULL)
                  .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
@@ -95,6 +96,7 @@
   grpc_completion_queue_shutdown(f->cq);
   drain_cq(f->cq);
   grpc_completion_queue_destroy(f->cq);
+  grpc_completion_queue_destroy(f->shutdown_cq);
 }
 
 /* Request/response with metadata and payload.*/
diff --git a/test/core/end2end/tests/call_creds.c b/test/core/end2end/tests/call_creds.c
index d65073f..9ec9701 100644
--- a/test/core/end2end/tests/call_creds.c
+++ b/test/core/end2end/tests/call_creds.c
@@ -92,9 +92,10 @@
 
 static void shutdown_server(grpc_end2end_test_fixture *f) {
   if (!f->server) return;
-  grpc_server_shutdown_and_notify(f->server, f->cq, tag(1000));
-  GPR_ASSERT(grpc_completion_queue_pluck(
-                 f->cq, tag(1000), grpc_timeout_seconds_to_deadline(5), NULL)
+  grpc_server_shutdown_and_notify(f->server, f->shutdown_cq, tag(1000));
+  GPR_ASSERT(grpc_completion_queue_pluck(f->shutdown_cq, tag(1000),
+                                         grpc_timeout_seconds_to_deadline(5),
+                                         NULL)
                  .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
@@ -113,6 +114,7 @@
   grpc_completion_queue_shutdown(f->cq);
   drain_cq(f->cq);
   grpc_completion_queue_destroy(f->cq);
+  grpc_completion_queue_destroy(f->shutdown_cq);
 }
 
 static void print_auth_context(int is_client, const grpc_auth_context *ctx) {
diff --git a/test/core/end2end/tests/cancel_after_accept.c b/test/core/end2end/tests/cancel_after_accept.c
index bda061c..7946865 100644
--- a/test/core/end2end/tests/cancel_after_accept.c
+++ b/test/core/end2end/tests/cancel_after_accept.c
@@ -81,9 +81,10 @@
 
 static void shutdown_server(grpc_end2end_test_fixture *f) {
   if (!f->server) return;
-  grpc_server_shutdown_and_notify(f->server, f->cq, tag(1000));
-  GPR_ASSERT(grpc_completion_queue_pluck(
-                 f->cq, tag(1000), grpc_timeout_seconds_to_deadline(5), NULL)
+  grpc_server_shutdown_and_notify(f->server, f->shutdown_cq, tag(1000));
+  GPR_ASSERT(grpc_completion_queue_pluck(f->shutdown_cq, tag(1000),
+                                         grpc_timeout_seconds_to_deadline(5),
+                                         NULL)
                  .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
@@ -102,6 +103,7 @@
   grpc_completion_queue_shutdown(f->cq);
   drain_cq(f->cq);
   grpc_completion_queue_destroy(f->cq);
+  grpc_completion_queue_destroy(f->shutdown_cq);
 }
 
 /* Cancel after accept, no payload */
diff --git a/test/core/end2end/tests/cancel_after_client_done.c b/test/core/end2end/tests/cancel_after_client_done.c
index 0e72911..7089f3f 100644
--- a/test/core/end2end/tests/cancel_after_client_done.c
+++ b/test/core/end2end/tests/cancel_after_client_done.c
@@ -75,9 +75,10 @@
 
 static void shutdown_server(grpc_end2end_test_fixture *f) {
   if (!f->server) return;
-  grpc_server_shutdown_and_notify(f->server, f->cq, tag(1000));
-  GPR_ASSERT(grpc_completion_queue_pluck(
-                 f->cq, tag(1000), grpc_timeout_seconds_to_deadline(5), NULL)
+  grpc_server_shutdown_and_notify(f->server, f->shutdown_cq, tag(1000));
+  GPR_ASSERT(grpc_completion_queue_pluck(f->shutdown_cq, tag(1000),
+                                         grpc_timeout_seconds_to_deadline(5),
+                                         NULL)
                  .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
@@ -96,6 +97,7 @@
   grpc_completion_queue_shutdown(f->cq);
   drain_cq(f->cq);
   grpc_completion_queue_destroy(f->cq);
+  grpc_completion_queue_destroy(f->shutdown_cq);
 }
 
 /* Cancel after accept with a writes closed, no payload */
diff --git a/test/core/end2end/tests/cancel_after_invoke.c b/test/core/end2end/tests/cancel_after_invoke.c
index 0ee5980..f29012b 100644
--- a/test/core/end2end/tests/cancel_after_invoke.c
+++ b/test/core/end2end/tests/cancel_after_invoke.c
@@ -78,9 +78,10 @@
 static void shutdown_server(grpc_end2end_test_fixture *f) {
   if (!f->server) return;
   grpc_server_shutdown_and_notify(f->server, f->cq, tag(1000));
-  GPR_ASSERT(grpc_completion_queue_pluck(
-                 f->cq, tag(1000), grpc_timeout_seconds_to_deadline(5), NULL)
-                 .type == GRPC_OP_COMPLETE);
+  grpc_event ev = grpc_completion_queue_next(
+      f->cq, grpc_timeout_seconds_to_deadline(5), NULL);
+  GPR_ASSERT(ev.type == GRPC_OP_COMPLETE);
+  GPR_ASSERT(ev.tag == tag(1000));
   grpc_server_destroy(f->server);
   f->server = NULL;
 }
@@ -98,6 +99,7 @@
   grpc_completion_queue_shutdown(f->cq);
   drain_cq(f->cq);
   grpc_completion_queue_destroy(f->cq);
+  grpc_completion_queue_destroy(f->shutdown_cq);
 }
 
 /* Cancel after invoke, no payload */
diff --git a/test/core/end2end/tests/cancel_before_invoke.c b/test/core/end2end/tests/cancel_before_invoke.c
index 7d53091..1b1296d 100644
--- a/test/core/end2end/tests/cancel_before_invoke.c
+++ b/test/core/end2end/tests/cancel_before_invoke.c
@@ -74,9 +74,10 @@
 
 static void shutdown_server(grpc_end2end_test_fixture *f) {
   if (!f->server) return;
-  grpc_server_shutdown_and_notify(f->server, f->cq, tag(1000));
-  GPR_ASSERT(grpc_completion_queue_pluck(
-                 f->cq, tag(1000), grpc_timeout_seconds_to_deadline(5), NULL)
+  grpc_server_shutdown_and_notify(f->server, f->shutdown_cq, tag(1000));
+  GPR_ASSERT(grpc_completion_queue_pluck(f->shutdown_cq, tag(1000),
+                                         grpc_timeout_seconds_to_deadline(5),
+                                         NULL)
                  .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
@@ -95,6 +96,7 @@
   grpc_completion_queue_shutdown(f->cq);
   drain_cq(f->cq);
   grpc_completion_queue_destroy(f->cq);
+  grpc_completion_queue_destroy(f->shutdown_cq);
 }
 
 /* Cancel before invoke */
diff --git a/test/core/end2end/tests/cancel_in_a_vacuum.c b/test/core/end2end/tests/cancel_in_a_vacuum.c
index c13fc88..4f5e496 100644
--- a/test/core/end2end/tests/cancel_in_a_vacuum.c
+++ b/test/core/end2end/tests/cancel_in_a_vacuum.c
@@ -75,9 +75,10 @@
 
 static void shutdown_server(grpc_end2end_test_fixture *f) {
   if (!f->server) return;
-  grpc_server_shutdown_and_notify(f->server, f->cq, tag(1000));
-  GPR_ASSERT(grpc_completion_queue_pluck(
-                 f->cq, tag(1000), grpc_timeout_seconds_to_deadline(5), NULL)
+  grpc_server_shutdown_and_notify(f->server, f->shutdown_cq, tag(1000));
+  GPR_ASSERT(grpc_completion_queue_pluck(f->shutdown_cq, tag(1000),
+                                         grpc_timeout_seconds_to_deadline(5),
+                                         NULL)
                  .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
@@ -96,6 +97,7 @@
   grpc_completion_queue_shutdown(f->cq);
   drain_cq(f->cq);
   grpc_completion_queue_destroy(f->cq);
+  grpc_completion_queue_destroy(f->shutdown_cq);
 }
 
 /* Cancel and do nothing */
diff --git a/test/core/end2end/tests/cancel_with_status.c b/test/core/end2end/tests/cancel_with_status.c
index 1e0e33b..180748c 100644
--- a/test/core/end2end/tests/cancel_with_status.c
+++ b/test/core/end2end/tests/cancel_with_status.c
@@ -77,9 +77,10 @@
 static void shutdown_server(grpc_end2end_test_fixture *f) {
   if (!f->server) return;
   grpc_server_shutdown_and_notify(f->server, f->cq, tag(1000));
-  GPR_ASSERT(grpc_completion_queue_pluck(
-                 f->cq, tag(1000), grpc_timeout_seconds_to_deadline(5), NULL)
-                 .type == GRPC_OP_COMPLETE);
+  grpc_event ev = grpc_completion_queue_next(
+      f->cq, grpc_timeout_seconds_to_deadline(5), NULL);
+  GPR_ASSERT(ev.type == GRPC_OP_COMPLETE);
+  GPR_ASSERT(ev.tag == tag(1000));
   grpc_server_destroy(f->server);
   f->server = NULL;
 }
@@ -97,6 +98,7 @@
   grpc_completion_queue_shutdown(f->cq);
   drain_cq(f->cq);
   grpc_completion_queue_destroy(f->cq);
+  grpc_completion_queue_destroy(f->shutdown_cq);
 }
 
 static void simple_request_body(grpc_end2end_test_config config,
diff --git a/test/core/end2end/tests/compressed_payload.c b/test/core/end2end/tests/compressed_payload.c
index c5b750a..1671ce5 100644
--- a/test/core/end2end/tests/compressed_payload.c
+++ b/test/core/end2end/tests/compressed_payload.c
@@ -82,9 +82,10 @@
 
 static void shutdown_server(grpc_end2end_test_fixture *f) {
   if (!f->server) return;
-  grpc_server_shutdown_and_notify(f->server, f->cq, tag(1000));
-  GPR_ASSERT(grpc_completion_queue_pluck(
-                 f->cq, tag(1000), grpc_timeout_seconds_to_deadline(5), NULL)
+  grpc_server_shutdown_and_notify(f->server, f->shutdown_cq, tag(1000));
+  GPR_ASSERT(grpc_completion_queue_pluck(f->shutdown_cq, tag(1000),
+                                         grpc_timeout_seconds_to_deadline(5),
+                                         NULL)
                  .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
@@ -103,6 +104,7 @@
   grpc_completion_queue_shutdown(f->cq);
   drain_cq(f->cq);
   grpc_completion_queue_destroy(f->cq);
+  grpc_completion_queue_destroy(f->shutdown_cq);
 }
 
 static void request_for_disabled_algorithm(
diff --git a/test/core/end2end/tests/connectivity.c b/test/core/end2end/tests/connectivity.c
index 979419a..eb84aae 100644
--- a/test/core/end2end/tests/connectivity.c
+++ b/test/core/end2end/tests/connectivity.c
@@ -171,6 +171,9 @@
   grpc_channel_destroy(f.client);
   grpc_completion_queue_shutdown(f.cq);
   grpc_completion_queue_destroy(f.cq);
+
+  /* shutdown_cq is not used in this test */
+  grpc_completion_queue_destroy(f.shutdown_cq);
   config.tear_down_data(&f);
 
   cq_verifier_destroy(cqv);
diff --git a/test/core/end2end/tests/default_host.c b/test/core/end2end/tests/default_host.c
index 8dccca2..c0ae50e 100644
--- a/test/core/end2end/tests/default_host.c
+++ b/test/core/end2end/tests/default_host.c
@@ -76,9 +76,10 @@
 
 static void shutdown_server(grpc_end2end_test_fixture *f) {
   if (!f->server) return;
-  grpc_server_shutdown_and_notify(f->server, f->cq, tag(1000));
-  GPR_ASSERT(grpc_completion_queue_pluck(
-                 f->cq, tag(1000), grpc_timeout_seconds_to_deadline(5), NULL)
+  grpc_server_shutdown_and_notify(f->server, f->shutdown_cq, tag(1000));
+  GPR_ASSERT(grpc_completion_queue_pluck(f->shutdown_cq, tag(1000),
+                                         grpc_timeout_seconds_to_deadline(5),
+                                         NULL)
                  .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
@@ -97,6 +98,7 @@
   grpc_completion_queue_shutdown(f->cq);
   drain_cq(f->cq);
   grpc_completion_queue_destroy(f->cq);
+  grpc_completion_queue_destroy(f->shutdown_cq);
 }
 
 static void simple_request_body(grpc_end2end_test_fixture f) {
diff --git a/test/core/end2end/tests/disappearing_server.c b/test/core/end2end/tests/disappearing_server.c
index e2b888a..22492c0 100644
--- a/test/core/end2end/tests/disappearing_server.c
+++ b/test/core/end2end/tests/disappearing_server.c
@@ -79,6 +79,9 @@
   grpc_completion_queue_shutdown(f->cq);
   drain_cq(f->cq);
   grpc_completion_queue_destroy(f->cq);
+
+  /* Note: shutdown_cq was unused in this test */
+  grpc_completion_queue_destroy(f->shutdown_cq);
 }
 
 static void do_request_and_shutdown_server(grpc_end2end_test_config config,
diff --git a/test/core/end2end/tests/empty_batch.c b/test/core/end2end/tests/empty_batch.c
index 37ca813..fe57a6e 100644
--- a/test/core/end2end/tests/empty_batch.c
+++ b/test/core/end2end/tests/empty_batch.c
@@ -76,9 +76,10 @@
 
 static void shutdown_server(grpc_end2end_test_fixture *f) {
   if (!f->server) return;
-  grpc_server_shutdown_and_notify(f->server, f->cq, tag(1000));
-  GPR_ASSERT(grpc_completion_queue_pluck(
-                 f->cq, tag(1000), grpc_timeout_seconds_to_deadline(5), NULL)
+  grpc_server_shutdown_and_notify(f->server, f->shutdown_cq, tag(1000));
+  GPR_ASSERT(grpc_completion_queue_pluck(f->shutdown_cq, tag(1000),
+                                         grpc_timeout_seconds_to_deadline(5),
+                                         NULL)
                  .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
@@ -97,6 +98,7 @@
   grpc_completion_queue_shutdown(f->cq);
   drain_cq(f->cq);
   grpc_completion_queue_destroy(f->cq);
+  grpc_completion_queue_destroy(f->shutdown_cq);
 }
 
 static void empty_batch_body(grpc_end2end_test_config config,
diff --git a/test/core/end2end/tests/filter_call_init_fails.c b/test/core/end2end/tests/filter_call_init_fails.c
index 0c4f0dd..8d654d7 100644
--- a/test/core/end2end/tests/filter_call_init_fails.c
+++ b/test/core/end2end/tests/filter_call_init_fails.c
@@ -84,9 +84,10 @@
 
 static void shutdown_server(grpc_end2end_test_fixture *f) {
   if (!f->server) return;
-  grpc_server_shutdown_and_notify(f->server, f->cq, tag(1000));
-  GPR_ASSERT(grpc_completion_queue_pluck(
-                 f->cq, tag(1000), grpc_timeout_seconds_to_deadline(5), NULL)
+  grpc_server_shutdown_and_notify(f->server, f->shutdown_cq, tag(1000));
+  GPR_ASSERT(grpc_completion_queue_pluck(f->shutdown_cq, tag(1000),
+                                         grpc_timeout_seconds_to_deadline(5),
+                                         NULL)
                  .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
@@ -105,6 +106,7 @@
   grpc_completion_queue_shutdown(f->cq);
   drain_cq(f->cq);
   grpc_completion_queue_destroy(f->cq);
+  grpc_completion_queue_destroy(f->shutdown_cq);
 }
 
 // Simple request via a SERVER_CHANNEL filter that always fails to
diff --git a/test/core/end2end/tests/filter_causes_close.c b/test/core/end2end/tests/filter_causes_close.c
index 9115823..decfff3 100644
--- a/test/core/end2end/tests/filter_causes_close.c
+++ b/test/core/end2end/tests/filter_causes_close.c
@@ -79,9 +79,10 @@
 
 static void shutdown_server(grpc_end2end_test_fixture *f) {
   if (!f->server) return;
-  grpc_server_shutdown_and_notify(f->server, f->cq, tag(1000));
-  GPR_ASSERT(grpc_completion_queue_pluck(
-                 f->cq, tag(1000), grpc_timeout_seconds_to_deadline(5), NULL)
+  grpc_server_shutdown_and_notify(f->server, f->shutdown_cq, tag(1000));
+  GPR_ASSERT(grpc_completion_queue_pluck(f->shutdown_cq, tag(1000),
+                                         grpc_timeout_seconds_to_deadline(5),
+                                         NULL)
                  .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
@@ -100,6 +101,7 @@
   grpc_completion_queue_shutdown(f->cq);
   drain_cq(f->cq);
   grpc_completion_queue_destroy(f->cq);
+  grpc_completion_queue_destroy(f->shutdown_cq);
 }
 
 /* Simple request via a server filter that always closes the stream.*/
diff --git a/test/core/end2end/tests/filter_latency.c b/test/core/end2end/tests/filter_latency.c
index d38ce22..e87e733 100644
--- a/test/core/end2end/tests/filter_latency.c
+++ b/test/core/end2end/tests/filter_latency.c
@@ -86,9 +86,10 @@
 
 static void shutdown_server(grpc_end2end_test_fixture *f) {
   if (!f->server) return;
-  grpc_server_shutdown_and_notify(f->server, f->cq, tag(1000));
-  GPR_ASSERT(grpc_completion_queue_pluck(
-                 f->cq, tag(1000), grpc_timeout_seconds_to_deadline(5), NULL)
+  grpc_server_shutdown_and_notify(f->server, f->shutdown_cq, tag(1000));
+  GPR_ASSERT(grpc_completion_queue_pluck(f->shutdown_cq, tag(1000),
+                                         grpc_timeout_seconds_to_deadline(5),
+                                         NULL)
                  .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
@@ -107,6 +108,7 @@
   grpc_completion_queue_shutdown(f->cq);
   drain_cq(f->cq);
   grpc_completion_queue_destroy(f->cq);
+  grpc_completion_queue_destroy(f->shutdown_cq);
 }
 
 // Simple request via a server filter that saves the reported latency value.
diff --git a/test/core/end2end/tests/graceful_server_shutdown.c b/test/core/end2end/tests/graceful_server_shutdown.c
index 182bb20..efb54a4 100644
--- a/test/core/end2end/tests/graceful_server_shutdown.c
+++ b/test/core/end2end/tests/graceful_server_shutdown.c
@@ -91,6 +91,8 @@
   grpc_completion_queue_shutdown(f->cq);
   drain_cq(f->cq);
   grpc_completion_queue_destroy(f->cq);
+  /* Note: shutdown_cq is not used in this test */
+  grpc_completion_queue_destroy(f->shutdown_cq);
 }
 
 static void test_early_server_shutdown_finishes_inflight_calls(
diff --git a/test/core/end2end/tests/high_initial_seqno.c b/test/core/end2end/tests/high_initial_seqno.c
index f534a19..ae364fd 100644
--- a/test/core/end2end/tests/high_initial_seqno.c
+++ b/test/core/end2end/tests/high_initial_seqno.c
@@ -78,9 +78,10 @@
 
 static void shutdown_server(grpc_end2end_test_fixture *f) {
   if (!f->server) return;
-  grpc_server_shutdown_and_notify(f->server, f->cq, tag(1000));
-  GPR_ASSERT(grpc_completion_queue_pluck(
-                 f->cq, tag(1000), grpc_timeout_seconds_to_deadline(5), NULL)
+  grpc_server_shutdown_and_notify(f->server, f->shutdown_cq, tag(1000));
+  GPR_ASSERT(grpc_completion_queue_pluck(f->shutdown_cq, tag(1000),
+                                         grpc_timeout_seconds_to_deadline(5),
+                                         NULL)
                  .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
@@ -99,6 +100,7 @@
   grpc_completion_queue_shutdown(f->cq);
   drain_cq(f->cq);
   grpc_completion_queue_destroy(f->cq);
+  grpc_completion_queue_destroy(f->shutdown_cq);
 }
 
 static void simple_request_body(grpc_end2end_test_config config,
diff --git a/test/core/end2end/tests/hpack_size.c b/test/core/end2end/tests/hpack_size.c
index 17ef204..15f5bb0 100644
--- a/test/core/end2end/tests/hpack_size.c
+++ b/test/core/end2end/tests/hpack_size.c
@@ -218,9 +218,10 @@
 
 static void shutdown_server(grpc_end2end_test_fixture *f) {
   if (!f->server) return;
-  grpc_server_shutdown_and_notify(f->server, f->cq, tag(1000));
-  GPR_ASSERT(grpc_completion_queue_pluck(
-                 f->cq, tag(1000), grpc_timeout_seconds_to_deadline(5), NULL)
+  grpc_server_shutdown_and_notify(f->server, f->shutdown_cq, tag(1000));
+  GPR_ASSERT(grpc_completion_queue_pluck(f->shutdown_cq, tag(1000),
+                                         grpc_timeout_seconds_to_deadline(5),
+                                         NULL)
                  .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
@@ -239,6 +240,7 @@
   grpc_completion_queue_shutdown(f->cq);
   drain_cq(f->cq);
   grpc_completion_queue_destroy(f->cq);
+  grpc_completion_queue_destroy(f->shutdown_cq);
 }
 
 static void simple_request_body(grpc_end2end_test_config config,
diff --git a/test/core/end2end/tests/idempotent_request.c b/test/core/end2end/tests/idempotent_request.c
index f80654d..9c1ec25 100644
--- a/test/core/end2end/tests/idempotent_request.c
+++ b/test/core/end2end/tests/idempotent_request.c
@@ -76,9 +76,10 @@
 
 static void shutdown_server(grpc_end2end_test_fixture *f) {
   if (!f->server) return;
-  grpc_server_shutdown_and_notify(f->server, f->cq, tag(1000));
-  GPR_ASSERT(grpc_completion_queue_pluck(
-                 f->cq, tag(1000), grpc_timeout_seconds_to_deadline(5), NULL)
+  grpc_server_shutdown_and_notify(f->server, f->shutdown_cq, tag(1000));
+  GPR_ASSERT(grpc_completion_queue_pluck(f->shutdown_cq, tag(1000),
+                                         grpc_timeout_seconds_to_deadline(5),
+                                         NULL)
                  .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
@@ -97,6 +98,7 @@
   grpc_completion_queue_shutdown(f->cq);
   drain_cq(f->cq);
   grpc_completion_queue_destroy(f->cq);
+  grpc_completion_queue_destroy(f->shutdown_cq);
 }
 
 static void simple_request_body(grpc_end2end_test_config config,
diff --git a/test/core/end2end/tests/invoke_large_request.c b/test/core/end2end/tests/invoke_large_request.c
index f4b93d9..a437fd7 100644
--- a/test/core/end2end/tests/invoke_large_request.c
+++ b/test/core/end2end/tests/invoke_large_request.c
@@ -71,9 +71,10 @@
 
 static void shutdown_server(grpc_end2end_test_fixture *f) {
   if (!f->server) return;
-  grpc_server_shutdown_and_notify(f->server, f->cq, tag(1000));
-  GPR_ASSERT(grpc_completion_queue_pluck(
-                 f->cq, tag(1000), grpc_timeout_seconds_to_deadline(5), NULL)
+  grpc_server_shutdown_and_notify(f->server, f->shutdown_cq, tag(1000));
+  GPR_ASSERT(grpc_completion_queue_pluck(f->shutdown_cq, tag(1000),
+                                         grpc_timeout_seconds_to_deadline(5),
+                                         NULL)
                  .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
@@ -92,6 +93,7 @@
   grpc_completion_queue_shutdown(f->cq);
   drain_cq(f->cq);
   grpc_completion_queue_destroy(f->cq);
+  grpc_completion_queue_destroy(f->shutdown_cq);
 }
 
 static grpc_slice large_slice(void) {
diff --git a/test/core/end2end/tests/keepalive_timeout.c b/test/core/end2end/tests/keepalive_timeout.c
index bf6ca0d..33a409b 100644
--- a/test/core/end2end/tests/keepalive_timeout.c
+++ b/test/core/end2end/tests/keepalive_timeout.c
@@ -78,8 +78,9 @@
 
 static void shutdown_server(grpc_end2end_test_fixture *f) {
   if (!f->server) return;
-  grpc_server_shutdown_and_notify(f->server, f->cq, tag(1000));
-  GPR_ASSERT(grpc_completion_queue_pluck(f->cq, tag(1000),
+
+  grpc_server_shutdown_and_notify(f->server, f->shutdown_cq, tag(1000));
+  GPR_ASSERT(grpc_completion_queue_pluck(f->shutdown_cq, tag(1000),
                                          five_seconds_from_now(), NULL)
                  .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
@@ -99,6 +100,7 @@
   grpc_completion_queue_shutdown(f->cq);
   drain_cq(f->cq);
   grpc_completion_queue_destroy(f->cq);
+  grpc_completion_queue_destroy(f->shutdown_cq);
 }
 
 /* Client sends a request, server replies with a payload, then waits for the
@@ -188,8 +190,6 @@
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   CQ_EXPECT_COMPLETION(cqv, tag(102), 1);
-  cq_verify(cqv);
-
   CQ_EXPECT_COMPLETION(cqv, tag(1), 1);
   cq_verify(cqv);
 
diff --git a/test/core/end2end/tests/large_metadata.c b/test/core/end2end/tests/large_metadata.c
index a670e41..cef03b6 100644
--- a/test/core/end2end/tests/large_metadata.c
+++ b/test/core/end2end/tests/large_metadata.c
@@ -74,9 +74,10 @@
 
 static void shutdown_server(grpc_end2end_test_fixture *f) {
   if (!f->server) return;
-  grpc_server_shutdown_and_notify(f->server, f->cq, tag(1000));
-  GPR_ASSERT(grpc_completion_queue_pluck(
-                 f->cq, tag(1000), grpc_timeout_seconds_to_deadline(5), NULL)
+  grpc_server_shutdown_and_notify(f->server, f->shutdown_cq, tag(1000));
+  GPR_ASSERT(grpc_completion_queue_pluck(f->shutdown_cq, tag(1000),
+                                         grpc_timeout_seconds_to_deadline(5),
+                                         NULL)
                  .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
@@ -95,6 +96,7 @@
   grpc_completion_queue_shutdown(f->cq);
   drain_cq(f->cq);
   grpc_completion_queue_destroy(f->cq);
+  grpc_completion_queue_destroy(f->shutdown_cq);
 }
 
 // Request with a large amount of metadata.
diff --git a/test/core/end2end/tests/load_reporting_hook.c b/test/core/end2end/tests/load_reporting_hook.c
index ea3dd23..c021bc0 100644
--- a/test/core/end2end/tests/load_reporting_hook.c
+++ b/test/core/end2end/tests/load_reporting_hook.c
@@ -101,9 +101,10 @@
 
 static void shutdown_server(grpc_end2end_test_fixture *f) {
   if (!f->server) return;
-  grpc_server_shutdown_and_notify(f->server, f->cq, tag(1000));
-  GPR_ASSERT(grpc_completion_queue_pluck(
-                 f->cq, tag(1000), grpc_timeout_seconds_to_deadline(5), NULL)
+  grpc_server_shutdown_and_notify(f->server, f->shutdown_cq, tag(1000));
+  GPR_ASSERT(grpc_completion_queue_pluck(f->shutdown_cq, tag(1000),
+                                         grpc_timeout_seconds_to_deadline(5),
+                                         NULL)
                  .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
@@ -122,13 +123,13 @@
   grpc_completion_queue_shutdown(f->cq);
   drain_cq(f->cq);
   grpc_completion_queue_destroy(f->cq);
+  grpc_completion_queue_destroy(f->shutdown_cq);
 }
 
 static void request_response_with_payload(
     grpc_end2end_test_config config, grpc_end2end_test_fixture f,
     const char *method_name, const char *request_msg, const char *response_msg,
-    grpc_metadata *initial_lr_metadata,
-    grpc_load_reporting_cost_context *cost_ctx) {
+    grpc_metadata *initial_lr_metadata, grpc_metadata *trailing_lr_metadata) {
   grpc_slice request_payload_slice = grpc_slice_from_static_string(request_msg);
   grpc_slice response_payload_slice =
       grpc_slice_from_static_string(response_msg);
@@ -241,8 +242,9 @@
   op->reserved = NULL;
   op++;
   op->op = GRPC_OP_SEND_STATUS_FROM_SERVER;
-  GPR_ASSERT(cost_ctx != NULL);
-  grpc_call_set_load_reporting_cost_context(s, cost_ctx);
+  GPR_ASSERT(trailing_lr_metadata != NULL);
+  op->data.send_status_from_server.trailing_metadata_count = 1;
+  op->data.send_status_from_server.trailing_metadata = trailing_lr_metadata;
   op->data.send_status_from_server.status = GRPC_STATUS_OK;
   grpc_slice status_details = grpc_slice_from_static_string("xyz");
   op->data.send_status_from_server.status_details = &status_details;
@@ -296,21 +298,21 @@
   const char *response_msg = "... and the response from the server";
 
   grpc_metadata initial_lr_metadata;
+  grpc_metadata trailing_lr_metadata;
 
   initial_lr_metadata.key = GRPC_MDSTR_LB_TOKEN;
   initial_lr_metadata.value = grpc_slice_from_static_string("client-token");
   memset(&initial_lr_metadata.internal_data, 0,
          sizeof(initial_lr_metadata.internal_data));
 
-  grpc_load_reporting_cost_context *cost_ctx = gpr_malloc(sizeof(*cost_ctx));
-  memset(cost_ctx, 0, sizeof(*cost_ctx));
-  cost_ctx->values_count = 1;
-  cost_ctx->values =
-      gpr_malloc(sizeof(*cost_ctx->values) * cost_ctx->values_count);
-  cost_ctx->values[0] = grpc_slice_from_static_string("cost-token");
+  trailing_lr_metadata.key = GRPC_MDSTR_LB_COST_BIN;
+  trailing_lr_metadata.value = grpc_slice_from_static_string("server-token");
+  memset(&trailing_lr_metadata.internal_data, 0,
+         sizeof(trailing_lr_metadata.internal_data));
 
   request_response_with_payload(config, f, method_name, request_msg,
-                                response_msg, &initial_lr_metadata, cost_ctx);
+                                response_msg, &initial_lr_metadata,
+                                &trailing_lr_metadata);
   end_test(&f);
   {
     grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
diff --git a/test/core/end2end/tests/max_concurrent_streams.c b/test/core/end2end/tests/max_concurrent_streams.c
index 2360138..6457016 100644
--- a/test/core/end2end/tests/max_concurrent_streams.c
+++ b/test/core/end2end/tests/max_concurrent_streams.c
@@ -74,9 +74,10 @@
 
 static void shutdown_server(grpc_end2end_test_fixture *f) {
   if (!f->server) return;
-  grpc_server_shutdown_and_notify(f->server, f->cq, tag(1000));
-  GPR_ASSERT(grpc_completion_queue_pluck(
-                 f->cq, tag(1000), grpc_timeout_seconds_to_deadline(5), NULL)
+  grpc_server_shutdown_and_notify(f->server, f->shutdown_cq, tag(1000));
+  GPR_ASSERT(grpc_completion_queue_pluck(f->shutdown_cq, tag(1000),
+                                         grpc_timeout_seconds_to_deadline(5),
+                                         NULL)
                  .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
@@ -95,6 +96,7 @@
   grpc_completion_queue_shutdown(f->cq);
   drain_cq(f->cq);
   grpc_completion_queue_destroy(f->cq);
+  grpc_completion_queue_destroy(f->shutdown_cq);
 }
 
 static void simple_request_body(grpc_end2end_test_config config,
diff --git a/test/core/end2end/tests/max_connection_age.c b/test/core/end2end/tests/max_connection_age.c
index 04bdb39..7b41fa5 100644
--- a/test/core/end2end/tests/max_connection_age.c
+++ b/test/core/end2end/tests/max_connection_age.c
@@ -89,6 +89,7 @@
   grpc_completion_queue_shutdown(f->cq);
   drain_cq(f->cq);
   grpc_completion_queue_destroy(f->cq);
+  grpc_completion_queue_destroy(f->shutdown_cq);
 }
 
 static void test_max_age_forcibly_close(grpc_end2end_test_config config) {
diff --git a/test/core/end2end/tests/max_connection_idle.c b/test/core/end2end/tests/max_connection_idle.c
index 98bc08c..ceb0294 100644
--- a/test/core/end2end/tests/max_connection_idle.c
+++ b/test/core/end2end/tests/max_connection_idle.c
@@ -242,6 +242,7 @@
   grpc_completion_queue_shutdown(f.cq);
   drain_cq(f.cq);
   grpc_completion_queue_destroy(f.cq);
+  grpc_completion_queue_destroy(f.shutdown_cq);
   config.tear_down_data(&f);
 
   cq_verifier_destroy(cqv);
diff --git a/test/core/end2end/tests/max_message_length.c b/test/core/end2end/tests/max_message_length.c
index ab58d9f..224c1cd 100644
--- a/test/core/end2end/tests/max_message_length.c
+++ b/test/core/end2end/tests/max_message_length.c
@@ -83,9 +83,10 @@
 
 static void shutdown_server(grpc_end2end_test_fixture *f) {
   if (!f->server) return;
-  grpc_server_shutdown_and_notify(f->server, f->cq, tag(1000));
-  GPR_ASSERT(grpc_completion_queue_pluck(
-                 f->cq, tag(1000), grpc_timeout_seconds_to_deadline(5), NULL)
+  grpc_server_shutdown_and_notify(f->server, f->shutdown_cq, tag(1000));
+  GPR_ASSERT(grpc_completion_queue_pluck(f->shutdown_cq, tag(1000),
+                                         grpc_timeout_seconds_to_deadline(5),
+                                         NULL)
                  .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
@@ -104,6 +105,7 @@
   grpc_completion_queue_shutdown(f->cq);
   drain_cq(f->cq);
   grpc_completion_queue_destroy(f->cq);
+  grpc_completion_queue_destroy(f->shutdown_cq);
 }
 
 // Test with request larger than the limit.
@@ -272,7 +274,7 @@
   GPR_ASSERT(was_cancelled == 1);
 
 done:
-  GPR_ASSERT(status == GRPC_STATUS_INVALID_ARGUMENT);
+  GPR_ASSERT(status == GRPC_STATUS_RESOURCE_EXHAUSTED);
   GPR_ASSERT(
       grpc_slice_str_cmp(
           details, send_limit
@@ -466,7 +468,7 @@
   GPR_ASSERT(0 ==
              grpc_slice_str_cmp(call_details.host, "foo.test.google.fr:1234"));
 
-  GPR_ASSERT(status == GRPC_STATUS_INVALID_ARGUMENT);
+  GPR_ASSERT(status == GRPC_STATUS_RESOURCE_EXHAUSTED);
   GPR_ASSERT(
       grpc_slice_str_cmp(
           details, send_limit
diff --git a/test/core/end2end/tests/negative_deadline.c b/test/core/end2end/tests/negative_deadline.c
index e7448bd..52c1a72 100644
--- a/test/core/end2end/tests/negative_deadline.c
+++ b/test/core/end2end/tests/negative_deadline.c
@@ -76,9 +76,10 @@
 
 static void shutdown_server(grpc_end2end_test_fixture *f) {
   if (!f->server) return;
-  grpc_server_shutdown_and_notify(f->server, f->cq, tag(1000));
-  GPR_ASSERT(grpc_completion_queue_pluck(
-                 f->cq, tag(1000), grpc_timeout_seconds_to_deadline(5), NULL)
+  grpc_server_shutdown_and_notify(f->server, f->shutdown_cq, tag(1000));
+  GPR_ASSERT(grpc_completion_queue_pluck(f->shutdown_cq, tag(1000),
+                                         grpc_timeout_seconds_to_deadline(5),
+                                         NULL)
                  .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
@@ -97,6 +98,7 @@
   grpc_completion_queue_shutdown(f->cq);
   drain_cq(f->cq);
   grpc_completion_queue_destroy(f->cq);
+  grpc_completion_queue_destroy(f->shutdown_cq);
 }
 
 static void simple_request_body(grpc_end2end_test_config config,
diff --git a/test/core/end2end/tests/network_status_change.c b/test/core/end2end/tests/network_status_change.c
index 1a5f2b2..a810489 100644
--- a/test/core/end2end/tests/network_status_change.c
+++ b/test/core/end2end/tests/network_status_change.c
@@ -77,9 +77,10 @@
 
 static void shutdown_server(grpc_end2end_test_fixture *f) {
   if (!f->server) return;
-  grpc_server_shutdown_and_notify(f->server, f->cq, tag(1000));
-  GPR_ASSERT(grpc_completion_queue_pluck(
-                 f->cq, tag(1000), grpc_timeout_seconds_to_deadline(5), NULL)
+  grpc_server_shutdown_and_notify(f->server, f->shutdown_cq, tag(1000));
+  GPR_ASSERT(grpc_completion_queue_pluck(f->shutdown_cq, tag(1000),
+                                         grpc_timeout_seconds_to_deadline(5),
+                                         NULL)
                  .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
@@ -98,6 +99,7 @@
   grpc_completion_queue_shutdown(f->cq);
   drain_cq(f->cq);
   grpc_completion_queue_destroy(f->cq);
+  grpc_completion_queue_destroy(f->shutdown_cq);
 }
 
 /* Client sends a request with payload, server reads then returns status. */
diff --git a/test/core/end2end/tests/no_logging.c b/test/core/end2end/tests/no_logging.c
index 683d646..44e8188 100644
--- a/test/core/end2end/tests/no_logging.c
+++ b/test/core/end2end/tests/no_logging.c
@@ -104,9 +104,10 @@
 
 static void shutdown_server(grpc_end2end_test_fixture *f) {
   if (!f->server) return;
-  grpc_server_shutdown_and_notify(f->server, f->cq, tag(1000));
-  GPR_ASSERT(grpc_completion_queue_pluck(
-                 f->cq, tag(1000), grpc_timeout_seconds_to_deadline(5), NULL)
+  grpc_server_shutdown_and_notify(f->server, f->shutdown_cq, tag(1000));
+  GPR_ASSERT(grpc_completion_queue_pluck(f->shutdown_cq, tag(1000),
+                                         grpc_timeout_seconds_to_deadline(5),
+                                         NULL)
                  .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
@@ -125,6 +126,7 @@
   grpc_completion_queue_shutdown(f->cq);
   drain_cq(f->cq);
   grpc_completion_queue_destroy(f->cq);
+  grpc_completion_queue_destroy(f->shutdown_cq);
 }
 
 static void simple_request_body(grpc_end2end_test_config config,
diff --git a/test/core/end2end/tests/no_op.c b/test/core/end2end/tests/no_op.c
index 698d8fb..0d98fc9 100644
--- a/test/core/end2end/tests/no_op.c
+++ b/test/core/end2end/tests/no_op.c
@@ -74,9 +74,10 @@
 
 static void shutdown_server(grpc_end2end_test_fixture *f) {
   if (!f->server) return;
-  grpc_server_shutdown_and_notify(f->server, f->cq, tag(1000));
-  GPR_ASSERT(grpc_completion_queue_pluck(
-                 f->cq, tag(1000), grpc_timeout_seconds_to_deadline(5), NULL)
+  grpc_server_shutdown_and_notify(f->server, f->shutdown_cq, tag(1000));
+  GPR_ASSERT(grpc_completion_queue_pluck(f->shutdown_cq, tag(1000),
+                                         grpc_timeout_seconds_to_deadline(5),
+                                         NULL)
                  .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
@@ -95,6 +96,7 @@
   grpc_completion_queue_shutdown(f->cq);
   drain_cq(f->cq);
   grpc_completion_queue_destroy(f->cq);
+  grpc_completion_queue_destroy(f->shutdown_cq);
 }
 
 static void test_no_op(grpc_end2end_test_config config) {
diff --git a/test/core/end2end/tests/payload.c b/test/core/end2end/tests/payload.c
index 5751b80..df9004f 100644
--- a/test/core/end2end/tests/payload.c
+++ b/test/core/end2end/tests/payload.c
@@ -74,9 +74,10 @@
 
 static void shutdown_server(grpc_end2end_test_fixture *f) {
   if (!f->server) return;
-  grpc_server_shutdown_and_notify(f->server, f->cq, tag(1000));
-  GPR_ASSERT(grpc_completion_queue_pluck(
-                 f->cq, tag(1000), grpc_timeout_seconds_to_deadline(5), NULL)
+  grpc_server_shutdown_and_notify(f->server, f->shutdown_cq, tag(1000));
+  GPR_ASSERT(grpc_completion_queue_pluck(f->shutdown_cq, tag(1000),
+                                         grpc_timeout_seconds_to_deadline(5),
+                                         NULL)
                  .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
@@ -95,6 +96,7 @@
   grpc_completion_queue_shutdown(f->cq);
   drain_cq(f->cq);
   grpc_completion_queue_destroy(f->cq);
+  grpc_completion_queue_destroy(f->shutdown_cq);
 }
 
 /* Creates and returns a grpc_slice containing random alphanumeric characters.
diff --git a/test/core/end2end/tests/ping.c b/test/core/end2end/tests/ping.c
index c51c499..027c17e 100644
--- a/test/core/end2end/tests/ping.c
+++ b/test/core/end2end/tests/ping.c
@@ -112,6 +112,9 @@
   grpc_channel_destroy(f.client);
   grpc_completion_queue_shutdown(f.cq);
   grpc_completion_queue_destroy(f.cq);
+
+  /* f.shutdown_cq is not used in this test */
+  grpc_completion_queue_destroy(f.shutdown_cq);
   config.tear_down_data(&f);
 
   cq_verifier_destroy(cqv);
diff --git a/test/core/end2end/tests/ping_pong_streaming.c b/test/core/end2end/tests/ping_pong_streaming.c
index cd81ce2..fc5a0a5 100644
--- a/test/core/end2end/tests/ping_pong_streaming.c
+++ b/test/core/end2end/tests/ping_pong_streaming.c
@@ -74,9 +74,10 @@
 
 static void shutdown_server(grpc_end2end_test_fixture *f) {
   if (!f->server) return;
-  grpc_server_shutdown_and_notify(f->server, f->cq, tag(1000));
-  GPR_ASSERT(grpc_completion_queue_pluck(
-                 f->cq, tag(1000), grpc_timeout_seconds_to_deadline(5), NULL)
+  grpc_server_shutdown_and_notify(f->server, f->shutdown_cq, tag(1000));
+  GPR_ASSERT(grpc_completion_queue_pluck(f->shutdown_cq, tag(1000),
+                                         grpc_timeout_seconds_to_deadline(5),
+                                         NULL)
                  .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
@@ -95,6 +96,7 @@
   grpc_completion_queue_shutdown(f->cq);
   drain_cq(f->cq);
   grpc_completion_queue_destroy(f->cq);
+  grpc_completion_queue_destroy(f->shutdown_cq);
 }
 
 /* Client pings and server pongs. Repeat messages rounds before finishing. */
diff --git a/test/core/end2end/tests/registered_call.c b/test/core/end2end/tests/registered_call.c
index 242add3..2580403 100644
--- a/test/core/end2end/tests/registered_call.c
+++ b/test/core/end2end/tests/registered_call.c
@@ -76,9 +76,10 @@
 
 static void shutdown_server(grpc_end2end_test_fixture *f) {
   if (!f->server) return;
-  grpc_server_shutdown_and_notify(f->server, f->cq, tag(1000));
-  GPR_ASSERT(grpc_completion_queue_pluck(
-                 f->cq, tag(1000), grpc_timeout_seconds_to_deadline(5), NULL)
+  grpc_server_shutdown_and_notify(f->server, f->shutdown_cq, tag(1000));
+  GPR_ASSERT(grpc_completion_queue_pluck(f->shutdown_cq, tag(1000),
+                                         grpc_timeout_seconds_to_deadline(5),
+                                         NULL)
                  .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
@@ -97,6 +98,7 @@
   grpc_completion_queue_shutdown(f->cq);
   drain_cq(f->cq);
   grpc_completion_queue_destroy(f->cq);
+  grpc_completion_queue_destroy(f->shutdown_cq);
 }
 
 static void simple_request_body(grpc_end2end_test_config config,
diff --git a/test/core/end2end/tests/request_with_flags.c b/test/core/end2end/tests/request_with_flags.c
index 10ecf5b..e913fa4 100644
--- a/test/core/end2end/tests/request_with_flags.c
+++ b/test/core/end2end/tests/request_with_flags.c
@@ -75,9 +75,10 @@
 
 static void shutdown_server(grpc_end2end_test_fixture *f) {
   if (!f->server) return;
-  grpc_server_shutdown_and_notify(f->server, f->cq, tag(1000));
-  GPR_ASSERT(grpc_completion_queue_pluck(
-                 f->cq, tag(1000), grpc_timeout_seconds_to_deadline(5), NULL)
+  grpc_server_shutdown_and_notify(f->server, f->shutdown_cq, tag(1000));
+  GPR_ASSERT(grpc_completion_queue_pluck(f->shutdown_cq, tag(1000),
+                                         grpc_timeout_seconds_to_deadline(5),
+                                         NULL)
                  .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
@@ -96,6 +97,7 @@
   grpc_completion_queue_shutdown(f->cq);
   drain_cq(f->cq);
   grpc_completion_queue_destroy(f->cq);
+  grpc_completion_queue_destroy(f->shutdown_cq);
 }
 
 static void test_invoke_request_with_flags(
diff --git a/test/core/end2end/tests/request_with_payload.c b/test/core/end2end/tests/request_with_payload.c
index 4eb3399..17c0761 100644
--- a/test/core/end2end/tests/request_with_payload.c
+++ b/test/core/end2end/tests/request_with_payload.c
@@ -74,9 +74,10 @@
 
 static void shutdown_server(grpc_end2end_test_fixture *f) {
   if (!f->server) return;
-  grpc_server_shutdown_and_notify(f->server, f->cq, tag(1000));
-  GPR_ASSERT(grpc_completion_queue_pluck(
-                 f->cq, tag(1000), grpc_timeout_seconds_to_deadline(5), NULL)
+  grpc_server_shutdown_and_notify(f->server, f->shutdown_cq, tag(1000));
+  GPR_ASSERT(grpc_completion_queue_pluck(f->shutdown_cq, tag(1000),
+                                         grpc_timeout_seconds_to_deadline(5),
+                                         NULL)
                  .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
@@ -95,6 +96,7 @@
   grpc_completion_queue_shutdown(f->cq);
   drain_cq(f->cq);
   grpc_completion_queue_destroy(f->cq);
+  grpc_completion_queue_destroy(f->shutdown_cq);
 }
 
 /* Client sends a request with payload, server reads then returns status. */
diff --git a/test/core/end2end/tests/resource_quota_server.c b/test/core/end2end/tests/resource_quota_server.c
index 4d3ce1c..b5bc399 100644
--- a/test/core/end2end/tests/resource_quota_server.c
+++ b/test/core/end2end/tests/resource_quota_server.c
@@ -74,9 +74,10 @@
 
 static void shutdown_server(grpc_end2end_test_fixture *f) {
   if (!f->server) return;
-  grpc_server_shutdown_and_notify(f->server, f->cq, tag(1000));
-  GPR_ASSERT(grpc_completion_queue_pluck(
-                 f->cq, tag(1000), grpc_timeout_seconds_to_deadline(5), NULL)
+  grpc_server_shutdown_and_notify(f->server, f->shutdown_cq, tag(1000));
+  GPR_ASSERT(grpc_completion_queue_pluck(f->shutdown_cq, tag(1000),
+                                         grpc_timeout_seconds_to_deadline(5),
+                                         NULL)
                  .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
@@ -95,6 +96,7 @@
   grpc_completion_queue_shutdown(f->cq);
   drain_cq(f->cq);
   grpc_completion_queue_destroy(f->cq);
+  grpc_completion_queue_destroy(f->shutdown_cq);
 }
 
 /* Creates and returns a grpc_slice containing random alphanumeric characters.
@@ -203,7 +205,7 @@
     op = ops;
     op->op = GRPC_OP_SEND_INITIAL_METADATA;
     op->data.send_initial_metadata.count = 0;
-    op->flags = 0;
+    op->flags = GRPC_INITIAL_METADATA_WAIT_FOR_READY;
     op->reserved = NULL;
     op++;
     op->op = GRPC_OP_SEND_MESSAGE;
diff --git a/test/core/end2end/tests/server_finishes_request.c b/test/core/end2end/tests/server_finishes_request.c
index 88bc90e..990f063 100644
--- a/test/core/end2end/tests/server_finishes_request.c
+++ b/test/core/end2end/tests/server_finishes_request.c
@@ -76,9 +76,10 @@
 
 static void shutdown_server(grpc_end2end_test_fixture *f) {
   if (!f->server) return;
-  grpc_server_shutdown_and_notify(f->server, f->cq, tag(1000));
-  GPR_ASSERT(grpc_completion_queue_pluck(
-                 f->cq, tag(1000), grpc_timeout_seconds_to_deadline(5), NULL)
+  grpc_server_shutdown_and_notify(f->server, f->shutdown_cq, tag(1000));
+  GPR_ASSERT(grpc_completion_queue_pluck(f->shutdown_cq, tag(1000),
+                                         grpc_timeout_seconds_to_deadline(5),
+                                         NULL)
                  .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
@@ -97,6 +98,7 @@
   grpc_completion_queue_shutdown(f->cq);
   drain_cq(f->cq);
   grpc_completion_queue_destroy(f->cq);
+  grpc_completion_queue_destroy(f->shutdown_cq);
 }
 
 static void simple_request_body(grpc_end2end_test_config config,
diff --git a/test/core/end2end/tests/shutdown_finishes_calls.c b/test/core/end2end/tests/shutdown_finishes_calls.c
index 6f9421d..2385423 100644
--- a/test/core/end2end/tests/shutdown_finishes_calls.c
+++ b/test/core/end2end/tests/shutdown_finishes_calls.c
@@ -84,6 +84,8 @@
   grpc_completion_queue_shutdown(f->cq);
   drain_cq(f->cq);
   grpc_completion_queue_destroy(f->cq);
+  /* f->shutdown_cq is not used in this test */
+  grpc_completion_queue_destroy(f->shutdown_cq);
 }
 
 static void test_early_server_shutdown_finishes_inflight_calls(
diff --git a/test/core/end2end/tests/shutdown_finishes_tags.c b/test/core/end2end/tests/shutdown_finishes_tags.c
index 51a2423..008f72e 100644
--- a/test/core/end2end/tests/shutdown_finishes_tags.c
+++ b/test/core/end2end/tests/shutdown_finishes_tags.c
@@ -84,6 +84,8 @@
   grpc_completion_queue_shutdown(f->cq);
   drain_cq(f->cq);
   grpc_completion_queue_destroy(f->cq);
+  /* f->shutdown_cq is not used in this test */
+  grpc_completion_queue_destroy(f->shutdown_cq);
 }
 
 static void test_early_server_shutdown_finishes_tags(
diff --git a/test/core/end2end/tests/simple_cacheable_request.c b/test/core/end2end/tests/simple_cacheable_request.c
index 4f1013a..d0c292c 100644
--- a/test/core/end2end/tests/simple_cacheable_request.c
+++ b/test/core/end2end/tests/simple_cacheable_request.c
@@ -76,9 +76,10 @@
 
 static void shutdown_server(grpc_end2end_test_fixture *f) {
   if (!f->server) return;
-  grpc_server_shutdown_and_notify(f->server, f->cq, tag(1000));
-  GPR_ASSERT(grpc_completion_queue_pluck(
-                 f->cq, tag(1000), grpc_timeout_seconds_to_deadline(5), NULL)
+  grpc_server_shutdown_and_notify(f->server, f->shutdown_cq, tag(1000));
+  GPR_ASSERT(grpc_completion_queue_pluck(f->shutdown_cq, tag(1000),
+                                         grpc_timeout_seconds_to_deadline(5),
+                                         NULL)
                  .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
@@ -97,6 +98,7 @@
   grpc_completion_queue_shutdown(f->cq);
   drain_cq(f->cq);
   grpc_completion_queue_destroy(f->cq);
+  grpc_completion_queue_destroy(f->shutdown_cq);
 }
 
 /* Request/response with metadata and payload.*/
diff --git a/test/core/end2end/tests/simple_delayed_request.c b/test/core/end2end/tests/simple_delayed_request.c
index 978dff0..c8b88de 100644
--- a/test/core/end2end/tests/simple_delayed_request.c
+++ b/test/core/end2end/tests/simple_delayed_request.c
@@ -62,9 +62,10 @@
 
 static void shutdown_server(grpc_end2end_test_fixture *f) {
   if (!f->server) return;
-  grpc_server_shutdown_and_notify(f->server, f->cq, tag(1000));
-  GPR_ASSERT(grpc_completion_queue_pluck(
-                 f->cq, tag(1000), grpc_timeout_seconds_to_deadline(5), NULL)
+  grpc_server_shutdown_and_notify(f->server, f->shutdown_cq, tag(1000));
+  GPR_ASSERT(grpc_completion_queue_pluck(f->shutdown_cq, tag(1000),
+                                         grpc_timeout_seconds_to_deadline(5),
+                                         NULL)
                  .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
@@ -83,6 +84,7 @@
   grpc_completion_queue_shutdown(f->cq);
   drain_cq(f->cq);
   grpc_completion_queue_destroy(f->cq);
+  grpc_completion_queue_destroy(f->shutdown_cq);
 }
 
 static void simple_delayed_request_body(grpc_end2end_test_config config,
diff --git a/test/core/end2end/tests/simple_metadata.c b/test/core/end2end/tests/simple_metadata.c
index 83d1037..367f0b7 100644
--- a/test/core/end2end/tests/simple_metadata.c
+++ b/test/core/end2end/tests/simple_metadata.c
@@ -74,9 +74,10 @@
 
 static void shutdown_server(grpc_end2end_test_fixture *f) {
   if (!f->server) return;
-  grpc_server_shutdown_and_notify(f->server, f->cq, tag(1000));
-  GPR_ASSERT(grpc_completion_queue_pluck(
-                 f->cq, tag(1000), grpc_timeout_seconds_to_deadline(5), NULL)
+  grpc_server_shutdown_and_notify(f->server, f->shutdown_cq, tag(1000));
+  GPR_ASSERT(grpc_completion_queue_pluck(f->shutdown_cq, tag(1000),
+                                         grpc_timeout_seconds_to_deadline(5),
+                                         NULL)
                  .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
@@ -95,6 +96,7 @@
   grpc_completion_queue_shutdown(f->cq);
   drain_cq(f->cq);
   grpc_completion_queue_destroy(f->cq);
+  grpc_completion_queue_destroy(f->shutdown_cq);
 }
 
 /* Request/response with metadata and payload.*/
diff --git a/test/core/end2end/tests/simple_request.c b/test/core/end2end/tests/simple_request.c
index 31bfef4..0f19fd0 100644
--- a/test/core/end2end/tests/simple_request.c
+++ b/test/core/end2end/tests/simple_request.c
@@ -76,9 +76,10 @@
 
 static void shutdown_server(grpc_end2end_test_fixture *f) {
   if (!f->server) return;
-  grpc_server_shutdown_and_notify(f->server, f->cq, tag(1000));
-  GPR_ASSERT(grpc_completion_queue_pluck(
-                 f->cq, tag(1000), grpc_timeout_seconds_to_deadline(5), NULL)
+  grpc_server_shutdown_and_notify(f->server, f->shutdown_cq, tag(1000));
+  GPR_ASSERT(grpc_completion_queue_pluck(f->shutdown_cq, tag(1000),
+                                         grpc_timeout_seconds_to_deadline(5),
+                                         NULL)
                  .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
@@ -97,6 +98,7 @@
   grpc_completion_queue_shutdown(f->cq);
   drain_cq(f->cq);
   grpc_completion_queue_destroy(f->cq);
+  grpc_completion_queue_destroy(f->shutdown_cq);
 }
 
 static void simple_request_body(grpc_end2end_test_config config,
diff --git a/test/core/end2end/tests/streaming_error_response.c b/test/core/end2end/tests/streaming_error_response.c
index c652d94..0946552 100644
--- a/test/core/end2end/tests/streaming_error_response.c
+++ b/test/core/end2end/tests/streaming_error_response.c
@@ -79,9 +79,10 @@
 
 static void shutdown_server(grpc_end2end_test_fixture *f) {
   if (!f->server) return;
-  grpc_server_shutdown_and_notify(f->server, f->cq, tag(1000));
-  GPR_ASSERT(grpc_completion_queue_pluck(
-                 f->cq, tag(1000), grpc_timeout_seconds_to_deadline(5), NULL)
+  grpc_server_shutdown_and_notify(f->server, f->shutdown_cq, tag(1000));
+  GPR_ASSERT(grpc_completion_queue_pluck(f->shutdown_cq, tag(1000),
+                                         grpc_timeout_seconds_to_deadline(5),
+                                         NULL)
                  .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
@@ -100,6 +101,7 @@
   grpc_completion_queue_shutdown(f->cq);
   drain_cq(f->cq);
   grpc_completion_queue_destroy(f->cq);
+  grpc_completion_queue_destroy(f->shutdown_cq);
 }
 
 /* Client sends a request with payload, server reads then returns status. */
@@ -182,6 +184,9 @@
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   CQ_EXPECT_COMPLETION(cqv, tag(102), 1);
+  if (!request_status_early) {
+    CQ_EXPECT_COMPLETION(cqv, tag(1), 1);
+  }
   cq_verify(cqv);
 
   memset(ops, 0, sizeof(ops));
@@ -193,9 +198,6 @@
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   CQ_EXPECT_COMPLETION(cqv, tag(103), 1);
-  if (!request_status_early) {
-    CQ_EXPECT_COMPLETION(cqv, tag(1), 1);
-  }
   cq_verify(cqv);
 
   memset(ops, 0, sizeof(ops));
diff --git a/test/core/end2end/tests/trailing_metadata.c b/test/core/end2end/tests/trailing_metadata.c
index 3cbffdf..7804626 100644
--- a/test/core/end2end/tests/trailing_metadata.c
+++ b/test/core/end2end/tests/trailing_metadata.c
@@ -74,9 +74,10 @@
 
 static void shutdown_server(grpc_end2end_test_fixture *f) {
   if (!f->server) return;
-  grpc_server_shutdown_and_notify(f->server, f->cq, tag(1000));
-  GPR_ASSERT(grpc_completion_queue_pluck(
-                 f->cq, tag(1000), grpc_timeout_seconds_to_deadline(5), NULL)
+  grpc_server_shutdown_and_notify(f->server, f->shutdown_cq, tag(1000));
+  GPR_ASSERT(grpc_completion_queue_pluck(f->shutdown_cq, tag(1000),
+                                         grpc_timeout_seconds_to_deadline(5),
+                                         NULL)
                  .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
@@ -95,6 +96,7 @@
   grpc_completion_queue_shutdown(f->cq);
   drain_cq(f->cq);
   grpc_completion_queue_destroy(f->cq);
+  grpc_completion_queue_destroy(f->shutdown_cq);
 }
 
 /* Request/response with metadata and payload.*/
diff --git a/test/core/end2end/tests/write_buffering.c b/test/core/end2end/tests/write_buffering.c
index 2d4142b..e937912 100644
--- a/test/core/end2end/tests/write_buffering.c
+++ b/test/core/end2end/tests/write_buffering.c
@@ -74,9 +74,10 @@
 
 static void shutdown_server(grpc_end2end_test_fixture *f) {
   if (!f->server) return;
-  grpc_server_shutdown_and_notify(f->server, f->cq, tag(1000));
-  GPR_ASSERT(grpc_completion_queue_pluck(
-                 f->cq, tag(1000), grpc_timeout_seconds_to_deadline(5), NULL)
+  grpc_server_shutdown_and_notify(f->server, f->shutdown_cq, tag(1000));
+  GPR_ASSERT(grpc_completion_queue_pluck(f->shutdown_cq, tag(1000),
+                                         grpc_timeout_seconds_to_deadline(5),
+                                         NULL)
                  .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
@@ -95,6 +96,7 @@
   grpc_completion_queue_shutdown(f->cq);
   drain_cq(f->cq);
   grpc_completion_queue_destroy(f->cq);
+  grpc_completion_queue_destroy(f->shutdown_cq);
 }
 
 /* Client sends a request with payload, server reads then returns status. */
diff --git a/test/core/end2end/tests/write_buffering_at_end.c b/test/core/end2end/tests/write_buffering_at_end.c
index e61343e..42024cf 100644
--- a/test/core/end2end/tests/write_buffering_at_end.c
+++ b/test/core/end2end/tests/write_buffering_at_end.c
@@ -74,9 +74,10 @@
 
 static void shutdown_server(grpc_end2end_test_fixture *f) {
   if (!f->server) return;
-  grpc_server_shutdown_and_notify(f->server, f->cq, tag(1000));
-  GPR_ASSERT(grpc_completion_queue_pluck(
-                 f->cq, tag(1000), grpc_timeout_seconds_to_deadline(5), NULL)
+  grpc_server_shutdown_and_notify(f->server, f->shutdown_cq, tag(1000));
+  GPR_ASSERT(grpc_completion_queue_pluck(f->shutdown_cq, tag(1000),
+                                         grpc_timeout_seconds_to_deadline(5),
+                                         NULL)
                  .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
@@ -95,6 +96,7 @@
   grpc_completion_queue_shutdown(f->cq);
   drain_cq(f->cq);
   grpc_completion_queue_destroy(f->cq);
+  grpc_completion_queue_destroy(f->shutdown_cq);
 }
 
 /* Client sends a request with payload, server reads then returns status. */
diff --git a/test/core/fling/client.c b/test/core/fling/client.c
index 85bab6d..ecb73cf 100644
--- a/test/core/fling/client.c
+++ b/test/core/fling/client.c
@@ -208,7 +208,7 @@
   }
 
   channel = grpc_insecure_channel_create(target, NULL, NULL);
-  cq = grpc_completion_queue_create(NULL);
+  cq = grpc_completion_queue_create_for_next(NULL);
   the_buffer = grpc_raw_byte_buffer_create(&slice, (size_t)payload_size);
   histogram = gpr_histogram_create(0.01, 60e9);
 
diff --git a/test/core/fling/server.c b/test/core/fling/server.c
index 7ea54b1..7edff3d 100644
--- a/test/core/fling/server.c
+++ b/test/core/fling/server.c
@@ -185,6 +185,7 @@
   call_state *s;
   char *addr_buf = NULL;
   gpr_cmdline *cl;
+  grpc_completion_queue *shutdown_cq;
   int shutdown_started = 0;
   int shutdown_finished = 0;
 
@@ -214,7 +215,7 @@
   }
   gpr_log(GPR_INFO, "creating server on: %s", addr);
 
-  cq = grpc_completion_queue_create(NULL);
+  cq = grpc_completion_queue_create_for_next(NULL);
   if (secure) {
     grpc_ssl_pem_key_cert_pair pem_key_cert_pair = {test_server1_key,
                                                     test_server1_cert};
@@ -242,10 +243,16 @@
   while (!shutdown_finished) {
     if (got_sigint && !shutdown_started) {
       gpr_log(GPR_INFO, "Shutting down due to SIGINT");
-      grpc_server_shutdown_and_notify(server, cq, tag(1000));
-      GPR_ASSERT(grpc_completion_queue_pluck(
-                     cq, tag(1000), grpc_timeout_seconds_to_deadline(5), NULL)
-                     .type == GRPC_OP_COMPLETE);
+
+      shutdown_cq = grpc_completion_queue_create_for_pluck(NULL);
+      grpc_server_shutdown_and_notify(server, shutdown_cq, tag(1000));
+
+      GPR_ASSERT(
+          grpc_completion_queue_pluck(shutdown_cq, tag(1000),
+                                      grpc_timeout_seconds_to_deadline(5), NULL)
+              .type == GRPC_OP_COMPLETE);
+      grpc_completion_queue_destroy(shutdown_cq);
+
       grpc_completion_queue_shutdown(cq);
       shutdown_started = 1;
     }
diff --git a/test/core/handshake/client_ssl.c b/test/core/handshake/client_ssl.c
index f291d09..f7fa919 100644
--- a/test/core/handshake/client_ssl.c
+++ b/test/core/handshake/client_ssl.c
@@ -289,7 +289,8 @@
   // completed and we know that the client's ALPN list satisfied the server.
   int retries = 10;
   grpc_connectivity_state state = GRPC_CHANNEL_IDLE;
-  grpc_completion_queue *cq = grpc_completion_queue_create(NULL);
+  grpc_completion_queue *cq = grpc_completion_queue_create_for_next(NULL);
+
   while (state != GRPC_CHANNEL_READY && retries-- > 0) {
     grpc_channel_watch_connectivity_state(
         channel, state, grpc_timeout_seconds_to_deadline(3), cq, NULL);
diff --git a/test/core/handshake/server_ssl.c b/test/core/handshake/server_ssl.c
index e568a37..30f6474 100644
--- a/test/core/handshake/server_ssl.c
+++ b/test/core/handshake/server_ssl.c
@@ -104,7 +104,7 @@
   GPR_ASSERT(grpc_server_add_secure_http2_port(server, addr, ssl_creds));
   free(addr);
 
-  grpc_completion_queue *cq = grpc_completion_queue_create(NULL);
+  grpc_completion_queue *cq = grpc_completion_queue_create_for_next(NULL);
 
   grpc_server_register_completion_queue(server, cq, NULL);
   grpc_server_start(server);
diff --git a/test/core/iomgr/udp_server_test.c b/test/core/iomgr/udp_server_test.c
index 12d8406..1f1696a 100644
--- a/test/core/iomgr/udp_server_test.c
+++ b/test/core/iomgr/udp_server_test.c
@@ -91,7 +91,7 @@
 }
 
 static void on_fd_orphaned(grpc_exec_ctx *exec_ctx, grpc_fd *emfd,
-                           void *user_data) {
+                           grpc_closure *closure, void *user_data) {
   gpr_log(GPR_INFO, "gRPC FD about to be orphaned: %d",
           grpc_fd_wrapped_fd(emfd));
   g_number_of_orphan_calls++;
@@ -228,9 +228,9 @@
   grpc_udp_server_destroy(&exec_ctx, s, NULL);
   grpc_exec_ctx_finish(&exec_ctx);
 
-  /* The server had a single FD, which is orphaned once in *
-   * deactivated_all_ports, and once in grpc_udp_server_destroy. */
-  GPR_ASSERT(g_number_of_orphan_calls == 2);
+  /* The server had a single FD, which is orphaned exactly once in *
+   * grpc_udp_server_destroy. */
+  GPR_ASSERT(g_number_of_orphan_calls == 1);
 }
 
 static void test_receive(int number_of_clients) {
@@ -297,9 +297,9 @@
   grpc_udp_server_destroy(&exec_ctx, s, NULL);
   grpc_exec_ctx_finish(&exec_ctx);
 
-  /* The server had a single FD, which is orphaned once in *
-   * deactivated_all_ports, and once in grpc_udp_server_destroy. */
-  GPR_ASSERT(g_number_of_orphan_calls == 2);
+  /* The server had a single FD, which is orphaned exactly once in *
+   * grpc_udp_server_destroy. */
+  GPR_ASSERT(g_number_of_orphan_calls == 1);
 
   /* The write callback should have fired a few times. */
   GPR_ASSERT(g_number_of_writes > 0);
diff --git a/test/core/memory_usage/client.c b/test/core/memory_usage/client.c
index 51ea51b..fcdc161 100644
--- a/test/core/memory_usage/client.c
+++ b/test/core/memory_usage/client.c
@@ -223,7 +223,7 @@
     calls[k].details = grpc_empty_slice();
   }
 
-  cq = grpc_completion_queue_create(NULL);
+  cq = grpc_completion_queue_create_for_next(NULL);
 
   struct grpc_memory_counters client_channel_start =
       grpc_memory_counters_snapshot();
diff --git a/test/core/memory_usage/server.c b/test/core/memory_usage/server.c
index ab059c2..44c5488 100644
--- a/test/core/memory_usage/server.c
+++ b/test/core/memory_usage/server.c
@@ -161,6 +161,7 @@
   grpc_event ev;
   char *addr_buf = NULL;
   gpr_cmdline *cl;
+  grpc_completion_queue *shutdown_cq;
   int shutdown_started = 0;
   int shutdown_finished = 0;
 
@@ -188,7 +189,7 @@
   }
   gpr_log(GPR_INFO, "creating server on: %s", addr);
 
-  cq = grpc_completion_queue_create(NULL);
+  cq = grpc_completion_queue_create_for_next(NULL);
 
   struct grpc_memory_counters before_server_create =
       grpc_memory_counters_snapshot();
@@ -230,10 +231,14 @@
   while (!shutdown_finished) {
     if (got_sigint && !shutdown_started) {
       gpr_log(GPR_INFO, "Shutting down due to SIGINT");
-      grpc_server_shutdown_and_notify(server, cq, tag(1000));
-      GPR_ASSERT(grpc_completion_queue_pluck(
-                     cq, tag(1000), grpc_timeout_seconds_to_deadline(5), NULL)
-                     .type == GRPC_OP_COMPLETE);
+
+      shutdown_cq = grpc_completion_queue_create_for_pluck(NULL);
+      grpc_server_shutdown_and_notify(server, shutdown_cq, tag(1000));
+      GPR_ASSERT(
+          grpc_completion_queue_pluck(shutdown_cq, tag(1000),
+                                      grpc_timeout_seconds_to_deadline(5), NULL)
+              .type == GRPC_OP_COMPLETE);
+      grpc_completion_queue_destroy(shutdown_cq);
       grpc_completion_queue_shutdown(cq);
       shutdown_started = 1;
     }
diff --git a/test/core/support/spinlock_test.c b/test/core/support/spinlock_test.c
index c70e76c..96055e9 100644
--- a/test/core/support/spinlock_test.c
+++ b/test/core/support/spinlock_test.c
@@ -109,7 +109,7 @@
       start, gpr_time_from_micros((int64_t)timeout_s * 1000000, GPR_TIMESPAN));
   fprintf(stderr, "%s:", name);
   while (gpr_time_cmp(gpr_now(GPR_CLOCK_REALTIME), deadline) < 0) {
-    iterations <<= 1;
+    if (iterations < INT64_MAX / 2) iterations <<= 1;
     fprintf(stderr, " %ld", (long)iterations);
     m = test_new(10, iterations, incr_step);
     test_create_threads(m, body);
diff --git a/test/core/surface/alarm_test.c b/test/core/surface/alarm_test.c
index 4afe357..6ea3444 100644
--- a/test/core/surface/alarm_test.c
+++ b/test/core/surface/alarm_test.c
@@ -58,7 +58,7 @@
   grpc_completion_queue *cc;
 
   LOG_TEST("test_alarm");
-  cc = grpc_completion_queue_create(NULL);
+  cc = grpc_completion_queue_create_for_next(NULL);
   {
     /* regular expiry */
     grpc_event ev;
diff --git a/test/core/surface/completion_queue_test.c b/test/core/surface/completion_queue_test.c
index 07f6a98..35bda5b 100644
--- a/test/core/surface/completion_queue_test.c
+++ b/test/core/surface/completion_queue_test.c
@@ -51,33 +51,88 @@
 static void shutdown_and_destroy(grpc_completion_queue *cc) {
   grpc_event ev;
   grpc_completion_queue_shutdown(cc);
-  ev = grpc_completion_queue_next(cc, gpr_inf_past(GPR_CLOCK_REALTIME), NULL);
+
+  switch (grpc_get_cq_completion_type(cc)) {
+    case GRPC_CQ_NEXT: {
+      ev = grpc_completion_queue_next(cc, gpr_inf_past(GPR_CLOCK_REALTIME),
+                                      NULL);
+      break;
+    }
+    case GRPC_CQ_PLUCK: {
+      ev = grpc_completion_queue_pluck(cc, create_test_tag(),
+                                       gpr_inf_past(GPR_CLOCK_REALTIME), NULL);
+      break;
+    }
+    default: {
+      gpr_log(GPR_ERROR, "Unknown completion type");
+      break;
+    }
+  }
+
   GPR_ASSERT(ev.type == GRPC_QUEUE_SHUTDOWN);
   grpc_completion_queue_destroy(cc);
 }
 
 /* ensure we can create and destroy a completion channel */
 static void test_no_op(void) {
+  grpc_cq_completion_type completion_types[] = {GRPC_CQ_NEXT, GRPC_CQ_PLUCK};
+  grpc_cq_polling_type polling_types[] = {
+      GRPC_CQ_DEFAULT_POLLING, GRPC_CQ_NON_LISTENING, GRPC_CQ_NON_POLLING};
+  grpc_completion_queue_attributes attr;
   LOG_TEST("test_no_op");
-  shutdown_and_destroy(grpc_completion_queue_create(NULL));
+
+  attr.version = 1;
+  for (size_t i = 0; i < GPR_ARRAY_SIZE(completion_types); i++) {
+    for (size_t j = 0; j < GPR_ARRAY_SIZE(polling_types); j++) {
+      attr.cq_completion_type = completion_types[i];
+      attr.cq_polling_type = polling_types[j];
+      shutdown_and_destroy(grpc_completion_queue_create(
+          grpc_completion_queue_factory_lookup(&attr), &attr, NULL));
+    }
+  }
 }
 
 static void test_pollset_conversion(void) {
-  grpc_completion_queue *cq = grpc_completion_queue_create(NULL);
-  GPR_ASSERT(grpc_cq_from_pollset(grpc_cq_pollset(cq)) == cq);
-  shutdown_and_destroy(cq);
+  grpc_cq_completion_type completion_types[] = {GRPC_CQ_NEXT, GRPC_CQ_PLUCK};
+  grpc_cq_polling_type polling_types[] = {GRPC_CQ_DEFAULT_POLLING,
+                                          GRPC_CQ_NON_LISTENING};
+  grpc_completion_queue *cq;
+  grpc_completion_queue_attributes attr;
+
+  LOG_TEST("test_pollset_conversion");
+
+  attr.version = 1;
+  for (size_t i = 0; i < GPR_ARRAY_SIZE(completion_types); i++) {
+    for (size_t j = 0; j < GPR_ARRAY_SIZE(polling_types); j++) {
+      attr.cq_completion_type = completion_types[i];
+      attr.cq_polling_type = polling_types[j];
+      cq = grpc_completion_queue_create(
+          grpc_completion_queue_factory_lookup(&attr), &attr, NULL);
+      GPR_ASSERT(grpc_cq_from_pollset(grpc_cq_pollset(cq)) == cq);
+      shutdown_and_destroy(cq);
+    }
+  }
 }
 
 static void test_wait_empty(void) {
+  grpc_cq_polling_type polling_types[] = {
+      GRPC_CQ_DEFAULT_POLLING, GRPC_CQ_NON_LISTENING, GRPC_CQ_NON_POLLING};
   grpc_completion_queue *cc;
+  grpc_completion_queue_attributes attr;
   grpc_event event;
 
   LOG_TEST("test_wait_empty");
 
-  cc = grpc_completion_queue_create(NULL);
-  event = grpc_completion_queue_next(cc, gpr_now(GPR_CLOCK_REALTIME), NULL);
-  GPR_ASSERT(event.type == GRPC_QUEUE_TIMEOUT);
-  shutdown_and_destroy(cc);
+  attr.version = 1;
+  attr.cq_completion_type = GRPC_CQ_NEXT;
+  for (size_t i = 0; i < GPR_ARRAY_SIZE(polling_types); i++) {
+    attr.cq_polling_type = polling_types[i];
+    cc = grpc_completion_queue_create(
+        grpc_completion_queue_factory_lookup(&attr), &attr, NULL);
+    event = grpc_completion_queue_next(cc, gpr_now(GPR_CLOCK_REALTIME), NULL);
+    GPR_ASSERT(event.type == GRPC_QUEUE_TIMEOUT);
+    shutdown_and_destroy(cc);
+  }
 }
 
 static void do_nothing_end_completion(grpc_exec_ctx *exec_ctx, void *arg,
@@ -87,50 +142,80 @@
   grpc_event ev;
   grpc_completion_queue *cc;
   grpc_cq_completion completion;
-  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+  grpc_cq_polling_type polling_types[] = {
+      GRPC_CQ_DEFAULT_POLLING, GRPC_CQ_NON_LISTENING, GRPC_CQ_NON_POLLING};
+  grpc_completion_queue_attributes attr;
+  grpc_exec_ctx init_exec_ctx = GRPC_EXEC_CTX_INIT;
+  grpc_exec_ctx exec_ctx;
   void *tag = create_test_tag();
 
   LOG_TEST("test_cq_end_op");
 
-  cc = grpc_completion_queue_create(NULL);
+  attr.version = 1;
+  attr.cq_completion_type = GRPC_CQ_NEXT;
+  for (size_t i = 0; i < GPR_ARRAY_SIZE(polling_types); i++) {
+    exec_ctx = init_exec_ctx;  // Reset exec_ctx
+    attr.cq_polling_type = polling_types[i];
+    cc = grpc_completion_queue_create(
+        grpc_completion_queue_factory_lookup(&attr), &attr, NULL);
 
-  grpc_cq_begin_op(cc, tag);
-  grpc_cq_end_op(&exec_ctx, cc, tag, GRPC_ERROR_NONE, do_nothing_end_completion,
-                 NULL, &completion);
+    grpc_cq_begin_op(cc, tag);
+    grpc_cq_end_op(&exec_ctx, cc, tag, GRPC_ERROR_NONE,
+                   do_nothing_end_completion, NULL, &completion);
 
-  ev = grpc_completion_queue_next(cc, gpr_inf_past(GPR_CLOCK_REALTIME), NULL);
-  GPR_ASSERT(ev.type == GRPC_OP_COMPLETE);
-  GPR_ASSERT(ev.tag == tag);
-  GPR_ASSERT(ev.success);
+    ev = grpc_completion_queue_next(cc, gpr_inf_past(GPR_CLOCK_REALTIME), NULL);
+    GPR_ASSERT(ev.type == GRPC_OP_COMPLETE);
+    GPR_ASSERT(ev.tag == tag);
+    GPR_ASSERT(ev.success);
 
-  shutdown_and_destroy(cc);
-  grpc_exec_ctx_finish(&exec_ctx);
+    shutdown_and_destroy(cc);
+    grpc_exec_ctx_finish(&exec_ctx);
+  }
 }
 
 static void test_shutdown_then_next_polling(void) {
+  grpc_cq_polling_type polling_types[] = {
+      GRPC_CQ_DEFAULT_POLLING, GRPC_CQ_NON_LISTENING, GRPC_CQ_NON_POLLING};
   grpc_completion_queue *cc;
+  grpc_completion_queue_attributes attr;
   grpc_event event;
   LOG_TEST("test_shutdown_then_next_polling");
 
-  cc = grpc_completion_queue_create(NULL);
-  grpc_completion_queue_shutdown(cc);
-  event =
-      grpc_completion_queue_next(cc, gpr_inf_past(GPR_CLOCK_REALTIME), NULL);
-  GPR_ASSERT(event.type == GRPC_QUEUE_SHUTDOWN);
-  grpc_completion_queue_destroy(cc);
+  attr.version = 1;
+  attr.cq_completion_type = GRPC_CQ_NEXT;
+  for (size_t i = 0; i < GPR_ARRAY_SIZE(polling_types); i++) {
+    attr.cq_polling_type = polling_types[i];
+    cc = grpc_completion_queue_create(
+        grpc_completion_queue_factory_lookup(&attr), &attr, NULL);
+    grpc_completion_queue_shutdown(cc);
+    event =
+        grpc_completion_queue_next(cc, gpr_inf_past(GPR_CLOCK_REALTIME), NULL);
+    GPR_ASSERT(event.type == GRPC_QUEUE_SHUTDOWN);
+    grpc_completion_queue_destroy(cc);
+  }
 }
 
 static void test_shutdown_then_next_with_timeout(void) {
+  grpc_cq_polling_type polling_types[] = {
+      GRPC_CQ_DEFAULT_POLLING, GRPC_CQ_NON_LISTENING, GRPC_CQ_NON_POLLING};
   grpc_completion_queue *cc;
+  grpc_completion_queue_attributes attr;
   grpc_event event;
   LOG_TEST("test_shutdown_then_next_with_timeout");
 
-  cc = grpc_completion_queue_create(NULL);
-  grpc_completion_queue_shutdown(cc);
-  event =
-      grpc_completion_queue_next(cc, gpr_inf_future(GPR_CLOCK_REALTIME), NULL);
-  GPR_ASSERT(event.type == GRPC_QUEUE_SHUTDOWN);
-  grpc_completion_queue_destroy(cc);
+  attr.version = 1;
+  attr.cq_completion_type = GRPC_CQ_NEXT;
+  for (size_t i = 0; i < GPR_ARRAY_SIZE(polling_types); i++) {
+    attr.cq_polling_type = polling_types[i];
+    cc = grpc_completion_queue_create(
+        grpc_completion_queue_factory_lookup(&attr), &attr, NULL);
+
+    grpc_completion_queue_shutdown(cc);
+    event = grpc_completion_queue_next(cc, gpr_inf_future(GPR_CLOCK_REALTIME),
+                                       NULL);
+    GPR_ASSERT(event.type == GRPC_QUEUE_SHUTDOWN);
+    grpc_completion_queue_destroy(cc);
+  }
 }
 
 static void test_pluck(void) {
@@ -138,7 +223,11 @@
   grpc_completion_queue *cc;
   void *tags[128];
   grpc_cq_completion completions[GPR_ARRAY_SIZE(tags)];
-  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+  grpc_cq_polling_type polling_types[] = {
+      GRPC_CQ_DEFAULT_POLLING, GRPC_CQ_NON_LISTENING, GRPC_CQ_NON_POLLING};
+  grpc_completion_queue_attributes attr;
+  grpc_exec_ctx init_exec_ctx = GRPC_EXEC_CTX_INIT;
+  grpc_exec_ctx exec_ctx;
   unsigned i, j;
 
   LOG_TEST("test_pluck");
@@ -150,49 +239,71 @@
     }
   }
 
-  cc = grpc_completion_queue_create(NULL);
+  attr.version = 1;
+  attr.cq_completion_type = GRPC_CQ_PLUCK;
+  for (size_t pidx = 0; pidx < GPR_ARRAY_SIZE(polling_types); pidx++) {
+    exec_ctx = init_exec_ctx;  // reset exec_ctx
+    attr.cq_polling_type = polling_types[pidx];
+    cc = grpc_completion_queue_create(
+        grpc_completion_queue_factory_lookup(&attr), &attr, NULL);
 
-  for (i = 0; i < GPR_ARRAY_SIZE(tags); i++) {
-    grpc_cq_begin_op(cc, tags[i]);
-    grpc_cq_end_op(&exec_ctx, cc, tags[i], GRPC_ERROR_NONE,
-                   do_nothing_end_completion, NULL, &completions[i]);
+    for (i = 0; i < GPR_ARRAY_SIZE(tags); i++) {
+      grpc_cq_begin_op(cc, tags[i]);
+      grpc_cq_end_op(&exec_ctx, cc, tags[i], GRPC_ERROR_NONE,
+                     do_nothing_end_completion, NULL, &completions[i]);
+    }
+
+    for (i = 0; i < GPR_ARRAY_SIZE(tags); i++) {
+      ev = grpc_completion_queue_pluck(cc, tags[i],
+                                       gpr_inf_past(GPR_CLOCK_REALTIME), NULL);
+      GPR_ASSERT(ev.tag == tags[i]);
+    }
+
+    for (i = 0; i < GPR_ARRAY_SIZE(tags); i++) {
+      grpc_cq_begin_op(cc, tags[i]);
+      grpc_cq_end_op(&exec_ctx, cc, tags[i], GRPC_ERROR_NONE,
+                     do_nothing_end_completion, NULL, &completions[i]);
+    }
+
+    for (i = 0; i < GPR_ARRAY_SIZE(tags); i++) {
+      ev = grpc_completion_queue_pluck(cc, tags[GPR_ARRAY_SIZE(tags) - i - 1],
+                                       gpr_inf_past(GPR_CLOCK_REALTIME), NULL);
+      GPR_ASSERT(ev.tag == tags[GPR_ARRAY_SIZE(tags) - i - 1]);
+    }
+
+    shutdown_and_destroy(cc);
+    grpc_exec_ctx_finish(&exec_ctx);
   }
-
-  for (i = 0; i < GPR_ARRAY_SIZE(tags); i++) {
-    ev = grpc_completion_queue_pluck(cc, tags[i],
-                                     gpr_inf_past(GPR_CLOCK_REALTIME), NULL);
-    GPR_ASSERT(ev.tag == tags[i]);
-  }
-
-  for (i = 0; i < GPR_ARRAY_SIZE(tags); i++) {
-    grpc_cq_begin_op(cc, tags[i]);
-    grpc_cq_end_op(&exec_ctx, cc, tags[i], GRPC_ERROR_NONE,
-                   do_nothing_end_completion, NULL, &completions[i]);
-  }
-
-  for (i = 0; i < GPR_ARRAY_SIZE(tags); i++) {
-    ev = grpc_completion_queue_pluck(cc, tags[GPR_ARRAY_SIZE(tags) - i - 1],
-                                     gpr_inf_past(GPR_CLOCK_REALTIME), NULL);
-    GPR_ASSERT(ev.tag == tags[GPR_ARRAY_SIZE(tags) - i - 1]);
-  }
-
-  shutdown_and_destroy(cc);
-  grpc_exec_ctx_finish(&exec_ctx);
 }
 
 static void test_pluck_after_shutdown(void) {
+  grpc_cq_polling_type polling_types[] = {
+      GRPC_CQ_DEFAULT_POLLING, GRPC_CQ_NON_LISTENING, GRPC_CQ_NON_POLLING};
   grpc_event ev;
   grpc_completion_queue *cc;
+  grpc_completion_queue_attributes attr;
 
   LOG_TEST("test_pluck_after_shutdown");
-  cc = grpc_completion_queue_create(NULL);
-  grpc_completion_queue_shutdown(cc);
-  ev = grpc_completion_queue_pluck(cc, NULL, gpr_inf_future(GPR_CLOCK_REALTIME),
-                                   NULL);
-  GPR_ASSERT(ev.type == GRPC_QUEUE_SHUTDOWN);
-  grpc_completion_queue_destroy(cc);
+
+  attr.version = 1;
+  attr.cq_completion_type = GRPC_CQ_PLUCK;
+  for (size_t i = 0; i < GPR_ARRAY_SIZE(polling_types); i++) {
+    attr.cq_polling_type = polling_types[i];
+    cc = grpc_completion_queue_create(
+        grpc_completion_queue_factory_lookup(&attr), &attr, NULL);
+    grpc_completion_queue_shutdown(cc);
+    ev = grpc_completion_queue_pluck(cc, NULL,
+                                     gpr_inf_future(GPR_CLOCK_REALTIME), NULL);
+    GPR_ASSERT(ev.type == GRPC_QUEUE_SHUTDOWN);
+    grpc_completion_queue_destroy(cc);
+  }
 }
 
+struct thread_state {
+  grpc_completion_queue *cc;
+  void *tag;
+};
+
 int main(int argc, char **argv) {
   grpc_test_init(argc, argv);
   grpc_init();
diff --git a/test/core/surface/completion_queue_threading_test.c b/test/core/surface/completion_queue_threading_test.c
index 2d55ead..bff69ec 100644
--- a/test/core/surface/completion_queue_threading_test.c
+++ b/test/core/surface/completion_queue_threading_test.c
@@ -52,7 +52,24 @@
 static void shutdown_and_destroy(grpc_completion_queue *cc) {
   grpc_event ev;
   grpc_completion_queue_shutdown(cc);
-  ev = grpc_completion_queue_next(cc, gpr_inf_past(GPR_CLOCK_REALTIME), NULL);
+
+  switch (grpc_get_cq_completion_type(cc)) {
+    case GRPC_CQ_NEXT: {
+      ev = grpc_completion_queue_next(cc, gpr_inf_past(GPR_CLOCK_REALTIME),
+                                      NULL);
+      break;
+    }
+    case GRPC_CQ_PLUCK: {
+      ev = grpc_completion_queue_pluck(cc, create_test_tag(),
+                                       gpr_inf_past(GPR_CLOCK_REALTIME), NULL);
+      break;
+    }
+    default: {
+      gpr_log(GPR_ERROR, "Unknown completion type");
+      break;
+    }
+  }
+
   GPR_ASSERT(ev.type == GRPC_QUEUE_SHUTDOWN);
   grpc_completion_queue_destroy(cc);
 }
@@ -84,7 +101,7 @@
 
   LOG_TEST("test_too_many_plucks");
 
-  cc = grpc_completion_queue_create(NULL);
+  cc = grpc_completion_queue_create_for_pluck(NULL);
   gpr_thd_options_set_joinable(&thread_options);
 
   for (i = 0; i < GPR_ARRAY_SIZE(tags); i++) {
@@ -210,7 +227,7 @@
       gpr_malloc((producers + consumers) * sizeof(test_thread_options));
   gpr_event phase1 = GPR_EVENT_INIT;
   gpr_event phase2 = GPR_EVENT_INIT;
-  grpc_completion_queue *cc = grpc_completion_queue_create(NULL);
+  grpc_completion_queue *cc = grpc_completion_queue_create_for_next(NULL);
   size_t i;
   size_t total_consumed = 0;
   static int optid = 101;
diff --git a/test/core/surface/concurrent_connectivity_test.c b/test/core/surface/concurrent_connectivity_test.c
index 2f7c3df..d6841ea 100644
--- a/test/core/surface/concurrent_connectivity_test.c
+++ b/test/core/surface/concurrent_connectivity_test.c
@@ -66,7 +66,7 @@
 
 void create_loop_destroy(void *addr) {
   for (int i = 0; i < NUM_OUTER_LOOPS; ++i) {
-    grpc_completion_queue *cq = grpc_completion_queue_create(NULL);
+    grpc_completion_queue *cq = grpc_completion_queue_create_for_next(NULL);
     grpc_channel *chan = grpc_insecure_channel_create((char *)addr, NULL, NULL);
 
     for (int j = 0; j < NUM_INNER_LOOPS; ++j) {
@@ -196,7 +196,7 @@
   gpr_asprintf(&args.addr, "localhost:%d", port);
   args.server = grpc_server_create(NULL, NULL);
   grpc_server_add_insecure_http2_port(args.server, args.addr);
-  args.cq = grpc_completion_queue_create(NULL);
+  args.cq = grpc_completion_queue_create_for_next(NULL);
   grpc_server_register_completion_queue(args.server, args.cq, NULL);
   grpc_server_start(args.server);
   gpr_thd_new(&server, server_thread, &args, &options);
diff --git a/test/core/surface/lame_client_test.c b/test/core/surface/lame_client_test.c
index 9deb50b..6c14a5d 100644
--- a/test/core/surface/lame_client_test.c
+++ b/test/core/surface/lame_client_test.c
@@ -108,7 +108,7 @@
   GPR_ASSERT(GRPC_CHANNEL_SHUTDOWN ==
              grpc_channel_check_connectivity_state(chan, 0));
 
-  cq = grpc_completion_queue_create(NULL);
+  cq = grpc_completion_queue_create_for_next(NULL);
 
   grpc_slice host = grpc_slice_from_static_string("anywhere");
   call = grpc_channel_create_call(chan, NULL, GRPC_PROPAGATE_DEFAULTS, cq,
diff --git a/test/core/surface/sequential_connectivity_test.c b/test/core/surface/sequential_connectivity_test.c
index 5f66f90..fbecdd7 100644
--- a/test/core/surface/sequential_connectivity_test.c
+++ b/test/core/surface/sequential_connectivity_test.c
@@ -76,7 +76,8 @@
 
   grpc_server *server = grpc_server_create(NULL, NULL);
   fixture->add_server_port(server, addr);
-  grpc_completion_queue *server_cq = grpc_completion_queue_create(NULL);
+  grpc_completion_queue *server_cq =
+      grpc_completion_queue_create_for_next(NULL);
   grpc_server_register_completion_queue(server, server_cq, NULL);
   grpc_server_start(server);
 
@@ -86,7 +87,7 @@
   gpr_thd_options_set_joinable(&thdopt);
   gpr_thd_new(&server_thread, server_thread_func, &sta, &thdopt);
 
-  grpc_completion_queue *cq = grpc_completion_queue_create(NULL);
+  grpc_completion_queue *cq = grpc_completion_queue_create_for_next(NULL);
   grpc_channel *channels[NUM_CONNECTIONS];
   for (size_t i = 0; i < NUM_CONNECTIONS; i++) {
     channels[i] = fixture->create_channel(addr);
diff --git a/test/core/surface/server_chttp2_test.c b/test/core/surface/server_chttp2_test.c
index 8d40c64..06293e5 100644
--- a/test/core/surface/server_chttp2_test.c
+++ b/test/core/surface/server_chttp2_test.c
@@ -60,7 +60,7 @@
 
   int port = grpc_pick_unused_port_or_die();
   char *addr = NULL;
-  grpc_completion_queue *cq = grpc_completion_queue_create(NULL);
+  grpc_completion_queue *cq = grpc_completion_queue_create_for_pluck(NULL);
   grpc_server *server = grpc_server_create(&args, NULL);
   grpc_server_credentials *fake_creds =
       grpc_fake_transport_security_server_credentials_create();
diff --git a/test/core/surface/server_test.c b/test/core/surface/server_test.c
index 3fd1c2c..81a39de 100644
--- a/test/core/surface/server_test.c
+++ b/test/core/surface/server_test.c
@@ -70,7 +70,7 @@
 }
 
 void test_request_call_on_no_server_cq(void) {
-  grpc_completion_queue *cc = grpc_completion_queue_create(NULL);
+  grpc_completion_queue *cc = grpc_completion_queue_create_for_next(NULL);
   grpc_server *server = grpc_server_create(NULL, NULL);
   GPR_ASSERT(GRPC_CALL_ERROR_NOT_SERVER_COMPLETION_QUEUE ==
              grpc_server_request_call(server, NULL, NULL, NULL, cc, cc, NULL));
@@ -91,7 +91,7 @@
   char *addr;
   grpc_server *server1 = grpc_server_create(&args, NULL);
   grpc_server *server2 = grpc_server_create(&args, NULL);
-  grpc_completion_queue *cq = grpc_completion_queue_create(NULL);
+  grpc_completion_queue *cq = grpc_completion_queue_create_for_next(NULL);
   int port = grpc_pick_unused_port_or_die();
   gpr_asprintf(&addr, "[::]:%d", port);
   grpc_server_register_completion_queue(server1, cq, NULL);
@@ -128,7 +128,7 @@
   } else {
     GPR_ASSERT(grpc_server_add_insecure_http2_port(server, addr));
   }
-  grpc_completion_queue *cq = grpc_completion_queue_create(NULL);
+  grpc_completion_queue *cq = grpc_completion_queue_create_for_next(NULL);
   grpc_server_register_completion_queue(server, cq, NULL);
   grpc_server_start(server);
   grpc_server_shutdown_and_notify(server, cq, NULL);
diff --git a/test/core/transport/chttp2/hpack_encoder_test.c b/test/core/transport/chttp2/hpack_encoder_test.c
index d572d79..f4ccc71 100644
--- a/test/core/transport/chttp2/hpack_encoder_test.c
+++ b/test/core/transport/chttp2/hpack_encoder_test.c
@@ -60,9 +60,9 @@
 
 /* verify that the output generated by encoding the stream matches the
    hexstring passed in */
-static void verify(grpc_exec_ctx *exec_ctx, size_t window_available, int eof,
-                   size_t expect_window_used, const char *expected,
-                   size_t nheaders, ...) {
+static void verify(grpc_exec_ctx *exec_ctx, size_t window_available, bool eof,
+                   bool use_true_binary_metadata, size_t expect_window_used,
+                   const char *expected, size_t nheaders, ...) {
   grpc_slice_buffer output;
   grpc_slice merged;
   grpc_slice expect = parse_hexstring(expected);
@@ -103,8 +103,14 @@
 
   grpc_transport_one_way_stats stats;
   memset(&stats, 0, sizeof(stats));
-  grpc_chttp2_encode_header(exec_ctx, &g_compressor, 0xdeadbeef, &b, eof, 16384,
-                            &stats, &output);
+  grpc_encode_header_options hopt = {
+      .stream_id = 0xdeadbeef,
+      .is_eof = eof,
+      .use_true_binary_metadata = use_true_binary_metadata,
+      .max_frame_size = 16384,
+      .stats = &stats,
+  };
+  grpc_chttp2_encode_header(exec_ctx, &g_compressor, &b, &hopt, &output);
   merged = grpc_slice_merge(output.slices, output.count);
   grpc_slice_buffer_destroy_internal(exec_ctx, &output);
   grpc_metadata_batch_destroy(exec_ctx, &b);
@@ -127,25 +133,28 @@
 static void test_basic_headers(grpc_exec_ctx *exec_ctx) {
   int i;
 
-  verify(exec_ctx, 0, 0, 0, "000005 0104 deadbeef 40 0161 0161", 1, "a", "a");
-  verify(exec_ctx, 0, 0, 0, "000001 0104 deadbeef be", 1, "a", "a");
-  verify(exec_ctx, 0, 0, 0, "000001 0104 deadbeef be", 1, "a", "a");
-  verify(exec_ctx, 0, 0, 0, "000006 0104 deadbeef be 40 0162 0163", 2, "a", "a",
-         "b", "c");
-  verify(exec_ctx, 0, 0, 0, "000002 0104 deadbeef bf be", 2, "a", "a", "b",
-         "c");
-  verify(exec_ctx, 0, 0, 0, "000004 0104 deadbeef 7f 00 0164", 1, "a", "d");
+  verify(exec_ctx, 0, false, false, 0, "000005 0104 deadbeef 40 0161 0161", 1,
+         "a", "a");
+  verify(exec_ctx, 0, false, false, 0, "000001 0104 deadbeef be", 1, "a", "a");
+  verify(exec_ctx, 0, false, false, 0, "000001 0104 deadbeef be", 1, "a", "a");
+  verify(exec_ctx, 0, false, false, 0, "000006 0104 deadbeef be 40 0162 0163",
+         2, "a", "a", "b", "c");
+  verify(exec_ctx, 0, false, false, 0, "000002 0104 deadbeef bf be", 2, "a",
+         "a", "b", "c");
+  verify(exec_ctx, 0, false, false, 0, "000004 0104 deadbeef 7f 00 0164", 1,
+         "a", "d");
 
   /* flush out what's there to make a few values look very popular */
   for (i = 0; i < 350; i++) {
-    verify(exec_ctx, 0, 0, 0, "000003 0104 deadbeef c0 bf be", 3, "a", "a", "b",
-           "c", "a", "d");
+    verify(exec_ctx, 0, false, false, 0, "000003 0104 deadbeef c0 bf be", 3,
+           "a", "a", "b", "c", "a", "d");
   }
 
-  verify(exec_ctx, 0, 0, 0, "000006 0104 deadbeef c0 00 016b 0176", 2, "a", "a",
-         "k", "v");
+  verify(exec_ctx, 0, false, false, 0, "000006 0104 deadbeef c0 00 016b 0176",
+         2, "a", "a", "k", "v");
   /* this could be 000004 0104 deadbeef 0f 30 0176 also */
-  verify(exec_ctx, 0, 0, 0, "000004 0104 deadbeef 0f 2f 0176", 1, "a", "v");
+  verify(exec_ctx, 0, false, false, 0, "000004 0104 deadbeef 0f 2f 0176", 1,
+         "a", "v");
 }
 
 static void encode_int_to_str(int i, char *p) {
@@ -179,17 +188,17 @@
     }
 
     if (i > 0) {
-      verify(exec_ctx, 0, 0, 0, expect, 2, "aa", "ba", key, value);
+      verify(exec_ctx, 0, false, false, 0, expect, 2, "aa", "ba", key, value);
     } else {
-      verify(exec_ctx, 0, 0, 0, expect, 1, key, value);
+      verify(exec_ctx, 0, false, false, 0, expect, 1, key, value);
     }
     gpr_free(expect);
   }
 
   /* if the above passes, then we must have just knocked this pair out of the
      decoder stack, and so we'll be forced to re-encode it */
-  verify(exec_ctx, 0, 0, 0, "000007 0104 deadbeef 40 026161 026261", 1, "aa",
-         "ba");
+  verify(exec_ctx, 0, false, false, 0, "000007 0104 deadbeef 40 026161 026261",
+         1, "aa", "ba");
 }
 
 static void verify_table_size_change_match_elem_size(grpc_exec_ctx *exec_ctx,
@@ -214,8 +223,12 @@
 
   grpc_transport_one_way_stats stats;
   memset(&stats, 0, sizeof(stats));
-  grpc_chttp2_encode_header(exec_ctx, &g_compressor, 0xdeadbeef, &b, 0, 16384,
-                            &stats, &output);
+  grpc_encode_header_options hopt = {.stream_id = 0xdeadbeef,
+                                     .is_eof = false,
+                                     .use_true_binary_metadata = false,
+                                     .max_frame_size = 16384,
+                                     .stats = &stats};
+  grpc_chttp2_encode_header(exec_ctx, &g_compressor, &b, &hopt, &output);
   grpc_slice_buffer_destroy_internal(exec_ctx, &output);
   grpc_metadata_batch_destroy(exec_ctx, &b);
 
diff --git a/test/cpp/grpclb/grpclb_api_test.cc b/test/cpp/grpclb/grpclb_api_test.cc
index d9df2bb..0b569f1 100644
--- a/test/cpp/grpclb/grpclb_api_test.cc
+++ b/test/cpp/grpclb/grpclb_api_test.cc
@@ -106,11 +106,13 @@
   auto* server = serverlist->add_servers();
   server->set_ip_address(Ip4ToPackedString("127.0.0.1"));
   server->set_port(12345);
-  server->set_drop_request(true);
+  server->set_drop_for_rate_limiting(true);
+  server->set_drop_for_load_balancing(false);
   server = response.mutable_server_list()->add_servers();
   server->set_ip_address(Ip4ToPackedString("10.0.0.1"));
   server->set_port(54321);
-  server->set_drop_request(false);
+  server->set_drop_for_rate_limiting(false);
+  server->set_drop_for_load_balancing(true);
   auto* expiration_interval = serverlist->mutable_expiration_interval();
   expiration_interval->set_seconds(888);
   expiration_interval->set_nanos(999);
@@ -125,12 +127,14 @@
   EXPECT_EQ(PackedStringToIp(c_serverlist->servers[0]->ip_address),
             "127.0.0.1");
   EXPECT_EQ(c_serverlist->servers[0]->port, 12345);
-  EXPECT_TRUE(c_serverlist->servers[0]->drop_request);
+  EXPECT_TRUE(c_serverlist->servers[0]->drop_for_rate_limiting);
+  EXPECT_FALSE(c_serverlist->servers[0]->drop_for_load_balancing);
   EXPECT_TRUE(c_serverlist->servers[1]->has_ip_address);
 
   EXPECT_EQ(PackedStringToIp(c_serverlist->servers[1]->ip_address), "10.0.0.1");
   EXPECT_EQ(c_serverlist->servers[1]->port, 54321);
-  EXPECT_FALSE(c_serverlist->servers[1]->drop_request);
+  EXPECT_FALSE(c_serverlist->servers[1]->drop_for_rate_limiting);
+  EXPECT_TRUE(c_serverlist->servers[1]->drop_for_load_balancing);
 
   EXPECT_TRUE(c_serverlist->expiration_interval.has_seconds);
   EXPECT_EQ(c_serverlist->expiration_interval.seconds, 888);
diff --git a/test/cpp/grpclb/grpclb_test.cc b/test/cpp/grpclb/grpclb_test.cc
index eb3e5b6..997a839 100644
--- a/test/cpp/grpclb/grpclb_test.cc
+++ b/test/cpp/grpclb/grpclb_test.cc
@@ -573,34 +573,51 @@
 static void setup_client(const server_fixture *lb_server,
                          const server_fixture *backends, client_fixture *cf) {
   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-  char *lb_uri;
-  // The grpclb LB policy will be automatically selected by virtue of
-  // the fact that the returned addresses are balancer addresses.
-  gpr_asprintf(&lb_uri, "test:///%s?lb_enabled=1&balancer_names=%s",
-               lb_server->servers_hostport, lb_server->balancer_name);
-
-  grpc_arg expected_target_arg;
-  expected_target_arg.type = GRPC_ARG_STRING;
-  expected_target_arg.key =
-      const_cast<char *>(GRPC_ARG_FAKE_SECURITY_EXPECTED_TARGETS);
 
   char *expected_target_names = NULL;
   const char *backends_name = lb_server->servers_hostport;
   gpr_asprintf(&expected_target_names, "%s;%s", backends_name, BALANCERS_NAME);
 
-  expected_target_arg.value.string = const_cast<char *>(expected_target_names);
+  grpc_fake_resolver_response_generator *response_generator =
+      grpc_fake_resolver_response_generator_create();
+
+  grpc_lb_addresses *addresses = grpc_lb_addresses_create(1, NULL);
+  char *lb_uri_str;
+  gpr_asprintf(&lb_uri_str, "ipv4:%s", lb_server->servers_hostport);
+  grpc_uri *lb_uri = grpc_uri_parse(&exec_ctx, lb_uri_str, true);
+  GPR_ASSERT(lb_uri != NULL);
+  grpc_lb_addresses_set_address_from_uri(addresses, 0, lb_uri, true,
+                                         lb_server->balancer_name, NULL);
+  grpc_uri_destroy(lb_uri);
+  gpr_free(lb_uri_str);
+
+  gpr_asprintf(&cf->server_uri, "test:///%s", lb_server->servers_hostport);
+  const grpc_arg fake_addresses =
+      grpc_lb_addresses_create_channel_arg(addresses);
+  grpc_channel_args *fake_result =
+      grpc_channel_args_copy_and_add(NULL, &fake_addresses, 1);
+  grpc_lb_addresses_destroy(&exec_ctx, addresses);
+
+  const grpc_arg new_args[] = {
+      grpc_fake_transport_expected_targets_arg(expected_target_names),
+      grpc_fake_resolver_response_generator_arg(response_generator)};
+
   grpc_channel_args *args =
-      grpc_channel_args_copy_and_add(NULL, &expected_target_arg, 1);
+      grpc_channel_args_copy_and_add(NULL, new_args, GPR_ARRAY_SIZE(new_args));
   gpr_free(expected_target_names);
 
-  cf->cq = grpc_completion_queue_create(NULL);
-  cf->server_uri = lb_uri;
+  cf->cq = grpc_completion_queue_create_for_next(NULL);
   grpc_channel_credentials *fake_creds =
       grpc_fake_transport_security_credentials_create();
   cf->client =
       grpc_secure_channel_create(fake_creds, cf->server_uri, args, NULL);
+  grpc_fake_resolver_response_generator_set_response(
+      &exec_ctx, response_generator, fake_result);
+  grpc_channel_args_destroy(&exec_ctx, fake_result);
   grpc_channel_credentials_unref(&exec_ctx, fake_creds);
   grpc_channel_args_destroy(&exec_ctx, args);
+  grpc_fake_resolver_response_generator_unref(response_generator);
+  grpc_exec_ctx_finish(&exec_ctx);
 }
 
 static void teardown_client(client_fixture *cf) {
@@ -616,7 +633,7 @@
 static void setup_server(const char *host, server_fixture *sf) {
   int assigned_port;
 
-  sf->cq = grpc_completion_queue_create(NULL);
+  sf->cq = grpc_completion_queue_create_for_next(NULL);
   const char *colon_idx = strchr(host, ':');
   if (colon_idx) {
     const char *port_str = colon_idx + 1;
@@ -643,10 +660,15 @@
   if (!sf->server) return;
 
   gpr_log(GPR_INFO, "Server[%s] shutting down", sf->servers_hostport);
-  grpc_server_shutdown_and_notify(sf->server, sf->cq, tag(1000));
-  GPR_ASSERT(grpc_completion_queue_pluck(
-                 sf->cq, tag(1000), grpc_timeout_seconds_to_deadline(5), NULL)
+
+  grpc_completion_queue *shutdown_cq =
+      grpc_completion_queue_create_for_pluck(NULL);
+  grpc_server_shutdown_and_notify(sf->server, shutdown_cq, tag(1000));
+  GPR_ASSERT(grpc_completion_queue_pluck(shutdown_cq, tag(1000),
+                                         grpc_timeout_seconds_to_deadline(5),
+                                         NULL)
                  .type == GRPC_OP_COMPLETE);
+  grpc_completion_queue_destroy(shutdown_cq);
   grpc_server_destroy(sf->server);
   gpr_thd_join(sf->tid);
 
@@ -782,8 +804,8 @@
 
 int main(int argc, char **argv) {
   ::testing::InitGoogleTest(&argc, argv);
-  grpc_test_init(argc, argv);
   grpc_fake_resolver_init();
+  grpc_test_init(argc, argv);
   grpc_init();
   const auto result = RUN_ALL_TESTS();
   grpc_shutdown();
diff --git a/test/cpp/interop/client.cc b/test/cpp/interop/client.cc
index 369413e..6f1d910 100644
--- a/test/cpp/interop/client.cc
+++ b/test/cpp/interop/client.cc
@@ -163,8 +163,8 @@
       std::bind(&grpc::testing::InteropClient::DoUnimplementedMethod, &client);
   actions["unimplemented_service"] =
       std::bind(&grpc::testing::InteropClient::DoUnimplementedService, &client);
-  // actions["cacheable_unary"] =
-  //    std::bind(&grpc::testing::InteropClient::DoCacheableUnary, &client);
+  actions["cacheable_unary"] =
+      std::bind(&grpc::testing::InteropClient::DoCacheableUnary, &client);
 
   UpdateActions(&actions);
 
diff --git a/test/cpp/interop/interop_client.cc b/test/cpp/interop/interop_client.cc
index 55ba324..0e79c5e 100644
--- a/test/cpp/interop/interop_client.cc
+++ b/test/cpp/interop/interop_client.cc
@@ -918,6 +918,26 @@
   // second response is a cached copy of the first response
   GPR_ASSERT(response2.payload().body() == response1.payload().body());
 
+  // Request 3
+  // Modify the request body so it will not get a cache hit
+  ts = gpr_now(GPR_CLOCK_PRECISE);
+  timestamp = std::to_string((long long unsigned)ts.tv_nsec);
+  SimpleRequest request1;
+  request1.mutable_payload()->set_body(timestamp.c_str(), timestamp.size());
+  ClientContext context3;
+  SimpleResponse response3;
+  context3.set_cacheable(true);
+  context3.AddMetadata("x-user-ip", "1.2.3.4");
+  Status s3 =
+      serviceStub_.Get()->CacheableUnaryCall(&context3, request1, &response3);
+  if (!AssertStatusOk(s3)) {
+    return false;
+  }
+  gpr_log(GPR_DEBUG, "response 3 payload: %s",
+          response3.payload().body().c_str());
+
+  // Check that the response is different from the previous response.
+  GPR_ASSERT(response3.payload().body() != response1.payload().body());
   return true;
 }
 
diff --git a/test/cpp/microbenchmarks/bm_call_create.cc b/test/cpp/microbenchmarks/bm_call_create.cc
index 136b7c0..8373eea 100644
--- a/test/cpp/microbenchmarks/bm_call_create.cc
+++ b/test/cpp/microbenchmarks/bm_call_create.cc
@@ -46,14 +46,14 @@
 
 extern "C" {
 #include "src/core/ext/filters/client_channel/client_channel.h"
+#include "src/core/ext/filters/deadline/deadline_filter.h"
+#include "src/core/ext/filters/http/client/http_client_filter.h"
+#include "src/core/ext/filters/http/message_compress/message_compress_filter.h"
+#include "src/core/ext/filters/http/server/http_server_filter.h"
 #include "src/core/ext/filters/load_reporting/load_reporting_filter.h"
+#include "src/core/ext/filters/message_size/message_size_filter.h"
 #include "src/core/lib/channel/channel_stack.h"
-#include "src/core/lib/channel/compress_filter.h"
 #include "src/core/lib/channel/connected_channel.h"
-#include "src/core/lib/channel/deadline_filter.h"
-#include "src/core/lib/channel/http_client_filter.h"
-#include "src/core/lib/channel/http_server_filter.h"
-#include "src/core/lib/channel/message_size_filter.h"
 #include "src/core/lib/profiling/timers.h"
 #include "src/core/lib/surface/channel.h"
 #include "src/core/lib/transport/transport_impl.h"
@@ -119,7 +119,7 @@
 static void BM_CallCreateDestroy(benchmark::State &state) {
   TrackCounters track_counters;
   Fixture fixture;
-  grpc_completion_queue *cq = grpc_completion_queue_create(NULL);
+  grpc_completion_queue *cq = grpc_completion_queue_create_for_next(NULL);
   gpr_timespec deadline = gpr_inf_future(GPR_CLOCK_MONOTONIC);
   void *method_hdl =
       grpc_channel_register_call(fixture.channel(), "/foo/bar", NULL, NULL);
@@ -461,7 +461,7 @@
 BENCHMARK_TEMPLATE(BM_IsolatedFilter, DummyFilter, SendEmptyMetadata);
 typedef Fixture<&grpc_client_channel_filter, 0> ClientChannelFilter;
 BENCHMARK_TEMPLATE(BM_IsolatedFilter, ClientChannelFilter, NoOp);
-typedef Fixture<&grpc_compress_filter, CHECKS_NOT_LAST> CompressFilter;
+typedef Fixture<&grpc_message_compress_filter, CHECKS_NOT_LAST> CompressFilter;
 BENCHMARK_TEMPLATE(BM_IsolatedFilter, CompressFilter, NoOp);
 BENCHMARK_TEMPLATE(BM_IsolatedFilter, CompressFilter, SendEmptyMetadata);
 typedef Fixture<&grpc_client_deadline_filter, CHECKS_NOT_LAST>
@@ -576,7 +576,7 @@
                                                   GRPC_CLIENT_CHANNEL);
       grpc_exec_ctx_finish(&exec_ctx);
     }
-    cq_ = grpc_completion_queue_create(NULL);
+    cq_ = grpc_completion_queue_create_for_next(NULL);
   }
 
   void Finish(benchmark::State &state) {
diff --git a/test/cpp/microbenchmarks/bm_chttp2_hpack.cc b/test/cpp/microbenchmarks/bm_chttp2_hpack.cc
index 55d2d2f..5814406 100644
--- a/test/cpp/microbenchmarks/bm_chttp2_hpack.cc
+++ b/test/cpp/microbenchmarks/bm_chttp2_hpack.cc
@@ -90,10 +90,15 @@
   grpc_slice_buffer outbuf;
   grpc_slice_buffer_init(&outbuf);
   while (state.KeepRunning()) {
-    uint32_t stream_id = static_cast<uint32_t>(state.iterations());
-    grpc_chttp2_encode_header(&exec_ctx, &c, stream_id, &b, state.range(0),
-                              state.range(1), &stats, &outbuf);
-    if (!logged_representative_output) {
+    grpc_encode_header_options hopt = {
+        static_cast<uint32_t>(state.iterations()),
+        state.range(0) != 0,
+        Fixture::kEnableTrueBinary,
+        (size_t)state.range(1),
+        &stats,
+    };
+    grpc_chttp2_encode_header(&exec_ctx, &c, &b, &hopt, &outbuf);
+    if (!logged_representative_output && state.iterations() > 3) {
       logged_representative_output = true;
       for (size_t i = 0; i < outbuf.count; i++) {
         char *s = grpc_dump_slice(outbuf.slices[i], GPR_DUMP_HEX);
@@ -122,6 +127,7 @@
 
 class EmptyBatch {
  public:
+  static constexpr bool kEnableTrueBinary = false;
   static std::vector<grpc_mdelem> GetElems(grpc_exec_ctx *exec_ctx) {
     return {};
   }
@@ -129,6 +135,7 @@
 
 class SingleStaticElem {
  public:
+  static constexpr bool kEnableTrueBinary = false;
   static std::vector<grpc_mdelem> GetElems(grpc_exec_ctx *exec_ctx) {
     return {GRPC_MDELEM_GRPC_ACCEPT_ENCODING_IDENTITY_COMMA_DEFLATE};
   }
@@ -136,6 +143,7 @@
 
 class SingleInternedElem {
  public:
+  static constexpr bool kEnableTrueBinary = false;
   static std::vector<grpc_mdelem> GetElems(grpc_exec_ctx *exec_ctx) {
     return {grpc_mdelem_from_slices(
         exec_ctx, grpc_slice_intern(grpc_slice_from_static_string("abc")),
@@ -143,9 +151,10 @@
   }
 };
 
-template <int kLength>
+template <int kLength, bool kTrueBinary>
 class SingleInternedBinaryElem {
  public:
+  static constexpr bool kEnableTrueBinary = kTrueBinary;
   static std::vector<grpc_mdelem> GetElems(grpc_exec_ctx *exec_ctx) {
     grpc_slice bytes = MakeBytes();
     std::vector<grpc_mdelem> out = {grpc_mdelem_from_slices(
@@ -167,6 +176,7 @@
 
 class SingleInternedKeyElem {
  public:
+  static constexpr bool kEnableTrueBinary = false;
   static std::vector<grpc_mdelem> GetElems(grpc_exec_ctx *exec_ctx) {
     return {grpc_mdelem_from_slices(
         exec_ctx, grpc_slice_intern(grpc_slice_from_static_string("abc")),
@@ -176,6 +186,7 @@
 
 class SingleNonInternedElem {
  public:
+  static constexpr bool kEnableTrueBinary = false;
   static std::vector<grpc_mdelem> GetElems(grpc_exec_ctx *exec_ctx) {
     return {grpc_mdelem_from_slices(exec_ctx,
                                     grpc_slice_from_static_string("abc"),
@@ -183,9 +194,10 @@
   }
 };
 
-template <int kLength>
+template <int kLength, bool kTrueBinary>
 class SingleNonInternedBinaryElem {
  public:
+  static constexpr bool kEnableTrueBinary = kTrueBinary;
   static std::vector<grpc_mdelem> GetElems(grpc_exec_ctx *exec_ctx) {
     return {grpc_mdelem_from_slices(
         exec_ctx, grpc_slice_from_static_string("abc-bin"), MakeBytes())};
@@ -203,6 +215,7 @@
 
 class RepresentativeClientInitialMetadata {
  public:
+  static constexpr bool kEnableTrueBinary = true;
   static std::vector<grpc_mdelem> GetElems(grpc_exec_ctx *exec_ctx) {
     return {
         GRPC_MDELEM_SCHEME_HTTP, GRPC_MDELEM_METHOD_POST,
@@ -224,6 +237,7 @@
 
 class RepresentativeServerInitialMetadata {
  public:
+  static constexpr bool kEnableTrueBinary = true;
   static std::vector<grpc_mdelem> GetElems(grpc_exec_ctx *exec_ctx) {
     return {GRPC_MDELEM_STATUS_200,
             GRPC_MDELEM_CONTENT_TYPE_APPLICATION_SLASH_GRPC,
@@ -233,6 +247,7 @@
 
 class RepresentativeServerTrailingMetadata {
  public:
+  static constexpr bool kEnableTrueBinary = true;
   static std::vector<grpc_mdelem> GetElems(grpc_exec_ctx *exec_ctx) {
     return {GRPC_MDELEM_GRPC_STATUS_0};
   }
@@ -247,28 +262,67 @@
     ->Args({0, 16384});
 BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader, SingleInternedElem)
     ->Args({0, 16384});
-BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader, SingleInternedBinaryElem<1>)
+BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader,
+                   SingleInternedBinaryElem<1, false>)
     ->Args({0, 16384});
-BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader, SingleInternedBinaryElem<3>)
+BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader,
+                   SingleInternedBinaryElem<3, false>)
     ->Args({0, 16384});
-BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader, SingleInternedBinaryElem<10>)
+BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader,
+                   SingleInternedBinaryElem<10, false>)
     ->Args({0, 16384});
-BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader, SingleInternedBinaryElem<31>)
+BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader,
+                   SingleInternedBinaryElem<31, false>)
     ->Args({0, 16384});
-BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader, SingleInternedBinaryElem<100>)
+BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader,
+                   SingleInternedBinaryElem<100, false>)
+    ->Args({0, 16384});
+BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader,
+                   SingleInternedBinaryElem<1, true>)
+    ->Args({0, 16384});
+BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader,
+                   SingleInternedBinaryElem<3, true>)
+    ->Args({0, 16384});
+BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader,
+                   SingleInternedBinaryElem<10, true>)
+    ->Args({0, 16384});
+BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader,
+                   SingleInternedBinaryElem<31, true>)
+    ->Args({0, 16384});
+BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader,
+                   SingleInternedBinaryElem<100, true>)
     ->Args({0, 16384});
 BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader, SingleNonInternedElem)
     ->Args({0, 16384});
-BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader, SingleNonInternedBinaryElem<1>)
-    ->Args({0, 16384});
-BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader, SingleNonInternedBinaryElem<3>)
-    ->Args({0, 16384});
-BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader, SingleNonInternedBinaryElem<10>)
-    ->Args({0, 16384});
-BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader, SingleNonInternedBinaryElem<31>)
+BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader,
+                   SingleNonInternedBinaryElem<1, false>)
     ->Args({0, 16384});
 BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader,
-                   SingleNonInternedBinaryElem<100>)
+                   SingleNonInternedBinaryElem<3, false>)
+    ->Args({0, 16384});
+BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader,
+                   SingleNonInternedBinaryElem<10, false>)
+    ->Args({0, 16384});
+BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader,
+                   SingleNonInternedBinaryElem<31, false>)
+    ->Args({0, 16384});
+BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader,
+                   SingleNonInternedBinaryElem<100, false>)
+    ->Args({0, 16384});
+BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader,
+                   SingleNonInternedBinaryElem<1, true>)
+    ->Args({0, 16384});
+BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader,
+                   SingleNonInternedBinaryElem<3, true>)
+    ->Args({0, 16384});
+BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader,
+                   SingleNonInternedBinaryElem<10, true>)
+    ->Args({0, 16384});
+BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader,
+                   SingleNonInternedBinaryElem<31, true>)
+    ->Args({0, 16384});
+BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader,
+                   SingleNonInternedBinaryElem<100, true>)
     ->Args({0, 16384});
 // test with a tiny frame size, to highlight continuation costs
 BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader, SingleNonInternedElem)
@@ -421,7 +475,27 @@
   }
 };
 
-class NonIndexedBinaryElem1 {
+template <int kLength, bool kTrueBinary>
+class NonIndexedBinaryElem;
+
+template <int kLength>
+class NonIndexedBinaryElem<kLength, true> {
+ public:
+  static std::vector<grpc_slice> GetInitSlices() { return {}; }
+  static std::vector<grpc_slice> GetBenchmarkSlices() {
+    std::vector<uint8_t> v = {
+        0x00, 0x07, 'a', 'b', 'c',
+        '-',  'b',  'i', 'n', static_cast<uint8_t>(kLength + 1),
+        0};
+    for (int i = 0; i < kLength; i++) {
+      v.push_back(static_cast<uint8_t>(i));
+    }
+    return {MakeSlice(v)};
+  }
+};
+
+template <>
+class NonIndexedBinaryElem<1, false> {
  public:
   static std::vector<grpc_slice> GetInitSlices() { return {}; }
   static std::vector<grpc_slice> GetBenchmarkSlices() {
@@ -430,7 +504,8 @@
   }
 };
 
-class NonIndexedBinaryElem3 {
+template <>
+class NonIndexedBinaryElem<3, false> {
  public:
   static std::vector<grpc_slice> GetInitSlices() { return {}; }
   static std::vector<grpc_slice> GetBenchmarkSlices() {
@@ -439,7 +514,8 @@
   }
 };
 
-class NonIndexedBinaryElem10 {
+template <>
+class NonIndexedBinaryElem<10, false> {
  public:
   static std::vector<grpc_slice> GetInitSlices() { return {}; }
   static std::vector<grpc_slice> GetBenchmarkSlices() {
@@ -449,7 +525,8 @@
   }
 };
 
-class NonIndexedBinaryElem31 {
+template <>
+class NonIndexedBinaryElem<31, false> {
  public:
   static std::vector<grpc_slice> GetInitSlices() { return {}; }
   static std::vector<grpc_slice> GetBenchmarkSlices() {
@@ -461,7 +538,8 @@
   }
 };
 
-class NonIndexedBinaryElem100 {
+template <>
+class NonIndexedBinaryElem<100, false> {
  public:
   static std::vector<grpc_slice> GetInitSlices() { return {}; }
   static std::vector<grpc_slice> GetBenchmarkSlices() {
@@ -570,11 +648,16 @@
 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, AddIndexedSingleInternedElem);
 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, KeyIndexedSingleInternedElem);
 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, NonIndexedElem);
-BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, NonIndexedBinaryElem1);
-BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, NonIndexedBinaryElem3);
-BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, NonIndexedBinaryElem10);
-BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, NonIndexedBinaryElem31);
-BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, NonIndexedBinaryElem100);
+BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, NonIndexedBinaryElem<1, false>);
+BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, NonIndexedBinaryElem<3, false>);
+BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, NonIndexedBinaryElem<10, false>);
+BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, NonIndexedBinaryElem<31, false>);
+BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, NonIndexedBinaryElem<100, false>);
+BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, NonIndexedBinaryElem<1, true>);
+BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, NonIndexedBinaryElem<3, true>);
+BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, NonIndexedBinaryElem<10, true>);
+BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, NonIndexedBinaryElem<31, true>);
+BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, NonIndexedBinaryElem<100, true>);
 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader,
                    RepresentativeClientInitialMetadata);
 BENCHMARK_TEMPLATE(BM_HpackParserParseHeader,
@@ -584,23 +667,4 @@
 
 }  // namespace hpack_parser_fixtures
 
-static void BM_Base16SomeStuff(benchmark::State &state) {
-  uint8_t *bytes = new uint8_t[state.range(0)];
-  for (int i = 0; i < state.range(0); i++) {
-    bytes[i] = static_cast<uint8_t>(rand());
-  }
-  uint8_t *encoded = new uint8_t[state.range(0) * 2];
-  static const uint8_t hex[] = "0123456789abcdef";
-  while (state.KeepRunning()) {
-    for (int i = 0; i < state.range(0); i++) {
-      encoded[2 * i + 0] = hex[encoded[i] >> 8];
-      encoded[2 * i + 1] = hex[encoded[i] & 0xf];
-    }
-  }
-  delete[] encoded;
-  delete[] bytes;
-  state.SetBytesProcessed(state.iterations() * state.range(0));
-}
-BENCHMARK(BM_Base16SomeStuff)->Range(1, 4096);
-
 BENCHMARK_MAIN();
diff --git a/test/cpp/microbenchmarks/bm_chttp2_transport.cc b/test/cpp/microbenchmarks/bm_chttp2_transport.cc
index c89f349..8c5413b 100644
--- a/test/cpp/microbenchmarks/bm_chttp2_transport.cc
+++ b/test/cpp/microbenchmarks/bm_chttp2_transport.cc
@@ -569,12 +569,17 @@
         grpc_closure_sched(exec_ctx, c.get(), GRPC_ERROR_NONE);
         return;
       }
-    } while (grpc_byte_stream_next(exec_ctx, recv_stream, &recv_slice,
+    } while (grpc_byte_stream_next(exec_ctx, recv_stream,
                                    recv_stream->length - received,
-                                   drain_continue.get()));
+                                   drain_continue.get()) &&
+             GRPC_ERROR_NONE ==
+                 grpc_byte_stream_pull(exec_ctx, recv_stream, &recv_slice) &&
+             (received += GRPC_SLICE_LENGTH(recv_slice),
+              grpc_slice_unref_internal(exec_ctx, recv_slice), true));
   });
 
   drain_continue = MakeClosure([&](grpc_exec_ctx *exec_ctx, grpc_error *error) {
+    grpc_byte_stream_pull(exec_ctx, recv_stream, &recv_slice);
     received += GRPC_SLICE_LENGTH(recv_slice);
     grpc_slice_unref_internal(exec_ctx, recv_slice);
     grpc_closure_run(exec_ctx, drain.get(), GRPC_ERROR_NONE);
diff --git a/test/cpp/microbenchmarks/bm_cq.cc b/test/cpp/microbenchmarks/bm_cq.cc
index 38ac9d2..8b26bf9 100644
--- a/test/cpp/microbenchmarks/bm_cq.cc
+++ b/test/cpp/microbenchmarks/bm_cq.cc
@@ -62,7 +62,8 @@
 static void BM_CreateDestroyCpp2(benchmark::State& state) {
   TrackCounters track_counters;
   while (state.KeepRunning()) {
-    grpc_completion_queue* core_cq = grpc_completion_queue_create(NULL);
+    grpc_completion_queue* core_cq =
+        grpc_completion_queue_create_for_next(NULL);
     CompletionQueue cq(core_cq);
   }
   track_counters.Finish(state);
@@ -72,7 +73,9 @@
 static void BM_CreateDestroyCore(benchmark::State& state) {
   TrackCounters track_counters;
   while (state.KeepRunning()) {
-    grpc_completion_queue_destroy(grpc_completion_queue_create(NULL));
+    // TODO: sreek Templatize this benchmark and pass completion type and
+    // polling type as parameters
+    grpc_completion_queue_destroy(grpc_completion_queue_create_for_next(NULL));
   }
   track_counters.Finish(state);
 }
@@ -108,7 +111,8 @@
 
 static void BM_Pass1Core(benchmark::State& state) {
   TrackCounters track_counters;
-  grpc_completion_queue* cq = grpc_completion_queue_create(NULL);
+  // TODO: sreek Templatize this benchmark and pass polling_type as a param
+  grpc_completion_queue* cq = grpc_completion_queue_create_for_next(NULL);
   gpr_timespec deadline = gpr_inf_future(GPR_CLOCK_MONOTONIC);
   while (state.KeepRunning()) {
     grpc_cq_completion completion;
@@ -126,7 +130,8 @@
 
 static void BM_Pluck1Core(benchmark::State& state) {
   TrackCounters track_counters;
-  grpc_completion_queue* cq = grpc_completion_queue_create(NULL);
+  // TODO: sreek Templatize this benchmark and pass polling_type as a param
+  grpc_completion_queue* cq = grpc_completion_queue_create_for_pluck(NULL);
   gpr_timespec deadline = gpr_inf_future(GPR_CLOCK_MONOTONIC);
   while (state.KeepRunning()) {
     grpc_cq_completion completion;
@@ -144,7 +149,8 @@
 
 static void BM_EmptyCore(benchmark::State& state) {
   TrackCounters track_counters;
-  grpc_completion_queue* cq = grpc_completion_queue_create(NULL);
+  // TODO: sreek Templatize this benchmark and pass polling_type as a param
+  grpc_completion_queue* cq = grpc_completion_queue_create_for_next(NULL);
   gpr_timespec deadline = gpr_inf_past(GPR_CLOCK_MONOTONIC);
   while (state.KeepRunning()) {
     grpc_completion_queue_next(cq, deadline, NULL);
diff --git a/test/cpp/microbenchmarks/bm_cq_multiple_threads.cc b/test/cpp/microbenchmarks/bm_cq_multiple_threads.cc
index 8627463..9d7f65d 100644
--- a/test/cpp/microbenchmarks/bm_cq_multiple_threads.cc
+++ b/test/cpp/microbenchmarks/bm_cq_multiple_threads.cc
@@ -108,7 +108,7 @@
   init_engine_vtable();
   grpc_set_event_engine_test_only(&g_vtable);
 
-  g_cq = grpc_completion_queue_create(NULL);
+  g_cq = grpc_completion_queue_create_for_next(NULL);
 }
 
 static void teardown() {
diff --git a/test/cpp/microbenchmarks/bm_fullstack_streaming_ping_pong.cc b/test/cpp/microbenchmarks/bm_fullstack_streaming_ping_pong.cc
index c536e15..fd2210c 100644
--- a/test/cpp/microbenchmarks/bm_fullstack_streaming_ping_pong.cc
+++ b/test/cpp/microbenchmarks/bm_fullstack_streaming_ping_pong.cc
@@ -436,6 +436,18 @@
 BENCHMARK_TEMPLATE(BM_StreamingPingPongMsgs, TCP, NoOpMutator, NoOpMutator)
     ->Range(0, 128 * 1024 * 1024);
 
+BENCHMARK_TEMPLATE(BM_StreamingPingPong, MinInProcessCHTTP2, NoOpMutator,
+                   NoOpMutator)
+    ->Apply(StreamingPingPongArgs);
+BENCHMARK_TEMPLATE(BM_StreamingPingPong, MinTCP, NoOpMutator, NoOpMutator)
+    ->Apply(StreamingPingPongArgs);
+
+BENCHMARK_TEMPLATE(BM_StreamingPingPongMsgs, MinInProcessCHTTP2, NoOpMutator,
+                   NoOpMutator)
+    ->Range(0, 128 * 1024 * 1024);
+BENCHMARK_TEMPLATE(BM_StreamingPingPongMsgs, MinTCP, NoOpMutator, NoOpMutator)
+    ->Range(0, 128 * 1024 * 1024);
+
 // Generate Args for StreamingPingPongWithCoalescingApi benchmarks. Currently
 // generates args for only "small streams" (i.e streams with 0, 1 or 2 messages)
 static void StreamingPingPongWithCoalescingApiArgs(
@@ -459,6 +471,9 @@
 BENCHMARK_TEMPLATE(BM_StreamingPingPongWithCoalescingApi, InProcessCHTTP2,
                    NoOpMutator, NoOpMutator)
     ->Apply(StreamingPingPongWithCoalescingApiArgs);
+BENCHMARK_TEMPLATE(BM_StreamingPingPongWithCoalescingApi, MinInProcessCHTTP2,
+                   NoOpMutator, NoOpMutator)
+    ->Apply(StreamingPingPongWithCoalescingApiArgs);
 
 }  // namespace testing
 }  // namespace grpc
diff --git a/test/cpp/microbenchmarks/bm_fullstack_streaming_pump.cc b/test/cpp/microbenchmarks/bm_fullstack_streaming_pump.cc
index 5c1eb11..47705d3 100644
--- a/test/cpp/microbenchmarks/bm_fullstack_streaming_pump.cc
+++ b/test/cpp/microbenchmarks/bm_fullstack_streaming_pump.cc
@@ -189,6 +189,14 @@
     ->Range(0, 128 * 1024 * 1024);
 BENCHMARK_TEMPLATE(BM_PumpStreamServerToClient, InProcessCHTTP2)
     ->Range(0, 128 * 1024 * 1024);
+BENCHMARK_TEMPLATE(BM_PumpStreamClientToServer, MinTCP)->Arg(0);
+BENCHMARK_TEMPLATE(BM_PumpStreamClientToServer, MinUDS)->Arg(0);
+BENCHMARK_TEMPLATE(BM_PumpStreamClientToServer, MinSockPair)->Arg(0);
+BENCHMARK_TEMPLATE(BM_PumpStreamClientToServer, MinInProcessCHTTP2)->Arg(0);
+BENCHMARK_TEMPLATE(BM_PumpStreamServerToClient, MinTCP)->Arg(0);
+BENCHMARK_TEMPLATE(BM_PumpStreamServerToClient, MinUDS)->Arg(0);
+BENCHMARK_TEMPLATE(BM_PumpStreamServerToClient, MinSockPair)->Arg(0);
+BENCHMARK_TEMPLATE(BM_PumpStreamServerToClient, MinInProcessCHTTP2)->Arg(0);
 
 }  // namespace testing
 }  // namespace grpc
diff --git a/test/cpp/microbenchmarks/bm_fullstack_trickle.cc b/test/cpp/microbenchmarks/bm_fullstack_trickle.cc
index c563f28..a5cfeb4 100644
--- a/test/cpp/microbenchmarks/bm_fullstack_trickle.cc
+++ b/test/cpp/microbenchmarks/bm_fullstack_trickle.cc
@@ -53,7 +53,8 @@
 class TrickledCHTTP2 : public EndpointPairFixture {
  public:
   TrickledCHTTP2(Service* service, size_t megabits_per_second)
-      : EndpointPairFixture(service, MakeEndpoints(megabits_per_second)) {}
+      : EndpointPairFixture(service, MakeEndpoints(megabits_per_second),
+                            FixtureConfiguration()) {}
 
   void AddToLabel(std::ostream& out, benchmark::State& state) {
     out << " writes/iter:"
diff --git a/test/cpp/microbenchmarks/bm_fullstack_unary_ping_pong.cc b/test/cpp/microbenchmarks/bm_fullstack_unary_ping_pong.cc
index 615b05b..7524751 100644
--- a/test/cpp/microbenchmarks/bm_fullstack_unary_ping_pong.cc
+++ b/test/cpp/microbenchmarks/bm_fullstack_unary_ping_pong.cc
@@ -141,12 +141,21 @@
 
 BENCHMARK_TEMPLATE(BM_UnaryPingPong, TCP, NoOpMutator, NoOpMutator)
     ->Apply(SweepSizesArgs);
+BENCHMARK_TEMPLATE(BM_UnaryPingPong, MinTCP, NoOpMutator, NoOpMutator)
+    ->Apply(SweepSizesArgs);
 BENCHMARK_TEMPLATE(BM_UnaryPingPong, UDS, NoOpMutator, NoOpMutator)
     ->Args({0, 0});
+BENCHMARK_TEMPLATE(BM_UnaryPingPong, MinUDS, NoOpMutator, NoOpMutator)
+    ->Args({0, 0});
 BENCHMARK_TEMPLATE(BM_UnaryPingPong, SockPair, NoOpMutator, NoOpMutator)
     ->Args({0, 0});
+BENCHMARK_TEMPLATE(BM_UnaryPingPong, MinSockPair, NoOpMutator, NoOpMutator)
+    ->Args({0, 0});
 BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcessCHTTP2, NoOpMutator, NoOpMutator)
     ->Apply(SweepSizesArgs);
+BENCHMARK_TEMPLATE(BM_UnaryPingPong, MinInProcessCHTTP2, NoOpMutator,
+                   NoOpMutator)
+    ->Apply(SweepSizesArgs);
 BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcessCHTTP2,
                    Client_AddMetadata<RandomBinaryMetadata<10>, 1>, NoOpMutator)
     ->Args({0, 0});
diff --git a/test/cpp/microbenchmarks/fullstack_fixtures.h b/test/cpp/microbenchmarks/fullstack_fixtures.h
index acc56bf..f129ede 100644
--- a/test/cpp/microbenchmarks/fullstack_fixtures.h
+++ b/test/cpp/microbenchmarks/fullstack_fixtures.h
@@ -61,29 +61,33 @@
 namespace grpc {
 namespace testing {
 
-static void ApplyCommonServerBuilderConfig(ServerBuilder* b) {
-  b->SetMaxReceiveMessageSize(INT_MAX);
-  b->SetMaxSendMessageSize(INT_MAX);
-}
+class FixtureConfiguration {
+ public:
+  virtual void ApplyCommonChannelArguments(ChannelArguments* c) const {
+    c->SetInt(GRPC_ARG_MAX_RECEIVE_MESSAGE_LENGTH, INT_MAX);
+    c->SetInt(GRPC_ARG_MAX_SEND_MESSAGE_LENGTH, INT_MAX);
+  }
 
-static void ApplyCommonChannelArguments(ChannelArguments* c) {
-  c->SetInt(GRPC_ARG_MAX_RECEIVE_MESSAGE_LENGTH, INT_MAX);
-  c->SetInt(GRPC_ARG_MAX_SEND_MESSAGE_LENGTH, INT_MAX);
-}
+  virtual void ApplyCommonServerBuilderConfig(ServerBuilder* b) const {
+    b->SetMaxReceiveMessageSize(INT_MAX);
+    b->SetMaxSendMessageSize(INT_MAX);
+  }
+};
 
 class BaseFixture : public TrackCounters {};
 
 class FullstackFixture : public BaseFixture {
  public:
-  FullstackFixture(Service* service, const grpc::string& address) {
+  FullstackFixture(Service* service, const FixtureConfiguration& config,
+                   const grpc::string& address) {
     ServerBuilder b;
     b.AddListeningPort(address, InsecureServerCredentials());
     cq_ = b.AddCompletionQueue(true);
     b.RegisterService(service);
-    ApplyCommonServerBuilderConfig(&b);
+    config.ApplyCommonServerBuilderConfig(&b);
     server_ = b.BuildAndStart();
     ChannelArguments args;
-    ApplyCommonChannelArguments(&args);
+    config.ApplyCommonChannelArguments(&args);
     channel_ = CreateCustomChannel(address, InsecureChannelCredentials(), args);
   }
 
@@ -107,7 +111,9 @@
 
 class TCP : public FullstackFixture {
  public:
-  TCP(Service* service) : FullstackFixture(service, MakeAddress()) {}
+  TCP(Service* service, const FixtureConfiguration& fixture_configuration =
+                            FixtureConfiguration())
+      : FullstackFixture(service, fixture_configuration, MakeAddress()) {}
 
  private:
   static grpc::string MakeAddress() {
@@ -120,7 +126,9 @@
 
 class UDS : public FullstackFixture {
  public:
-  UDS(Service* service) : FullstackFixture(service, MakeAddress()) {}
+  UDS(Service* service, const FixtureConfiguration& fixture_configuration =
+                            FixtureConfiguration())
+      : FullstackFixture(service, fixture_configuration, MakeAddress()) {}
 
  private:
   static grpc::string MakeAddress() {
@@ -134,12 +142,13 @@
 
 class EndpointPairFixture : public BaseFixture {
  public:
-  EndpointPairFixture(Service* service, grpc_endpoint_pair endpoints)
+  EndpointPairFixture(Service* service, grpc_endpoint_pair endpoints,
+                      const FixtureConfiguration& fixture_configuration)
       : endpoint_pair_(endpoints) {
     ServerBuilder b;
     cq_ = b.AddCompletionQueue(true);
     b.RegisterService(service);
-    ApplyCommonServerBuilderConfig(&b);
+    fixture_configuration.ApplyCommonServerBuilderConfig(&b);
     server_ = b.BuildAndStart();
 
     grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
@@ -169,7 +178,7 @@
     {
       ChannelArguments args;
       args.SetString(GRPC_ARG_DEFAULT_AUTHORITY, "test.authority");
-      ApplyCommonChannelArguments(&args);
+      fixture_configuration.ApplyCommonChannelArguments(&args);
 
       grpc_channel_args c_args = args.c_channel_args();
       client_transport_ =
@@ -211,15 +220,19 @@
 
 class SockPair : public EndpointPairFixture {
  public:
-  SockPair(Service* service)
+  SockPair(Service* service, const FixtureConfiguration& fixture_configuration =
+                                 FixtureConfiguration())
       : EndpointPairFixture(service,
-                            grpc_iomgr_create_endpoint_pair("test", NULL)) {}
+                            grpc_iomgr_create_endpoint_pair("test", NULL),
+                            fixture_configuration) {}
 };
 
 class InProcessCHTTP2 : public EndpointPairFixture {
  public:
-  InProcessCHTTP2(Service* service)
-      : EndpointPairFixture(service, MakeEndpoints()) {}
+  InProcessCHTTP2(Service* service,
+                  const FixtureConfiguration& fixture_configuration =
+                      FixtureConfiguration())
+      : EndpointPairFixture(service, MakeEndpoints(), fixture_configuration) {}
 
   void AddToLabel(std::ostream& out, benchmark::State& state) {
     EndpointPairFixture::AddToLabel(out, state);
@@ -238,6 +251,32 @@
   }
 };
 
+////////////////////////////////////////////////////////////////////////////////
+// Minimal stack fixtures
+
+class MinStackConfiguration : public FixtureConfiguration {
+  void ApplyCommonChannelArguments(ChannelArguments* a) const override {
+    a->SetInt(GRPC_ARG_MINIMAL_STACK, 1);
+    FixtureConfiguration::ApplyCommonChannelArguments(a);
+  }
+
+  void ApplyCommonServerBuilderConfig(ServerBuilder* b) const override {
+    b->AddChannelArgument(GRPC_ARG_MINIMAL_STACK, 1);
+    FixtureConfiguration::ApplyCommonServerBuilderConfig(b);
+  }
+};
+
+template <class Base>
+class MinStackize : public Base {
+ public:
+  MinStackize(Service* service) : Base(service, MinStackConfiguration()) {}
+};
+
+typedef MinStackize<TCP> MinTCP;
+typedef MinStackize<UDS> MinUDS;
+typedef MinStackize<SockPair> MinSockPair;
+typedef MinStackize<InProcessCHTTP2> MinInProcessCHTTP2;
+
 }  // namespace testing
 }  // namespace grpc
 
diff --git a/test/cpp/util/BUILD b/test/cpp/util/BUILD
index dc90a4e..38f804f 100644
--- a/test/cpp/util/BUILD
+++ b/test/cpp/util/BUILD
@@ -62,7 +62,6 @@
 cc_library(
     name = "test_util",
     srcs = [
-        #        "test/cpp/end2end/test_service_impl.cc",
         "byte_buffer_proto_helper.cc",
         "create_test_channel.cc",
         "string_ref_helper.cc",
@@ -83,3 +82,18 @@
         "//test/core/util:gpr_test_util",
     ],
 )
+
+cc_test(
+    name = "error_details_test",
+    srcs = [
+        "error_details_test.cc",
+    ],
+    deps = [
+        "//:grpc++_error_details",
+        "//external:gtest",
+        "//src/proto/grpc/testing:echo_messages_proto",
+    ],
+)
+
+
+
diff --git a/test/cpp/util/error_details_test.cc b/test/cpp/util/error_details_test.cc
new file mode 100644
index 0000000..d01fd3b
--- /dev/null
+++ b/test/cpp/util/error_details_test.cc
@@ -0,0 +1,120 @@
+/*
+ *
+ * Copyright 2017, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc++/support/error_details.h>
+#include <gtest/gtest.h>
+
+#include "src/proto/grpc/status/status.pb.h"
+#include "src/proto/grpc/testing/echo_messages.pb.h"
+
+namespace grpc {
+namespace {
+
+TEST(ExtractTest, Success) {
+  google::rpc::Status expected;
+  expected.set_code(13);  // INTERNAL
+  expected.set_message("I am an error message");
+  testing::EchoRequest expected_details;
+  expected_details.set_message(grpc::string(100, '\0'));
+  expected.add_details()->PackFrom(expected_details);
+
+  google::rpc::Status to;
+  grpc::string error_details = expected.SerializeAsString();
+  Status from(static_cast<StatusCode>(expected.code()), expected.message(),
+              error_details);
+  EXPECT_TRUE(ExtractErrorDetails(from, &to).ok());
+  EXPECT_EQ(expected.code(), to.code());
+  EXPECT_EQ(expected.message(), to.message());
+  EXPECT_EQ(1, to.details_size());
+  testing::EchoRequest details;
+  to.details(0).UnpackTo(&details);
+  EXPECT_EQ(expected_details.message(), details.message());
+}
+
+TEST(ExtractTest, NullInput) {
+  EXPECT_EQ(StatusCode::FAILED_PRECONDITION,
+            ExtractErrorDetails(Status(), nullptr).error_code());
+}
+
+TEST(ExtractTest, Unparsable) {
+  grpc::string error_details("I am not a status object");
+  Status from(StatusCode::INTERNAL, "", error_details);
+  google::rpc::Status to;
+  EXPECT_EQ(StatusCode::INVALID_ARGUMENT,
+            ExtractErrorDetails(from, &to).error_code());
+}
+
+TEST(SetTest, Success) {
+  google::rpc::Status expected;
+  expected.set_code(13);  // INTERNAL
+  expected.set_message("I am an error message");
+  testing::EchoRequest expected_details;
+  expected_details.set_message(grpc::string(100, '\0'));
+  expected.add_details()->PackFrom(expected_details);
+
+  Status to;
+  Status s = SetErrorDetails(expected, &to);
+  EXPECT_TRUE(s.ok());
+  EXPECT_EQ(expected.code(), to.error_code());
+  EXPECT_EQ(expected.message(), to.error_message());
+  EXPECT_EQ(expected.SerializeAsString(), to.error_details());
+}
+
+TEST(SetTest, NullInput) {
+  EXPECT_EQ(StatusCode::FAILED_PRECONDITION,
+            SetErrorDetails(google::rpc::Status(), nullptr).error_code());
+}
+
+TEST(SetTest, OutOfScopeErrorCode) {
+  google::rpc::Status expected;
+  expected.set_code(20);  // Out of scope (DATA_LOSS is 15).
+  expected.set_message("I am an error message");
+  testing::EchoRequest expected_details;
+  expected_details.set_message(grpc::string(100, '\0'));
+  expected.add_details()->PackFrom(expected_details);
+
+  Status to;
+  Status s = SetErrorDetails(expected, &to);
+  EXPECT_TRUE(s.ok());
+  EXPECT_EQ(StatusCode::UNKNOWN, to.error_code());
+  EXPECT_EQ(expected.message(), to.error_message());
+  EXPECT_EQ(expected.SerializeAsString(), to.error_details());
+}
+
+}  // namespace
+}  // namespace grpc
+
+int main(int argc, char** argv) {
+  ::testing::InitGoogleTest(&argc, argv);
+  return RUN_ALL_TESTS();
+}
diff --git a/tools/codegen/core/gen_settings_ids.py b/tools/codegen/core/gen_settings_ids.py
new file mode 100755
index 0000000..a986138
--- /dev/null
+++ b/tools/codegen/core/gen_settings_ids.py
@@ -0,0 +1,184 @@
+#!/usr/bin/env python2.7
+
+# Copyright 2017, 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.
+
+import collections
+import perfection
+import sys
+
+_MAX_HEADER_LIST_SIZE = 16 * 1024 * 1024
+
+Setting = collections.namedtuple('Setting', 'id default min max on_error')
+OnError = collections.namedtuple('OnError', 'behavior code')
+clamp_invalid_value = OnError('CLAMP_INVALID_VALUE', 'PROTOCOL_ERROR')
+disconnect_on_invalid_value = lambda e: OnError('DISCONNECT_ON_INVALID_VALUE', e)
+DecoratedSetting = collections.namedtuple('DecoratedSetting', 'enum name setting')
+
+_SETTINGS = {
+  'HEADER_TABLE_SIZE': Setting(1, 4096, 0, 0xffffffff, clamp_invalid_value),
+  'ENABLE_PUSH': Setting(2, 1, 0, 1, disconnect_on_invalid_value('PROTOCOL_ERROR')),
+  'MAX_CONCURRENT_STREAMS': Setting(3, 0xffffffff, 0, 0xffffffff, disconnect_on_invalid_value('PROTOCOL_ERROR')),
+  'INITIAL_WINDOW_SIZE': Setting(4, 65535, 0, 0x7fffffff, disconnect_on_invalid_value('FLOW_CONTROL_ERROR')),
+  'MAX_FRAME_SIZE': Setting(5, 16384, 16384, 16777215, disconnect_on_invalid_value('PROTOCOL_ERROR')),
+  'MAX_HEADER_LIST_SIZE': Setting(6, _MAX_HEADER_LIST_SIZE, 0, _MAX_HEADER_LIST_SIZE, clamp_invalid_value),
+  'GRPC_ALLOW_TRUE_BINARY_METADATA': Setting(0xfe03, 0, 0, 1, clamp_invalid_value),
+}
+
+H = open('src/core/ext/transport/chttp2/transport/http2_settings.h', 'w')
+C = open('src/core/ext/transport/chttp2/transport/http2_settings.c', 'w')
+
+# utility: print a big comment block into a set of files
+def put_banner(files, banner):
+  for f in files:
+    print >>f, '/*'
+    for line in banner:
+      print >>f, ' * %s' % line
+    print >>f, ' */'
+    print >>f
+
+# copy-paste copyright notice from this file
+with open(sys.argv[0]) as my_source:
+  copyright = []
+  for line in my_source:
+    if line[0] != '#': break
+  for line in my_source:
+    if line[0] == '#':
+      copyright.append(line)
+      break
+  for line in my_source:
+    if line[0] != '#':
+      break
+    copyright.append(line)
+  put_banner([H,C], [line[2:].rstrip() for line in copyright])
+
+put_banner([H,C], ["Automatically generated by tools/codegen/core/gen_settings_ids.py"])
+
+print >>H, "#ifndef GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_HTTP2_SETTINGS_H"
+print >>H, "#define GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_HTTP2_SETTINGS_H"
+print >>H
+print >>H, "#include <stdint.h>"
+print >>H, "#include <stdbool.h>"
+print >>H
+
+print >>C, "#include \"src/core/ext/transport/chttp2/transport/http2_settings.h\""
+print >>C
+print >>C, "#include <grpc/support/useful.h>"
+print >>C, "#include \"src/core/lib/transport/http2_errors.h\""
+print >>C
+
+p = perfection.hash_parameters(sorted(x.id for x in _SETTINGS.values()))
+print p
+
+def hash(i):
+  i += p.offset
+  x = i % p.t
+  y = i / p.t
+  return x + p.r[y]
+
+decorated_settings = [DecoratedSetting(hash(setting.id), name, setting)
+                      for name, setting in _SETTINGS.iteritems()]
+
+print >>H, 'typedef enum {'
+for decorated_setting in sorted(decorated_settings):
+  print >>H, '  GRPC_CHTTP2_SETTINGS_%s = %d, /* wire id %d */' % (
+      decorated_setting.name, decorated_setting.enum, decorated_setting.setting.id)
+print >>H, '} grpc_chttp2_setting_id;'
+print >>H
+print >>H, '#define GRPC_CHTTP2_NUM_SETTINGS %d' % (max(x.enum for x in decorated_settings) + 1)
+
+print >>H, 'extern const uint16_t grpc_setting_id_to_wire_id[];'
+print >>C, 'const uint16_t grpc_setting_id_to_wire_id[] = {%s};' % ','.join(
+    '%d' % s for s in p.slots)
+print >>H
+print >>H, "bool grpc_wire_id_to_setting_id(uint32_t wire_id, grpc_chttp2_setting_id *out);"
+cgargs = {
+      'r': ','.join('%d' % (r if r is not None else 0) for r in p.r),
+      't': p.t,
+      'offset': abs(p.offset),
+      'offset_sign': '+' if p.offset > 0 else '-'
+  }
+print >>C, """
+bool grpc_wire_id_to_setting_id(uint32_t wire_id, grpc_chttp2_setting_id *out) {
+  uint32_t i = wire_id %(offset_sign)s %(offset)d;
+  uint32_t x = i %% %(t)d;
+  uint32_t y = i / %(t)d;
+  uint32_t h = x;
+  switch (y) {
+""" % cgargs
+for i, r in enumerate(p.r):
+  if not r: continue
+  if r < 0: print >>C, 'case %d: h -= %d; break;' % (i, -r)
+  else: print >>C, 'case %d: h += %d; break;' % (i, r)
+print >>C, """
+  }
+  *out = (grpc_chttp2_setting_id)h;
+  return h < GPR_ARRAY_SIZE(grpc_setting_id_to_wire_id) && grpc_setting_id_to_wire_id[h] == wire_id;
+}
+""" % cgargs
+
+print >>H, """
+typedef enum {
+  GRPC_CHTTP2_CLAMP_INVALID_VALUE,
+  GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE
+} grpc_chttp2_invalid_value_behavior;
+
+typedef struct {
+  const char *name;
+  uint32_t default_value;
+  uint32_t min_value;
+  uint32_t max_value;
+  grpc_chttp2_invalid_value_behavior invalid_value_behavior;
+  uint32_t error_value;
+} grpc_chttp2_setting_parameters;
+
+extern const grpc_chttp2_setting_parameters grpc_chttp2_settings_parameters[GRPC_CHTTP2_NUM_SETTINGS];
+"""
+print >>C, "const grpc_chttp2_setting_parameters grpc_chttp2_settings_parameters[GRPC_CHTTP2_NUM_SETTINGS] = {"
+i = 0
+for decorated_setting in sorted(decorated_settings):
+  while i < decorated_setting.enum:
+    print >>C, "{NULL, 0, 0, 0, GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE, GRPC_HTTP2_PROTOCOL_ERROR},"
+    i += 1
+  print >>C, "{\"%s\", %du, %du, %du, GRPC_CHTTP2_%s, GRPC_HTTP2_%s}," % (
+    decorated_setting.name,
+    decorated_setting.setting.default,
+    decorated_setting.setting.min,
+    decorated_setting.setting.max,
+    decorated_setting.setting.on_error.behavior,
+    decorated_setting.setting.on_error.code,
+  )
+  i += 1
+print >>C, "};"
+
+print >>H
+print >>H, "#endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_HTTP2_SETTINGS_H */"
+
+H.close()
+C.close()
diff --git a/tools/codegen/core/gen_static_metadata.py b/tools/codegen/core/gen_static_metadata.py
index 109701f..360b0f5 100755
--- a/tools/codegen/core/gen_static_metadata.py
+++ b/tools/codegen/core/gen_static_metadata.py
@@ -56,8 +56,9 @@
     ':authority',
     'grpc-message',
     'grpc-status',
-    'grpc-tracing-bin',
-    'grpc-stats-bin',
+    'grpc-server-stats-bin',
+    'grpc-tags-bin',
+    'grpc-trace-bin',
     '',
     # channel arg keys
     'grpc.wait_for_ready',
@@ -123,6 +124,7 @@
     ('if-unmodified-since', ''),
     ('last-modified', ''),
     ('lb-token', ''),
+    ('lb-cost-bin', ''),
     ('link', ''),
     ('location', ''),
     ('max-forwards', ''),
@@ -154,6 +156,9 @@
     'grpc-payload-bin',
     'grpc-encoding',
     'grpc-accept-encoding',
+    'grpc-server-stats-bin',
+    'grpc-tags-bin',
+    'grpc-trace-bin',
     'content-type',
     'grpc-internal-encoding-request',
     'user-agent',
@@ -167,6 +172,7 @@
     'gzip',
 ]
 
+
 # utility: mangle the name of a config
 def mangle(elem, name=None):
   xl = {
@@ -177,43 +183,56 @@
       ',': 'comma',
       ' ': '_',
   }
+
   def m0(x):
-    if not x: return 'empty'
+    if not x:
+      return 'empty'
     r = ''
     for c in x:
       put = xl.get(c, c.lower())
-      if not put: continue
+      if not put:
+        continue
       last_is_underscore = r[-1] == '_' if r else True
-      if last_is_underscore and put == '_': continue
+      if last_is_underscore and put == '_':
+        continue
       elif len(put) > 1:
-        if not last_is_underscore: r += '_'
+        if not last_is_underscore:
+          r += '_'
         r += put
         r += '_'
       else:
         r += put
-    if r[-1] == '_': r = r[:-1]
+    if r[-1] == '_':
+      r = r[:-1]
     return r
+
   def n(default, name=name):
-    if name is None: return 'grpc_%s_' % default
-    if name == '': return ''
+    if name is None:
+      return 'grpc_%s_' % default
+    if name == '':
+      return ''
     return 'grpc_%s_' % name
+
   if isinstance(elem, tuple):
     return '%s%s_%s' % (n('mdelem'), m0(elem[0]), m0(elem[1]))
   else:
     return '%s%s' % (n('mdstr'), m0(elem))
 
+
 # utility: generate some hash value for a string
 def fake_hash(elem):
   return hashlib.md5(elem).hexdigest()[0:8]
 
+
 # utility: print a big comment block into a set of files
 def put_banner(files, banner):
   for f in files:
-    print >>f, '/*'
+    print >> f, '/*'
     for line in banner:
-      print >>f, ' * %s' % line
-    print >>f, ' */'
-    print >>f
+      print >> f, ' * %s' % line
+    print >> f, ' */'
+    print >> f
+
 
 # build a list of all the strings we need
 all_strs = list()
@@ -236,7 +255,7 @@
     if elem not in all_strs:
       all_strs.append(elem)
 compression_elems = []
-for mask in range(1, 1<<len(COMPRESSION_ALGORITHMS)):
+for mask in range(1, 1 << len(COMPRESSION_ALGORITHMS)):
   val = ','.join(COMPRESSION_ALGORITHMS[alg]
                  for alg in range(0, len(COMPRESSION_ALGORITHMS))
                  if (1 << alg) & mask)
@@ -267,18 +286,25 @@
   else:
     D = open('/dev/null', 'w')
 else:
-  H = open(os.path.join(
-      os.path.dirname(sys.argv[0]), '../../../src/core/lib/transport/static_metadata.h'), 'w')
-  C = open(os.path.join(
-      os.path.dirname(sys.argv[0]), '../../../src/core/lib/transport/static_metadata.c'), 'w')
-  D = open(os.path.join(
-      os.path.dirname(sys.argv[0]), '../../../test/core/end2end/fuzzers/hpack.dictionary'), 'w')
+  H = open(
+      os.path.join(
+          os.path.dirname(sys.argv[0]),
+          '../../../src/core/lib/transport/static_metadata.h'), 'w')
+  C = open(
+      os.path.join(
+          os.path.dirname(sys.argv[0]),
+          '../../../src/core/lib/transport/static_metadata.c'), 'w')
+  D = open(
+      os.path.join(
+          os.path.dirname(sys.argv[0]),
+          '../../../test/core/end2end/fuzzers/hpack.dictionary'), 'w')
 
 # copy-paste copyright notice from this file
 with open(sys.argv[0]) as my_source:
   copyright = []
   for line in my_source:
-    if line[0] != '#': break
+    if line[0] != '#':
+      break
   for line in my_source:
     if line[0] == '#':
       copyright.append(line)
@@ -287,10 +313,9 @@
     if line[0] != '#':
       break
     copyright.append(line)
-  put_banner([H,C], [line[2:].rstrip() for line in copyright])
+  put_banner([H, C], [line[2:].rstrip() for line in copyright])
 
-
-hex_bytes = [ord(c) for c in "abcdefABCDEF0123456789"]
+hex_bytes = [ord(c) for c in 'abcdefABCDEF0123456789']
 
 
 def esc_dict(line):
@@ -302,11 +327,11 @@
       else:
         out += "\\\""
     else:
-      out += "\\x%02X" % c
+      out += '\\x%02X' % c
   return out + "\""
 
-put_banner([H,C],
-"""WARNING: Auto-generated code.
+
+put_banner([H, C], """WARNING: Auto-generated code.
 
 To make changes to this file, change
 tools/codegen/core/gen_static_metadata.py, and then re-run it.
@@ -315,108 +340,143 @@
 an explanation of what's going on.
 """.splitlines())
 
-print >>H, '#ifndef GRPC_CORE_LIB_TRANSPORT_STATIC_METADATA_H'
-print >>H, '#define GRPC_CORE_LIB_TRANSPORT_STATIC_METADATA_H'
-print >>H
-print >>H, '#include "src/core/lib/transport/metadata.h"'
-print >>H
+print >> H, '#ifndef GRPC_CORE_LIB_TRANSPORT_STATIC_METADATA_H'
+print >> H, '#define GRPC_CORE_LIB_TRANSPORT_STATIC_METADATA_H'
+print >> H
+print >> H, '#include "src/core/lib/transport/metadata.h"'
+print >> H
 
-print >>C, '#include "src/core/lib/transport/static_metadata.h"'
-print >>C
-print >>C, '#include "src/core/lib/slice/slice_internal.h"'
-print >>C
+print >> C, '#include "src/core/lib/transport/static_metadata.h"'
+print >> C
+print >> C, '#include "src/core/lib/slice/slice_internal.h"'
+print >> C
 
 str_ofs = 0
 id2strofs = {}
 for i, elem in enumerate(all_strs):
   id2strofs[i] = str_ofs
-  str_ofs += len(elem);
+  str_ofs += len(elem)
+
+
 def slice_def(i):
-  return '{.refcount = &grpc_static_metadata_refcounts[%d], .data.refcounted = {g_bytes+%d, %d}}' % (i, id2strofs[i], len(all_strs[i]))
+  return ('{.refcount = &grpc_static_metadata_refcounts[%d], .data.refcounted ='
+          ' {g_bytes+%d, %d}}') % (
+      i, id2strofs[i], len(all_strs[i]))
+
 
 # validate configuration
 for elem in METADATA_BATCH_CALLOUTS:
   assert elem in all_strs
 
-print >>H, '#define GRPC_STATIC_MDSTR_COUNT %d' % len(all_strs)
-print >>H, 'extern const grpc_slice grpc_static_slice_table[GRPC_STATIC_MDSTR_COUNT];'
+print >> H, '#define GRPC_STATIC_MDSTR_COUNT %d' % len(all_strs)
+print >> H, ('extern const grpc_slice '
+             'grpc_static_slice_table[GRPC_STATIC_MDSTR_COUNT];')
 for i, elem in enumerate(all_strs):
-  print >>H, '/* "%s" */' % elem
-  print >>H, '#define %s (grpc_static_slice_table[%d])' % (mangle(elem).upper(), i)
-print >>H
-print >>C, 'static uint8_t g_bytes[] = {%s};' % (','.join('%d' % ord(c) for c in ''.join(all_strs)))
-print >>C
-print >>C, 'static void static_ref(void *unused) {}'
-print >>C, 'static void static_unref(grpc_exec_ctx *exec_ctx, void *unused) {}'
-print >>C, 'static const grpc_slice_refcount_vtable static_sub_vtable = {static_ref, static_unref, grpc_slice_default_eq_impl, grpc_slice_default_hash_impl};';
-print >>H, 'extern const grpc_slice_refcount_vtable grpc_static_metadata_vtable;';
-print >>C, 'const grpc_slice_refcount_vtable grpc_static_metadata_vtable = {static_ref, static_unref, grpc_static_slice_eq, grpc_static_slice_hash};';
-print >>C, 'static grpc_slice_refcount static_sub_refcnt = {&static_sub_vtable, &static_sub_refcnt};';
-print >>H, 'extern grpc_slice_refcount grpc_static_metadata_refcounts[GRPC_STATIC_MDSTR_COUNT];'
-print >>C, 'grpc_slice_refcount grpc_static_metadata_refcounts[GRPC_STATIC_MDSTR_COUNT] = {'
+  print >> H, '/* "%s" */' % elem
+  print >> H, '#define %s (grpc_static_slice_table[%d])' % (
+      mangle(elem).upper(), i)
+print >> H
+print >> C, 'static uint8_t g_bytes[] = {%s};' % (
+    ','.join('%d' % ord(c) for c in ''.join(all_strs)))
+print >> C
+print >> C, 'static void static_ref(void *unused) {}'
+print >> C, 'static void static_unref(grpc_exec_ctx *exec_ctx, void *unused) {}'
+print >> C, ('static const grpc_slice_refcount_vtable static_sub_vtable = '
+             '{static_ref, static_unref, grpc_slice_default_eq_impl, '
+             'grpc_slice_default_hash_impl};')
+print >> H, ('extern const grpc_slice_refcount_vtable '
+             'grpc_static_metadata_vtable;')
+print >> C, ('const grpc_slice_refcount_vtable grpc_static_metadata_vtable = '
+             '{static_ref, static_unref, grpc_static_slice_eq, '
+             'grpc_static_slice_hash};')
+print >> C, ('static grpc_slice_refcount static_sub_refcnt = '
+             '{&static_sub_vtable, &static_sub_refcnt};')
+print >> H, ('extern grpc_slice_refcount '
+             'grpc_static_metadata_refcounts[GRPC_STATIC_MDSTR_COUNT];')
+print >> C, ('grpc_slice_refcount '
+             'grpc_static_metadata_refcounts[GRPC_STATIC_MDSTR_COUNT] = {')
 for i, elem in enumerate(all_strs):
-  print >>C, '  {&grpc_static_metadata_vtable, &static_sub_refcnt},'
-print >>C, '};'
-print >>C
-print >>H, '#define GRPC_IS_STATIC_METADATA_STRING(slice) \\'
-print >>H, '  ((slice).refcount != NULL && (slice).refcount->vtable == &grpc_static_metadata_vtable)'
-print >>H
-print >>C, 'const grpc_slice grpc_static_slice_table[GRPC_STATIC_MDSTR_COUNT] = {'
+  print >> C, '  {&grpc_static_metadata_vtable, &static_sub_refcnt},'
+print >> C, '};'
+print >> C
+print >> H, '#define GRPC_IS_STATIC_METADATA_STRING(slice) \\'
+print >> H, ('  ((slice).refcount != NULL && (slice).refcount->vtable == '
+             '&grpc_static_metadata_vtable)')
+print >> H
+print >> C, ('const grpc_slice grpc_static_slice_table[GRPC_STATIC_MDSTR_COUNT]'
+             ' = {')
 for i, elem in enumerate(all_strs):
-  print >>C, slice_def(i) + ','
-print >>C, '};'
-print >>C
-print >>H, '#define GRPC_STATIC_METADATA_INDEX(static_slice) \\'
-print >>H, '  ((int)((static_slice).refcount - grpc_static_metadata_refcounts))'
-print >>H
+  print >> C, slice_def(i) + ','
+print >> C, '};'
+print >> C
+print >> H, '#define GRPC_STATIC_METADATA_INDEX(static_slice) \\'
+print >> H, ('  ((int)((static_slice).refcount - '
+             'grpc_static_metadata_refcounts))')
+print >> H
 
-print >>D, '# hpack fuzzing dictionary'
+print >> D, '# hpack fuzzing dictionary'
 for i, elem in enumerate(all_strs):
-  print >>D, '%s' % (esc_dict([len(elem)] + [ord(c) for c in elem]))
+  print >> D, '%s' % (esc_dict([len(elem)] + [ord(c) for c in elem]))
 for i, elem in enumerate(all_elems):
-  print >>D, '%s' % (esc_dict([0, len(elem[0])] + [ord(c) for c in elem[0]] +
-                              [len(elem[1])] + [ord(c) for c in elem[1]]))
+  print >> D, '%s' % (esc_dict([0, len(elem[0])] + [ord(c) for c in elem[0]] +
+                               [len(elem[1])] + [ord(c) for c in elem[1]]))
 
-print >>H, '#define GRPC_STATIC_MDELEM_COUNT %d' % len(all_elems)
-print >>H, 'extern grpc_mdelem_data grpc_static_mdelem_table[GRPC_STATIC_MDELEM_COUNT];'
-print >>H, 'extern uintptr_t grpc_static_mdelem_user_data[GRPC_STATIC_MDELEM_COUNT];'
+print >> H, '#define GRPC_STATIC_MDELEM_COUNT %d' % len(all_elems)
+print >> H, ('extern grpc_mdelem_data '
+             'grpc_static_mdelem_table[GRPC_STATIC_MDELEM_COUNT];')
+print >> H, ('extern uintptr_t '
+             'grpc_static_mdelem_user_data[GRPC_STATIC_MDELEM_COUNT];')
 for i, elem in enumerate(all_elems):
-  print >>H, '/* "%s": "%s" */' % elem
-  print >>H, '#define %s (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[%d], GRPC_MDELEM_STORAGE_STATIC))' % (mangle(elem).upper(), i)
-print >>H
-print >>C, 'uintptr_t grpc_static_mdelem_user_data[GRPC_STATIC_MDELEM_COUNT] = {'
-print >>C, '  %s' % ','.join('%d' % static_userdata.get(elem, 0) for elem in all_elems)
-print >>C, '};'
-print >>C
+  print >> H, '/* "%s": "%s" */' % elem
+  print >> H, ('#define %s (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[%d], '
+               'GRPC_MDELEM_STORAGE_STATIC))') % (
+      mangle(elem).upper(), i)
+print >> H
+print >> C, ('uintptr_t grpc_static_mdelem_user_data[GRPC_STATIC_MDELEM_COUNT] '
+             '= {')
+print >> C, '  %s' % ','.join('%d' % static_userdata.get(elem, 0)
+                              for elem in all_elems)
+print >> C, '};'
+print >> C
+
 
 def str_idx(s):
   for i, s2 in enumerate(all_strs):
     if s == s2:
       return i
 
+
 def md_idx(m):
   for i, m2 in enumerate(all_elems):
     if m == m2:
       return i
 
+
 def offset_trials(mink):
   yield 0
   for i in range(1, 100):
     for mul in [-1, 1]:
       yield mul * i
 
+
 def perfect_hash(keys, name):
   p = perfection.hash_parameters(keys)
+
   def f(i, p=p):
     i += p.offset
     x = i % p.t
     y = i / p.t
     return x + p.r[y]
+
   return {
-    'PHASHRANGE': p.t - 1 + max(p.r),
-    'PHASHNKEYS': len(p.slots),
-    'pyfunc': f,
-    'code': """
+      'PHASHRANGE':
+          p.t - 1 + max(p.r),
+      'PHASHNKEYS':
+          len(p.slots),
+      'pyfunc':
+          f,
+      'code':
+          """
 static const int8_t %(name)s_r[] = {%(r)s};
 static uint32_t %(name)s_phash(uint32_t i) {
   i %(offset_sign)s= %(offset)d;
@@ -430,71 +490,77 @@
   return h;
 }
     """ % {
-      'name': name,
-      'r': ','.join('%d' % (r if r is not None else 0) for r in p.r),
-      't': p.t,
-      'offset': abs(p.offset),
-      'offset_sign': '+' if p.offset > 0 else '-'
+        'name': name,
+        'r': ','.join('%d' % (r if r is not None else 0) for r in p.r),
+        't': p.t,
+        'offset': abs(p.offset),
+        'offset_sign': '+' if p.offset > 0 else '-'
     }
   }
 
 
-elem_keys = [str_idx(elem[0]) * len(all_strs) + str_idx(elem[1]) for elem in all_elems]
-elem_hash = perfect_hash(elem_keys, "elems")
-print >>C, elem_hash['code']
+elem_keys = [
+    str_idx(elem[0]) * len(all_strs) + str_idx(elem[1]) for elem in all_elems
+]
+elem_hash = perfect_hash(elem_keys, 'elems')
+print >> C, elem_hash['code']
 
 keys = [0] * int(elem_hash['PHASHRANGE'])
 idxs = [255] * int(elem_hash['PHASHNKEYS'])
 for i, k in enumerate(elem_keys):
-    h = elem_hash['pyfunc'](k)
-    assert keys[h] == 0
-    keys[h] = k
-    idxs[h] = i
-print >>C, 'static const uint16_t elem_keys[] = {%s};' % ','.join('%d' % k for k in keys)
-print >>C, 'static const uint8_t elem_idxs[] = {%s};' % ','.join('%d' % i for i in idxs)
-print >>C
+  h = elem_hash['pyfunc'](k)
+  assert keys[h] == 0
+  keys[h] = k
+  idxs[h] = i
+print >> C, 'static const uint16_t elem_keys[] = {%s};' % ','.join(
+    '%d' % k for k in keys)
+print >> C, 'static const uint8_t elem_idxs[] = {%s};' % ','.join(
+    '%d' % i for i in idxs)
+print >> C
 
-print >>H, 'grpc_mdelem grpc_static_mdelem_for_static_strings(int a, int b);'
-print >>C, 'grpc_mdelem grpc_static_mdelem_for_static_strings(int a, int b) {'
-print >>C, '  if (a == -1 || b == -1) return GRPC_MDNULL;'
-print >>C, '  uint32_t k = (uint32_t)(a * %d + b);' % len(all_strs)
-print >>C, '  uint32_t h = elems_phash(k);'
-print >>C, '  return h < GPR_ARRAY_SIZE(elem_keys) && elem_keys[h] == k ? GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[elem_idxs[h]], GRPC_MDELEM_STORAGE_STATIC) : GRPC_MDNULL;'
-print >>C, '}'
-print >>C
+print >> H, 'grpc_mdelem grpc_static_mdelem_for_static_strings(int a, int b);'
+print >> C, 'grpc_mdelem grpc_static_mdelem_for_static_strings(int a, int b) {'
+print >> C, '  if (a == -1 || b == -1) return GRPC_MDNULL;'
+print >> C, '  uint32_t k = (uint32_t)(a * %d + b);' % len(all_strs)
+print >> C, '  uint32_t h = elems_phash(k);'
+print >> C, '  return h < GPR_ARRAY_SIZE(elem_keys) && elem_keys[h] == k ? GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[elem_idxs[h]], GRPC_MDELEM_STORAGE_STATIC) : GRPC_MDNULL;'
+print >> C, '}'
+print >> C
 
-print >>C, 'grpc_mdelem_data grpc_static_mdelem_table[GRPC_STATIC_MDELEM_COUNT] = {'
+print >> C, 'grpc_mdelem_data grpc_static_mdelem_table[GRPC_STATIC_MDELEM_COUNT] = {'
 for a, b in all_elems:
-  print >>C, '{%s,%s},' % (slice_def(str_idx(a)), slice_def(str_idx(b)))
-print >>C, '};'
+  print >> C, '{%s,%s},' % (slice_def(str_idx(a)), slice_def(str_idx(b)))
+print >> C, '};'
 
-print >>H, 'typedef enum {'
+print >> H, 'typedef enum {'
 for elem in METADATA_BATCH_CALLOUTS:
-  print >>H, '  %s,' % mangle(elem, 'batch').upper()
-print >>H, '  GRPC_BATCH_CALLOUTS_COUNT'
-print >>H, '} grpc_metadata_batch_callouts_index;'
-print >>H
-print >>H, 'typedef union {'
-print >>H, '  struct grpc_linked_mdelem *array[GRPC_BATCH_CALLOUTS_COUNT];'
-print >>H, '  struct {'
+  print >> H, '  %s,' % mangle(elem, 'batch').upper()
+print >> H, '  GRPC_BATCH_CALLOUTS_COUNT'
+print >> H, '} grpc_metadata_batch_callouts_index;'
+print >> H
+print >> H, 'typedef union {'
+print >> H, '  struct grpc_linked_mdelem *array[GRPC_BATCH_CALLOUTS_COUNT];'
+print >> H, '  struct {'
 for elem in METADATA_BATCH_CALLOUTS:
-  print >>H, '  struct grpc_linked_mdelem *%s;' % mangle(elem, '').lower()
-print >>H, '  } named;'
-print >>H, '} grpc_metadata_batch_callouts;'
-print >>H
-print >>H, '#define GRPC_BATCH_INDEX_OF(slice) \\'
-print >>H, '  (GRPC_IS_STATIC_METADATA_STRING((slice)) ? (grpc_metadata_batch_callouts_index)GPR_CLAMP(GRPC_STATIC_METADATA_INDEX((slice)), 0, GRPC_BATCH_CALLOUTS_COUNT) : GRPC_BATCH_CALLOUTS_COUNT)'
-print >>H
+  print >> H, '  struct grpc_linked_mdelem *%s;' % mangle(elem, '').lower()
+print >> H, '  } named;'
+print >> H, '} grpc_metadata_batch_callouts;'
+print >> H
+print >> H, '#define GRPC_BATCH_INDEX_OF(slice) \\'
+print >> H, '  (GRPC_IS_STATIC_METADATA_STRING((slice)) ? (grpc_metadata_batch_callouts_index)GPR_CLAMP(GRPC_STATIC_METADATA_INDEX((slice)), 0, GRPC_BATCH_CALLOUTS_COUNT) : GRPC_BATCH_CALLOUTS_COUNT)'
+print >> H
 
-print >>H, 'extern const uint8_t grpc_static_accept_encoding_metadata[%d];' % (1 << len(COMPRESSION_ALGORITHMS))
-print >>C, 'const uint8_t grpc_static_accept_encoding_metadata[%d] = {' % (1 << len(COMPRESSION_ALGORITHMS))
-print >>C, '0,%s' % ','.join('%d' % md_idx(elem) for elem in compression_elems)
-print >>C, '};'
-print >>C
+print >> H, 'extern const uint8_t grpc_static_accept_encoding_metadata[%d];' % (
+    1 << len(COMPRESSION_ALGORITHMS))
+print >> C, 'const uint8_t grpc_static_accept_encoding_metadata[%d] = {' % (
+    1 << len(COMPRESSION_ALGORITHMS))
+print >> C, '0,%s' % ','.join('%d' % md_idx(elem) for elem in compression_elems)
+print >> C, '};'
+print >> C
 
-print >>H, '#define GRPC_MDELEM_ACCEPT_ENCODING_FOR_ALGORITHMS(algs) (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[grpc_static_accept_encoding_metadata[(algs)]], GRPC_MDELEM_STORAGE_STATIC))'
+print >> H, '#define GRPC_MDELEM_ACCEPT_ENCODING_FOR_ALGORITHMS(algs) (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[grpc_static_accept_encoding_metadata[(algs)]], GRPC_MDELEM_STORAGE_STATIC))'
 
-print >>H, '#endif /* GRPC_CORE_LIB_TRANSPORT_STATIC_METADATA_H */'
+print >> H, '#endif /* GRPC_CORE_LIB_TRANSPORT_STATIC_METADATA_H */'
 
 H.close()
 C.close()
diff --git a/tools/distrib/check_copyright.py b/tools/distrib/check_copyright.py
index 42005e3..0a58adf 100755
--- a/tools/distrib/check_copyright.py
+++ b/tools/distrib/check_copyright.py
@@ -113,6 +113,8 @@
   'src/php/tests/bootstrap.php',
   # census.proto copied from github
   'tools/grpcz/census.proto',
+  # status.proto copied from googleapis
+  'src/proto/grpc/status/status.proto',
 ))
 
 
diff --git a/tools/distrib/python/grpcio_tools/grpc_version.py b/tools/distrib/python/grpcio_tools/grpc_version.py
index ad35b90..1f2aa81 100644
--- a/tools/distrib/python/grpcio_tools/grpc_version.py
+++ b/tools/distrib/python/grpcio_tools/grpc_version.py
@@ -29,4 +29,4 @@
 
 # AUTO-GENERATED FROM `$REPO_ROOT/templates/tools/distrib/python/grpcio_tools/grpc_version.py.template`!!!
 
-VERSION='1.3.0.dev0'
+VERSION='1.4.0.dev0'
diff --git a/tools/doxygen/Doxyfile.c++ b/tools/doxygen/Doxyfile.c++
index 59e6197..1864dd9 100644
--- a/tools/doxygen/Doxyfile.c++
+++ b/tools/doxygen/Doxyfile.c++
@@ -40,7 +40,7 @@
 # could be handy for archiving the generated documentation or if some version
 # control system is used.
 
-PROJECT_NUMBER         = 1.3.0-dev
+PROJECT_NUMBER         = 1.4.0-dev
 
 # Using the PROJECT_BRIEF tag one can provide an optional one line description
 # for a project that appears at the top of each page and should give viewer a
diff --git a/tools/doxygen/Doxyfile.c++.internal b/tools/doxygen/Doxyfile.c++.internal
index afab2296..ca3514b 100644
--- a/tools/doxygen/Doxyfile.c++.internal
+++ b/tools/doxygen/Doxyfile.c++.internal
@@ -40,7 +40,7 @@
 # could be handy for archiving the generated documentation or if some version
 # control system is used.
 
-PROJECT_NUMBER         = 1.3.0-dev
+PROJECT_NUMBER         = 1.4.0-dev
 
 # Using the PROJECT_BRIEF tag one can provide an optional one line description
 # for a project that appears at the top of each page and should give viewer a
@@ -906,25 +906,15 @@
 src/core/lib/channel/channel_stack.h \
 src/core/lib/channel/channel_stack_builder.c \
 src/core/lib/channel/channel_stack_builder.h \
-src/core/lib/channel/compress_filter.c \
-src/core/lib/channel/compress_filter.h \
 src/core/lib/channel/connected_channel.c \
 src/core/lib/channel/connected_channel.h \
 src/core/lib/channel/context.h \
-src/core/lib/channel/deadline_filter.c \
-src/core/lib/channel/deadline_filter.h \
 src/core/lib/channel/handshaker.c \
 src/core/lib/channel/handshaker.h \
 src/core/lib/channel/handshaker_factory.c \
 src/core/lib/channel/handshaker_factory.h \
 src/core/lib/channel/handshaker_registry.c \
 src/core/lib/channel/handshaker_registry.h \
-src/core/lib/channel/http_client_filter.c \
-src/core/lib/channel/http_client_filter.h \
-src/core/lib/channel/http_server_filter.c \
-src/core/lib/channel/http_server_filter.h \
-src/core/lib/channel/message_size_filter.c \
-src/core/lib/channel/message_size_filter.h \
 src/core/lib/compression/algorithm_metadata.h \
 src/core/lib/compression/compression.c \
 src/core/lib/compression/message_compress.c \
diff --git a/tools/doxygen/Doxyfile.core b/tools/doxygen/Doxyfile.core
index e6ca9cb..c3bfc6c 100644
--- a/tools/doxygen/Doxyfile.core
+++ b/tools/doxygen/Doxyfile.core
@@ -40,7 +40,7 @@
 # could be handy for archiving the generated documentation or if some version
 # control system is used.
 
-PROJECT_NUMBER         = 3.0.0-dev
+PROJECT_NUMBER         = 4.0.0-dev
 
 # Using the PROJECT_BRIEF tag one can provide an optional one line description
 # for a project that appears at the top of each page and should give viewer a
diff --git a/tools/doxygen/Doxyfile.core.internal b/tools/doxygen/Doxyfile.core.internal
index ee1fd1b..924595e 100644
--- a/tools/doxygen/Doxyfile.core.internal
+++ b/tools/doxygen/Doxyfile.core.internal
@@ -40,7 +40,7 @@
 # could be handy for archiving the generated documentation or if some version
 # control system is used.
 
-PROJECT_NUMBER         = 3.0.0-dev
+PROJECT_NUMBER         = 4.0.0-dev
 
 # Using the PROJECT_BRIEF tag one can provide an optional one line description
 # for a project that appears at the top of each page and should give viewer a
@@ -954,12 +954,23 @@
 src/core/ext/filters/client_channel/subchannel_index.h \
 src/core/ext/filters/client_channel/uri_parser.c \
 src/core/ext/filters/client_channel/uri_parser.h \
+src/core/ext/filters/deadline/deadline_filter.c \
+src/core/ext/filters/deadline/deadline_filter.h \
+src/core/ext/filters/http/client/http_client_filter.c \
+src/core/ext/filters/http/client/http_client_filter.h \
+src/core/ext/filters/http/http_filters_plugin.c \
+src/core/ext/filters/http/message_compress/message_compress_filter.c \
+src/core/ext/filters/http/message_compress/message_compress_filter.h \
+src/core/ext/filters/http/server/http_server_filter.c \
+src/core/ext/filters/http/server/http_server_filter.h \
 src/core/ext/filters/load_reporting/load_reporting.c \
 src/core/ext/filters/load_reporting/load_reporting.h \
 src/core/ext/filters/load_reporting/load_reporting_filter.c \
 src/core/ext/filters/load_reporting/load_reporting_filter.h \
 src/core/ext/filters/max_age/max_age_filter.c \
 src/core/ext/filters/max_age/max_age_filter.h \
+src/core/ext/filters/message_size/message_size_filter.c \
+src/core/ext/filters/message_size/message_size_filter.h \
 src/core/ext/transport/README.md \
 src/core/ext/transport/chttp2/README.md \
 src/core/ext/transport/chttp2/alpn/alpn.c \
@@ -1005,6 +1016,8 @@
 src/core/ext/transport/chttp2/transport/hpack_parser.h \
 src/core/ext/transport/chttp2/transport/hpack_table.c \
 src/core/ext/transport/chttp2/transport/hpack_table.h \
+src/core/ext/transport/chttp2/transport/http2_settings.c \
+src/core/ext/transport/chttp2/transport/http2_settings.h \
 src/core/ext/transport/chttp2/transport/huffsyms.c \
 src/core/ext/transport/chttp2/transport/huffsyms.h \
 src/core/ext/transport/chttp2/transport/incoming_metadata.c \
@@ -1025,25 +1038,15 @@
 src/core/lib/channel/channel_stack.h \
 src/core/lib/channel/channel_stack_builder.c \
 src/core/lib/channel/channel_stack_builder.h \
-src/core/lib/channel/compress_filter.c \
-src/core/lib/channel/compress_filter.h \
 src/core/lib/channel/connected_channel.c \
 src/core/lib/channel/connected_channel.h \
 src/core/lib/channel/context.h \
-src/core/lib/channel/deadline_filter.c \
-src/core/lib/channel/deadline_filter.h \
 src/core/lib/channel/handshaker.c \
 src/core/lib/channel/handshaker.h \
 src/core/lib/channel/handshaker_factory.c \
 src/core/lib/channel/handshaker_factory.h \
 src/core/lib/channel/handshaker_registry.c \
 src/core/lib/channel/handshaker_registry.h \
-src/core/lib/channel/http_client_filter.c \
-src/core/lib/channel/http_client_filter.h \
-src/core/lib/channel/http_server_filter.c \
-src/core/lib/channel/http_server_filter.h \
-src/core/lib/channel/message_size_filter.c \
-src/core/lib/channel/message_size_filter.h \
 src/core/lib/compression/algorithm_metadata.h \
 src/core/lib/compression/compression.c \
 src/core/lib/compression/message_compress.c \
diff --git a/tools/gce/linux_performance_worker_init.sh b/tools/gce/linux_performance_worker_init.sh
index 6412712..17f36fb 100755
--- a/tools/gce/linux_performance_worker_init.sh
+++ b/tools/gce/linux_performance_worker_init.sh
@@ -40,11 +40,6 @@
 sudo apt-get install -y openjdk-8-jdk
 sudo apt-get install -y unzip lsof
 
-# Add pubkey of jenkins@grpc-jenkins-master to authorized keys of jenkins@
-# This needs to happen as the last step to prevent Jenkins master from connecting
-# to a machine that hasn't been properly setup yet.
-cat jenkins_master.pub | sudo tee --append ~jenkins/.ssh/authorized_keys
-
 sudo apt-get install -y \
   autoconf \
   autotools-dev \
@@ -169,3 +164,21 @@
 
 # Install scipy and numpy for benchmarking scripts
 sudo apt-get install python-scipy python-numpy
+
+# Update Linux kernel to 4.9
+wget \
+  kernel.ubuntu.com/~kernel-ppa/mainline/v4.9.20/linux-headers-4.9.20-040920_4.9.20-040920.201703310531_all.deb \
+  kernel.ubuntu.com/~kernel-ppa/mainline/v4.9.20/linux-headers-4.9.20-040920-generic_4.9.20-040920.201703310531_amd64.deb \
+  kernel.ubuntu.com/~kernel-ppa/mainline/v4.9.20/linux-image-4.9.20-040920-generic_4.9.20-040920.201703310531_amd64.deb
+sudo dpkg -i linux-headers-4.9*.deb linux-image-4.9*.deb
+rm linux-*
+
+# Add pubkey of jenkins@grpc-jenkins-master to authorized keys of jenkins@
+# This needs to happen as the last step to prevent Jenkins master from connecting
+# to a machine that hasn't been properly setup yet.
+cat jenkins_master.pub | sudo tee --append ~jenkins/.ssh/authorized_keys
+
+# Restart for VM to pick up kernel update
+echo 'Successfully initialized the linux worker, going for reboot in 10 seconds'
+sleep 10
+sudo reboot
diff --git a/tools/gce/linux_worker_init.sh b/tools/gce/linux_worker_init.sh
index 9230acd..d552343 100755
--- a/tools/gce/linux_worker_init.sh
+++ b/tools/gce/linux_worker_init.sh
@@ -59,19 +59,27 @@
 
 # Use "overlay" storage driver for docker
 # see https://github.com/grpc/grpc/issues/4988
-echo 'DOCKER_OPTS="${DOCKER_OPTS} --storage-driver=overlay"' | sudo tee --append /etc/default/docker
+printf "{\n\t\"storage-driver\": \"overlay\"\n}" | sudo tee /etc/docker/daemon.json
 
 # Install RVM
 # TODO(jtattermusch): why is RVM needed?
 gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3
 curl -sSL https://get.rvm.io | bash -s stable --ruby
 
+# Upgrade Linux kernel to 4.9
+wget \
+  kernel.ubuntu.com/~kernel-ppa/mainline/v4.9.20/linux-headers-4.9.20-040920_4.9.20-040920.201703310531_all.deb \
+  kernel.ubuntu.com/~kernel-ppa/mainline/v4.9.20/linux-headers-4.9.20-040920-generic_4.9.20-040920.201703310531_amd64.deb \
+  kernel.ubuntu.com/~kernel-ppa/mainline/v4.9.20/linux-image-4.9.20-040920-generic_4.9.20-040920.201703310531_amd64.deb
+sudo dpkg -i linux-headers-4.9*.deb linux-image-4.9*.deb
+rm linux-*
+
 # Add pubkey of jenkins@grpc-jenkins-master to authorized keys of jenkins@
 # This needs to happen as the last step to prevent Jenkins master from connecting
 # to a machine that hasn't been properly setup yet.
 cat jenkins_master.pub | sudo tee --append ~jenkins/.ssh/authorized_keys
 
-# Restart for docker to pickup the config changes.
+# Restart for docker to pick up the config changes.
 echo 'Successfully initialized the linux worker, going for reboot in 10 seconds'
 sleep 10
 
diff --git a/tools/internal_ci/README.md b/tools/internal_ci/README.md
index 8bed6ca..e80e342 100644
--- a/tools/internal_ci/README.md
+++ b/tools/internal_ci/README.md
@@ -1,4 +1,4 @@
-#Internal continuous integration
+# Internal continuous integration
 
 gRPC's externally facing testing is managed by Jenkins CI (see `tools/jenkins`
 directory). Nevertheless, some of the tests are better suited for being run
diff --git a/tools/internal_ci/linux/grpc_portability.cfg b/tools/internal_ci/linux/grpc_portability.cfg
index 5cc49f1..92efda8 100644
--- a/tools/internal_ci/linux/grpc_portability.cfg
+++ b/tools/internal_ci/linux/grpc_portability.cfg
@@ -31,7 +31,7 @@
 
 # Location of the continuous shell script in repository.
 build_file: "grpc/tools/internal_ci/linux/grpc_portability.sh"
-timeout_mins: 720
+timeout_mins: 1440
 action {
   define_artifacts {
     regex: "**/*sponge_log.xml"
diff --git a/tools/internal_ci/linux/grpc_master_sanitizers.cfg b/tools/internal_ci/linux/sanitizer/grpc_c_asan.cfg
similarity index 95%
copy from tools/internal_ci/linux/grpc_master_sanitizers.cfg
copy to tools/internal_ci/linux/sanitizer/grpc_c_asan.cfg
index a2a9407..8f2be8b 100644
--- a/tools/internal_ci/linux/grpc_master_sanitizers.cfg
+++ b/tools/internal_ci/linux/sanitizer/grpc_c_asan.cfg
@@ -30,7 +30,7 @@
 # Config file for the internal CI (in protobuf text format)
 
 # Location of the continuous shell script in repository.
-build_file: "grpc/tools/internal_ci/linux/grpc_master_sanitizers.sh"
+build_file: "grpc/tools/internal_ci/linux/sanitizer/grpc_c_asan.sh"
 timeout_mins: 1440
 action {
   define_artifacts {
diff --git a/tools/internal_ci/linux/grpc_master_sanitizers.sh b/tools/internal_ci/linux/sanitizer/grpc_c_asan.sh
similarity index 94%
copy from tools/internal_ci/linux/grpc_master_sanitizers.sh
copy to tools/internal_ci/linux/sanitizer/grpc_c_asan.sh
index d22387f..335d47a 100755
--- a/tools/internal_ci/linux/grpc_master_sanitizers.sh
+++ b/tools/internal_ci/linux/sanitizer/grpc_c_asan.sh
@@ -31,10 +31,10 @@
 set -ex
 
 # change to grpc repo root
-cd $(dirname $0)/../../..
+cd $(dirname $0)/../../../..
 
 git submodule update --init
 
 # download docker images from dockerhub
 export DOCKERHUB_ORGANIZATION=grpctesting
-tools/run_tests/run_tests_matrix.py -f sanitizers linux
+tools/run_tests/run_tests_matrix.py -f c asan
diff --git a/tools/internal_ci/linux/grpc_master_sanitizers.cfg b/tools/internal_ci/linux/sanitizer/grpc_c_msan.cfg
similarity index 95%
copy from tools/internal_ci/linux/grpc_master_sanitizers.cfg
copy to tools/internal_ci/linux/sanitizer/grpc_c_msan.cfg
index a2a9407..2fd1997 100644
--- a/tools/internal_ci/linux/grpc_master_sanitizers.cfg
+++ b/tools/internal_ci/linux/sanitizer/grpc_c_msan.cfg
@@ -30,7 +30,7 @@
 # Config file for the internal CI (in protobuf text format)
 
 # Location of the continuous shell script in repository.
-build_file: "grpc/tools/internal_ci/linux/grpc_master_sanitizers.sh"
+build_file: "grpc/tools/internal_ci/linux/sanitizer/grpc_c_msan.sh"
 timeout_mins: 1440
 action {
   define_artifacts {
diff --git a/tools/internal_ci/linux/grpc_master_sanitizers.sh b/tools/internal_ci/linux/sanitizer/grpc_c_msan.sh
similarity index 94%
copy from tools/internal_ci/linux/grpc_master_sanitizers.sh
copy to tools/internal_ci/linux/sanitizer/grpc_c_msan.sh
index d22387f..fe9565e 100755
--- a/tools/internal_ci/linux/grpc_master_sanitizers.sh
+++ b/tools/internal_ci/linux/sanitizer/grpc_c_msan.sh
@@ -31,10 +31,10 @@
 set -ex
 
 # change to grpc repo root
-cd $(dirname $0)/../../..
+cd $(dirname $0)/../../../..
 
 git submodule update --init
 
 # download docker images from dockerhub
 export DOCKERHUB_ORGANIZATION=grpctesting
-tools/run_tests/run_tests_matrix.py -f sanitizers linux
+tools/run_tests/run_tests_matrix.py -f c msan
diff --git a/tools/internal_ci/linux/grpc_master_sanitizers.cfg b/tools/internal_ci/linux/sanitizer/grpc_c_tsan.cfg
similarity index 95%
copy from tools/internal_ci/linux/grpc_master_sanitizers.cfg
copy to tools/internal_ci/linux/sanitizer/grpc_c_tsan.cfg
index a2a9407..1ba0121 100644
--- a/tools/internal_ci/linux/grpc_master_sanitizers.cfg
+++ b/tools/internal_ci/linux/sanitizer/grpc_c_tsan.cfg
@@ -30,7 +30,7 @@
 # Config file for the internal CI (in protobuf text format)
 
 # Location of the continuous shell script in repository.
-build_file: "grpc/tools/internal_ci/linux/grpc_master_sanitizers.sh"
+build_file: "grpc/tools/internal_ci/linux/sanitizer/grpc_c_tsan.sh"
 timeout_mins: 1440
 action {
   define_artifacts {
diff --git a/tools/internal_ci/linux/grpc_master_sanitizers.sh b/tools/internal_ci/linux/sanitizer/grpc_c_tsan.sh
similarity index 94%
rename from tools/internal_ci/linux/grpc_master_sanitizers.sh
rename to tools/internal_ci/linux/sanitizer/grpc_c_tsan.sh
index d22387f..49bbbee 100755
--- a/tools/internal_ci/linux/grpc_master_sanitizers.sh
+++ b/tools/internal_ci/linux/sanitizer/grpc_c_tsan.sh
@@ -31,10 +31,10 @@
 set -ex
 
 # change to grpc repo root
-cd $(dirname $0)/../../..
+cd $(dirname $0)/../../../..
 
 git submodule update --init
 
 # download docker images from dockerhub
 export DOCKERHUB_ORGANIZATION=grpctesting
-tools/run_tests/run_tests_matrix.py -f sanitizers linux
+tools/run_tests/run_tests_matrix.py -f c tsan
diff --git a/tools/internal_ci/linux/grpc_master_sanitizers.cfg b/tools/internal_ci/linux/sanitizer/grpc_cpp_asan.cfg
similarity index 95%
rename from tools/internal_ci/linux/grpc_master_sanitizers.cfg
rename to tools/internal_ci/linux/sanitizer/grpc_cpp_asan.cfg
index a2a9407..49b7f12 100644
--- a/tools/internal_ci/linux/grpc_master_sanitizers.cfg
+++ b/tools/internal_ci/linux/sanitizer/grpc_cpp_asan.cfg
@@ -30,7 +30,7 @@
 # Config file for the internal CI (in protobuf text format)
 
 # Location of the continuous shell script in repository.
-build_file: "grpc/tools/internal_ci/linux/grpc_master_sanitizers.sh"
+build_file: "grpc/tools/internal_ci/linux/sanitizer/grpc_cpp_asan.sh"
 timeout_mins: 1440
 action {
   define_artifacts {
diff --git a/tools/internal_ci/linux/grpc_master_sanitizers.sh b/tools/internal_ci/linux/sanitizer/grpc_cpp_asan.sh
similarity index 94%
copy from tools/internal_ci/linux/grpc_master_sanitizers.sh
copy to tools/internal_ci/linux/sanitizer/grpc_cpp_asan.sh
index d22387f..47ccb26 100755
--- a/tools/internal_ci/linux/grpc_master_sanitizers.sh
+++ b/tools/internal_ci/linux/sanitizer/grpc_cpp_asan.sh
@@ -31,10 +31,10 @@
 set -ex
 
 # change to grpc repo root
-cd $(dirname $0)/../../..
+cd $(dirname $0)/../../../..
 
 git submodule update --init
 
 # download docker images from dockerhub
 export DOCKERHUB_ORGANIZATION=grpctesting
-tools/run_tests/run_tests_matrix.py -f sanitizers linux
+tools/run_tests/run_tests_matrix.py -f c++ asan
diff --git a/tools/internal_ci/linux/grpc_master_sanitizers.cfg b/tools/internal_ci/linux/sanitizer/grpc_cpp_tsan.cfg
similarity index 95%
copy from tools/internal_ci/linux/grpc_master_sanitizers.cfg
copy to tools/internal_ci/linux/sanitizer/grpc_cpp_tsan.cfg
index a2a9407..97c818b 100644
--- a/tools/internal_ci/linux/grpc_master_sanitizers.cfg
+++ b/tools/internal_ci/linux/sanitizer/grpc_cpp_tsan.cfg
@@ -30,7 +30,7 @@
 # Config file for the internal CI (in protobuf text format)
 
 # Location of the continuous shell script in repository.
-build_file: "grpc/tools/internal_ci/linux/grpc_master_sanitizers.sh"
+build_file: "grpc/tools/internal_ci/linux/sanitizer/grpc_cpp_tsan.sh"
 timeout_mins: 1440
 action {
   define_artifacts {
diff --git a/tools/internal_ci/linux/grpc_master_sanitizers.sh b/tools/internal_ci/linux/sanitizer/grpc_cpp_tsan.sh
similarity index 94%
copy from tools/internal_ci/linux/grpc_master_sanitizers.sh
copy to tools/internal_ci/linux/sanitizer/grpc_cpp_tsan.sh
index d22387f..ee3ec5e 100755
--- a/tools/internal_ci/linux/grpc_master_sanitizers.sh
+++ b/tools/internal_ci/linux/sanitizer/grpc_cpp_tsan.sh
@@ -31,10 +31,10 @@
 set -ex
 
 # change to grpc repo root
-cd $(dirname $0)/../../..
+cd $(dirname $0)/../../../..
 
 git submodule update --init
 
 # download docker images from dockerhub
 export DOCKERHUB_ORGANIZATION=grpctesting
-tools/run_tests/run_tests_matrix.py -f sanitizers linux
+tools/run_tests/run_tests_matrix.py -f c++ tsan
diff --git a/tools/jenkins/run_performance.sh b/tools/jenkins/run_performance.sh
index dee033a..544e31d 100755
--- a/tools/jenkins/run_performance.sh
+++ b/tools/jenkins/run_performance.sh
@@ -32,7 +32,7 @@
 set -ex
 
 # List of benchmarks that provide good signal for analyzing performance changes in pull requests
-BENCHMARKS_TO_RUN="bm_closure bm_cq bm_call_create bm_error bm_chttp2_hpack bm_chttp2_transport bm_pollset bm_metadata"
+BENCHMARKS_TO_RUN="bm_fullstack_unary_ping_pong bm_fullstack_streaming_ping_pong bm_fullstack_streaming_pump bm_closure bm_cq bm_call_create bm_error bm_chttp2_hpack bm_chttp2_transport bm_pollset bm_metadata"
 
 # Enter the gRPC repo root
 cd $(dirname $0)/../..
diff --git a/tools/jenkins/run_performance_profile_hourly.sh b/tools/jenkins/run_performance_profile_hourly.sh
index dfcc2bb..c352a9f 100755
--- a/tools/jenkins/run_performance_profile_hourly.sh
+++ b/tools/jenkins/run_performance_profile_hourly.sh
@@ -32,6 +32,8 @@
 
 cd $(dirname $0)/../..
 
+./tools/run_tests/start_port_server.py || true
+
 CPUS=`python -c 'import multiprocessing; print multiprocessing.cpu_count()'`
 
 make CONFIG=opt memory_profile_test memory_profile_client memory_profile_server -j $CPUS
diff --git a/tools/profiling/microbenchmarks/bm_diff.py b/tools/profiling/microbenchmarks/bm_diff.py
index 35a7959..ba0c225 100755
--- a/tools/profiling/microbenchmarks/bm_diff.py
+++ b/tools/profiling/microbenchmarks/bm_diff.py
@@ -41,6 +41,22 @@
 import os
 sys.path.append(os.path.join(os.path.dirname(sys.argv[0]), '..', '..', 'run_tests', 'python_utils'))
 import comment_on_pr
+import jobset
+import itertools
+import speedup
+import random
+import shutil
+import errno
+
+_INTERESTING = (
+  'cpu_time',
+  'real_time',
+  'locks_per_iteration',
+  'allocs_per_iteration',
+  'writes_per_iteration',
+  'atm_cas_per_iteration',
+  'atm_add_per_iteration',
+)
 
 def changed_ratio(n, o):
   if float(o) <= .0001: o = 0
@@ -60,26 +76,6 @@
 def min_change(pct):
   return lambda n, o: abs(changed_ratio(n,o)) > pct/100.0
 
-nanos = {
-  'abs_diff': 5,
-  'pct_diff': 10,
-}
-counter = {
-  'abs_diff': 0.5,
-  'pct_diff': 10,
-}
-
-_INTERESTING = {
-  'cpu_time': nanos,
-  'real_time': nanos,
-  'locks_per_iteration': counter,
-  'allocs_per_iteration': counter,
-  'writes_per_iteration': counter,
-  'atm_cas_per_iteration': counter,
-  'atm_add_per_iteration': counter,
-}
-
-
 _AVAILABLE_BENCHMARK_TESTS = ['bm_fullstack_unary_ping_pong',
                               'bm_fullstack_streaming_ping_pong',
                               'bm_fullstack_streaming_pump',
@@ -95,14 +91,15 @@
 
 argp = argparse.ArgumentParser(description='Perform diff on microbenchmarks')
 argp.add_argument('-t', '--track',
-                  choices=sorted(_INTERESTING.keys()),
+                  choices=sorted(_INTERESTING),
                   nargs='+',
-                  default=sorted(_INTERESTING.keys()),
+                  default=sorted(_INTERESTING),
                   help='Which metrics to track')
 argp.add_argument('-b', '--benchmarks', nargs='+', choices=_AVAILABLE_BENCHMARK_TESTS, default=['bm_cq'])
 argp.add_argument('-d', '--diff_base', type=str)
-argp.add_argument('-r', '--repetitions', type=int, default=4)
-argp.add_argument('-p', '--p_threshold', type=float, default=0.01)
+argp.add_argument('-r', '--repetitions', type=int, default=1)
+argp.add_argument('-l', '--loops', type=int, default=12)
+argp.add_argument('-j', '--jobs', type=int, default=multiprocessing.cpu_count())
 args = argp.parse_args()
 
 assert args.diff_base
@@ -117,9 +114,10 @@
 
 def make_cmd(cfg):
   return ['make'] + args.benchmarks + [
-      'CONFIG=%s' % cfg, '-j', '%d' % multiprocessing.cpu_count()]
+      'CONFIG=%s' % cfg, '-j', '%d' % args.jobs]
 
-def build():
+def build(dest):
+  shutil.rmtree('bm_diff_%s' % dest, ignore_errors=True)
   subprocess.check_call(['git', 'submodule', 'update'])
   try:
     subprocess.check_call(make_cmd('opt'))
@@ -128,38 +126,38 @@
     subprocess.check_call(['make', 'clean'])
     subprocess.check_call(make_cmd('opt'))
     subprocess.check_call(make_cmd('counters'))
+  os.rename('bins', 'bm_diff_%s' % dest)
 
-def collect1(bm, cfg, ver):
-  cmd = ['bins/%s/%s' % (cfg, bm),
-         '--benchmark_out=%s.%s.%s.json' % (bm, cfg, ver),
+def collect1(bm, cfg, ver, idx):
+  cmd = ['bm_diff_%s/%s/%s' % (ver, cfg, bm),
+         '--benchmark_out=%s.%s.%s.%d.json' % (bm, cfg, ver, idx),
          '--benchmark_out_format=json',
          '--benchmark_repetitions=%d' % (args.repetitions)
          ]
-  print cmd
-  subprocess.check_call(cmd)
+  return jobset.JobSpec(cmd, shortname='%s %s %s %d/%d' % (bm, cfg, ver, idx+1, args.loops),
+                             verbose_success=True, timeout_seconds=None)
 
-build()
-for bm in args.benchmarks:
-  collect1(bm, 'opt', 'new')
-  collect1(bm, 'counters', 'new')
+build('new')
 
 where_am_i = subprocess.check_output(['git', 'rev-parse', '--abbrev-ref', 'HEAD']).strip()
 subprocess.check_call(['git', 'checkout', args.diff_base])
-
 try:
-  build()
-  comparables = []
-  for bm in args.benchmarks:
-    try:
-      collect1(bm, 'opt', 'old')
-      collect1(bm, 'counters', 'old')
-      comparables.append(bm)
-    except subprocess.CalledProcessError, e:
-      pass
+  build('old')
 finally:
   subprocess.check_call(['git', 'checkout', where_am_i])
   subprocess.check_call(['git', 'submodule', 'update'])
 
+jobs = []
+for loop in range(0, args.loops):
+  jobs.extend(x for x in itertools.chain(
+    (collect1(bm, 'opt', 'new', loop) for bm in args.benchmarks),
+    (collect1(bm, 'counters', 'new', loop) for bm in args.benchmarks),
+    (collect1(bm, 'opt', 'old', loop) for bm in args.benchmarks),
+    (collect1(bm, 'counters', 'old', loop) for bm in args.benchmarks),
+  ))
+random.shuffle(jobs, random.SystemRandom().random)
+
+jobset.run(jobs, maxjobs=args.jobs)
 
 class Benchmark:
 
@@ -180,16 +178,11 @@
       new = self.samples[True][f]
       old = self.samples[False][f]
       if not new or not old: continue
-      p = stats.ttest_ind(new, old)[1]
-      new_mdn = median(new)
-      old_mdn = median(old)
-      delta = new_mdn - old_mdn
-      ratio = changed_ratio(new_mdn, old_mdn)
-      print '%s: new=%r old=%r new_mdn=%f old_mdn=%f delta=%f(%f:%f) ratio=%f(%f:%f) p=%f' % (
-      f, new, old, new_mdn, old_mdn, delta, abs(delta), _INTERESTING[f]['abs_diff'], ratio, abs(ratio), _INTERESTING[f]['pct_diff']/100.0, p
-      )
-      if p < args.p_threshold and abs(delta) > _INTERESTING[f]['abs_diff'] and abs(ratio) > _INTERESTING[f]['pct_diff']/100.0:
-        self.final[f] = delta
+      mdn_diff = abs(median(new) - median(old))
+      print '%s: new=%r old=%r mdn_diff=%r' % (f, new, old, mdn_diff)
+      s = speedup.speedup(new, old)
+      if abs(s) > 3 and mdn_diff > 0.5:
+        self.final[f] = '%+d%%' % s
     return self.final.keys()
 
   def skip(self):
@@ -199,28 +192,37 @@
     return [self.final[f] if f in self.final else '' for f in flds]
 
 
+def read_file(filename):
+  while True:
+    try:
+      with open(filename) as f:
+        return f.read()
+    except IOError, e:
+      if e.errno != errno.EINTR:
+        raise
+
+def read_json(filename):
+  return json.loads(read_file(filename))
+
 benchmarks = collections.defaultdict(Benchmark)
 
-for bm in comparables:
-  with open('%s.counters.new.json' % bm) as f:
-    js_new_ctr = json.loads(f.read())
-  with open('%s.opt.new.json' % bm) as f:
-    js_new_opt = json.loads(f.read())
-  with open('%s.counters.old.json' % bm) as f:
-    js_old_ctr = json.loads(f.read())
-  with open('%s.opt.old.json' % bm) as f:
-    js_old_opt = json.loads(f.read())
+for bm in args.benchmarks:
+  for loop in range(0, args.loops):
+    js_new_ctr = read_json('%s.counters.new.%d.json' % (bm, loop))
+    js_new_opt = read_json('%s.opt.new.%d.json' % (bm, loop))
+    js_old_ctr = read_json('%s.counters.old.%d.json' % (bm, loop))
+    js_old_opt = read_json('%s.opt.old.%d.json' % (bm, loop))
 
-  for row in bm_json.expand_json(js_new_ctr, js_new_opt):
-    print row
-    name = row['cpp_name']
-    if name.endswith('_mean') or name.endswith('_stddev'): continue
-    benchmarks[name].add_sample(row, True)
-  for row in bm_json.expand_json(js_old_ctr, js_old_opt):
-    print row
-    name = row['cpp_name']
-    if name.endswith('_mean') or name.endswith('_stddev'): continue
-    benchmarks[name].add_sample(row, False)
+    for row in bm_json.expand_json(js_new_ctr, js_new_opt):
+      print row
+      name = row['cpp_name']
+      if name.endswith('_mean') or name.endswith('_stddev'): continue
+      benchmarks[name].add_sample(row, True)
+    for row in bm_json.expand_json(js_old_ctr, js_old_opt):
+      print row
+      name = row['cpp_name']
+      if name.endswith('_mean') or name.endswith('_stddev'): continue
+      benchmarks[name].add_sample(row, False)
 
 really_interesting = set()
 for name, bm in benchmarks.items():
diff --git a/tools/profiling/microbenchmarks/speedup.py b/tools/profiling/microbenchmarks/speedup.py
new file mode 100644
index 0000000..8f9023d
--- /dev/null
+++ b/tools/profiling/microbenchmarks/speedup.py
@@ -0,0 +1,67 @@
+# Copyright 2017, 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.
+
+from scipy import stats
+import math
+
+_THRESHOLD = 0.0001
+
+def scale(a, mul):
+  return [x*mul for x in a]
+
+def cmp(a, b):
+  return stats.ttest_ind(a, b)
+
+def speedup(new, old):
+  s0, p0 = cmp(new, old)
+  if math.isnan(p0): return 0
+  if s0 == 0: return 0
+  if p0 > _THRESHOLD: return 0
+  if s0 < 0:
+    pct = 1
+    while pct < 101:
+      sp, pp = cmp(new, scale(old, 1 - pct/100.0))
+      if sp > 0: break
+      if pp > _THRESHOLD: break
+      pct += 1
+    return -(pct - 1)
+  else:
+    pct = 1
+    while pct < 101:
+      sp, pp = cmp(new, scale(old, 1 + pct/100.0))
+      if sp < 0: break
+      if pp > _THRESHOLD: break
+      pct += 1
+    return pct - 1
+
+if __name__ == "__main__":
+  new=[66034560.0, 126765693.0, 99074674.0, 98588433.0, 96731372.0, 110179725.0, 103802110.0, 101139800.0, 102357205.0, 99016353.0, 98840824.0, 99585632.0, 98791720.0, 96171521.0, 95327098.0, 95629704.0, 98209772.0, 99779411.0, 100182488.0, 98354192.0, 99644781.0, 98546709.0, 99019176.0, 99543014.0, 99077269.0, 98046601.0, 99319039.0, 98542572.0, 98886614.0, 72560968.0]
+  old=[60423464.0, 71249570.0, 73213089.0, 73200055.0, 72911768.0, 72347798.0, 72494672.0, 72756976.0, 72116565.0, 71541342.0, 73442538.0, 74817383.0, 73007780.0, 72499062.0, 72404945.0, 71843504.0, 73245405.0, 72778304.0, 74004519.0, 73694464.0, 72919931.0, 72955481.0, 71583857.0, 71350467.0, 71836817.0, 70064115.0, 70355345.0, 72516202.0, 71716777.0, 71532266.0]
+  print speedup(new, old)
+  print speedup(old, new)
diff --git a/tools/run_tests/generated/sources_and_headers.json b/tools/run_tests/generated/sources_and_headers.json
index 5ee5d0b..aa4869e 100644
--- a/tools/run_tests/generated/sources_and_headers.json
+++ b/tools/run_tests/generated/sources_and_headers.json
@@ -480,6 +480,23 @@
     "headers": [], 
     "is_filegroup": false, 
     "language": "c", 
+    "name": "fake_resolver_test", 
+    "src": [
+      "test/core/client_channel/resolvers/fake_resolver_test.c"
+    ], 
+    "third_party": false, 
+    "type": "target"
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "is_filegroup": false, 
+    "language": "c", 
     "name": "fd_conservation_posix_test", 
     "src": [
       "test/core/iomgr/fd_conservation_posix_test.c"
@@ -1599,6 +1616,23 @@
     "headers": [], 
     "is_filegroup": false, 
     "language": "c", 
+    "name": "minimal_stack_is_minimal_test", 
+    "src": [
+      "test/core/channel/minimal_stack_is_minimal_test.c"
+    ], 
+    "third_party": false, 
+    "type": "target"
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "is_filegroup": false, 
+    "language": "c", 
     "name": "mlog_test", 
     "src": [
       "test/core/census/mlog_test.c"
@@ -2969,6 +3003,24 @@
   }, 
   {
     "deps": [
+      "grpc++", 
+      "grpc++_error_details"
+    ], 
+    "headers": [
+      "src/proto/grpc/testing/echo_messages.grpc.pb.h", 
+      "src/proto/grpc/testing/echo_messages.pb.h"
+    ], 
+    "is_filegroup": false, 
+    "language": "c++", 
+    "name": "error_details_test", 
+    "src": [
+      "test/cpp/util/error_details_test.cc"
+    ], 
+    "third_party": false, 
+    "type": "target"
+  }, 
+  {
+    "deps": [
       "gpr", 
       "gpr_test_util", 
       "grpc", 
@@ -5593,11 +5645,13 @@
       "census", 
       "gpr", 
       "grpc_base", 
+      "grpc_deadline_filter", 
       "grpc_lb_policy_grpclb_secure", 
       "grpc_lb_policy_pick_first", 
       "grpc_lb_policy_round_robin", 
       "grpc_load_reporting", 
       "grpc_max_age_filter", 
+      "grpc_message_size_filter", 
       "grpc_resolver_dns_ares", 
       "grpc_resolver_dns_native", 
       "grpc_resolver_sockaddr", 
@@ -5696,11 +5750,13 @@
       "census", 
       "gpr", 
       "grpc_base", 
+      "grpc_deadline_filter", 
       "grpc_lb_policy_grpclb", 
       "grpc_lb_policy_pick_first", 
       "grpc_lb_policy_round_robin", 
       "grpc_load_reporting", 
       "grpc_max_age_filter", 
+      "grpc_message_size_filter", 
       "grpc_resolver_dns_ares", 
       "grpc_resolver_dns_native", 
       "grpc_resolver_sockaddr", 
@@ -5820,6 +5876,25 @@
   }, 
   {
     "deps": [
+      "grpc++"
+    ], 
+    "headers": [
+      "include/grpc++/support/error_details.h", 
+      "src/proto/grpc/status/status.grpc.pb.h", 
+      "src/proto/grpc/status/status.pb.h"
+    ], 
+    "is_filegroup": false, 
+    "language": "c++", 
+    "name": "grpc++_error_details", 
+    "src": [
+      "include/grpc++/support/error_details.h", 
+      "src/cpp/util/error_details.cc"
+    ], 
+    "third_party": false, 
+    "type": "lib"
+  }, 
+  {
+    "deps": [
       "grpc++", 
       "grpc++_config_proto", 
       "grpc++_reflection_proto"
@@ -7538,16 +7613,11 @@
       "src/core/lib/channel/channel_args.h", 
       "src/core/lib/channel/channel_stack.h", 
       "src/core/lib/channel/channel_stack_builder.h", 
-      "src/core/lib/channel/compress_filter.h", 
       "src/core/lib/channel/connected_channel.h", 
       "src/core/lib/channel/context.h", 
-      "src/core/lib/channel/deadline_filter.h", 
       "src/core/lib/channel/handshaker.h", 
       "src/core/lib/channel/handshaker_factory.h", 
       "src/core/lib/channel/handshaker_registry.h", 
-      "src/core/lib/channel/http_client_filter.h", 
-      "src/core/lib/channel/http_server_filter.h", 
-      "src/core/lib/channel/message_size_filter.h", 
       "src/core/lib/compression/algorithm_metadata.h", 
       "src/core/lib/compression/message_compress.h", 
       "src/core/lib/debug/trace.h", 
@@ -7667,25 +7737,15 @@
       "src/core/lib/channel/channel_stack.h", 
       "src/core/lib/channel/channel_stack_builder.c", 
       "src/core/lib/channel/channel_stack_builder.h", 
-      "src/core/lib/channel/compress_filter.c", 
-      "src/core/lib/channel/compress_filter.h", 
       "src/core/lib/channel/connected_channel.c", 
       "src/core/lib/channel/connected_channel.h", 
       "src/core/lib/channel/context.h", 
-      "src/core/lib/channel/deadline_filter.c", 
-      "src/core/lib/channel/deadline_filter.h", 
       "src/core/lib/channel/handshaker.c", 
       "src/core/lib/channel/handshaker.h", 
       "src/core/lib/channel/handshaker_factory.c", 
       "src/core/lib/channel/handshaker_factory.h", 
       "src/core/lib/channel/handshaker_registry.c", 
       "src/core/lib/channel/handshaker_registry.h", 
-      "src/core/lib/channel/http_client_filter.c", 
-      "src/core/lib/channel/http_client_filter.h", 
-      "src/core/lib/channel/http_server_filter.c", 
-      "src/core/lib/channel/http_server_filter.h", 
-      "src/core/lib/channel/message_size_filter.c", 
-      "src/core/lib/channel/message_size_filter.h", 
       "src/core/lib/compression/algorithm_metadata.h", 
       "src/core/lib/compression/compression.c", 
       "src/core/lib/compression/message_compress.c", 
@@ -7904,7 +7964,8 @@
   {
     "deps": [
       "gpr", 
-      "grpc_base"
+      "grpc_base", 
+      "grpc_deadline_filter"
     ], 
     "headers": [
       "src/core/ext/filters/client_channel/client_channel.h", 
@@ -8005,6 +8066,49 @@
   {
     "deps": [
       "gpr", 
+      "grpc_base"
+    ], 
+    "headers": [
+      "src/core/ext/filters/deadline/deadline_filter.h"
+    ], 
+    "is_filegroup": true, 
+    "language": "c", 
+    "name": "grpc_deadline_filter", 
+    "src": [
+      "src/core/ext/filters/deadline/deadline_filter.c", 
+      "src/core/ext/filters/deadline/deadline_filter.h"
+    ], 
+    "third_party": false, 
+    "type": "filegroup"
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "grpc_base"
+    ], 
+    "headers": [
+      "src/core/ext/filters/http/client/http_client_filter.h", 
+      "src/core/ext/filters/http/message_compress/message_compress_filter.h", 
+      "src/core/ext/filters/http/server/http_server_filter.h"
+    ], 
+    "is_filegroup": true, 
+    "language": "c", 
+    "name": "grpc_http_filters", 
+    "src": [
+      "src/core/ext/filters/http/client/http_client_filter.c", 
+      "src/core/ext/filters/http/client/http_client_filter.h", 
+      "src/core/ext/filters/http/http_filters_plugin.c", 
+      "src/core/ext/filters/http/message_compress/message_compress_filter.c", 
+      "src/core/ext/filters/http/message_compress/message_compress_filter.h", 
+      "src/core/ext/filters/http/server/http_server_filter.c", 
+      "src/core/ext/filters/http/server/http_server_filter.h"
+    ], 
+    "third_party": false, 
+    "type": "filegroup"
+  }, 
+  {
+    "deps": [
+      "gpr", 
       "grpc_base", 
       "grpc_client_channel", 
       "nanopb"
@@ -8135,6 +8239,24 @@
   {
     "deps": [
       "gpr", 
+      "grpc_base"
+    ], 
+    "headers": [
+      "src/core/ext/filters/message_size/message_size_filter.h"
+    ], 
+    "is_filegroup": true, 
+    "language": "c", 
+    "name": "grpc_message_size_filter", 
+    "src": [
+      "src/core/ext/filters/message_size/message_size_filter.c", 
+      "src/core/ext/filters/message_size/message_size_filter.h"
+    ], 
+    "third_party": false, 
+    "type": "filegroup"
+  }, 
+  {
+    "deps": [
+      "gpr", 
       "grpc_base", 
       "grpc_client_channel"
     ], 
@@ -8332,6 +8454,7 @@
     "deps": [
       "gpr", 
       "grpc_base", 
+      "grpc_http_filters", 
       "grpc_transport_chttp2_alpn"
     ], 
     "headers": [
@@ -8348,6 +8471,7 @@
       "src/core/ext/transport/chttp2/transport/hpack_encoder.h", 
       "src/core/ext/transport/chttp2/transport/hpack_parser.h", 
       "src/core/ext/transport/chttp2/transport/hpack_table.h", 
+      "src/core/ext/transport/chttp2/transport/http2_settings.h", 
       "src/core/ext/transport/chttp2/transport/huffsyms.h", 
       "src/core/ext/transport/chttp2/transport/incoming_metadata.h", 
       "src/core/ext/transport/chttp2/transport/internal.h", 
@@ -8384,6 +8508,8 @@
       "src/core/ext/transport/chttp2/transport/hpack_parser.h", 
       "src/core/ext/transport/chttp2/transport/hpack_table.c", 
       "src/core/ext/transport/chttp2/transport/hpack_table.h", 
+      "src/core/ext/transport/chttp2/transport/http2_settings.c", 
+      "src/core/ext/transport/chttp2/transport/http2_settings.h", 
       "src/core/ext/transport/chttp2/transport/huffsyms.c", 
       "src/core/ext/transport/chttp2/transport/huffsyms.h", 
       "src/core/ext/transport/chttp2/transport/incoming_metadata.c", 
@@ -8533,6 +8659,7 @@
   {
     "deps": [
       "grpc_base", 
+      "grpc_http_filters", 
       "grpc_transport_chttp2"
     ], 
     "headers": [
diff --git a/tools/run_tests/generated/tests.json b/tools/run_tests/generated/tests.json
index 12d48f2..6338ea7 100644
--- a/tools/run_tests/generated/tests.json
+++ b/tools/run_tests/generated/tests.json
@@ -582,6 +582,28 @@
     "ci_platforms": [
       "linux", 
       "mac", 
+      "posix", 
+      "windows"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "gtest": false, 
+    "language": "c", 
+    "name": "fake_resolver_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ]
+  }, 
+  {
+    "args": [], 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
       "posix"
     ], 
     "cpu_cost": 1.0, 
@@ -1686,6 +1708,28 @@
     "cpu_cost": 1.0, 
     "exclude_configs": [], 
     "exclude_iomgrs": [], 
+    "flaky": false, 
+    "gtest": false, 
+    "language": "c", 
+    "name": "minimal_stack_is_minimal_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ]
+  }, 
+  {
+    "args": [], 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
     "flaky": true, 
     "gtest": false, 
     "language": "c", 
@@ -3209,6 +3253,28 @@
     "flaky": false, 
     "gtest": true, 
     "language": "c++", 
+    "name": "error_details_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ]
+  }, 
+  {
+    "args": [], 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "gtest": true, 
+    "language": "c++", 
     "name": "filter_end2end_test", 
     "platforms": [
       "linux", 
@@ -41456,7 +41522,7 @@
   {
     "args": [
       "--scenarios_json", 
-      "{\"scenarios\": [{\"name\": \"cpp_protobuf_async_unary_ping_pong_secure_1mb\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 0, \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"server_type\": \"ASYNC_SERVER\"}, \"num_clients\": 1, \"client_config\": {\"client_type\": \"ASYNC_CLIENT\", \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"payload_config\": {\"simple_params\": {\"resp_size\": 1048576, \"req_size\": 1048576}}, \"client_channels\": 1, \"async_client_threads\": 1, \"outstanding_rpcs_per_channel\": 1, \"rpc_type\": \"UNARY\", \"load_params\": {\"closed_loop\": {}}, \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+      "{\"scenarios\": [{\"name\": \"cpp_protobuf_async_unary_ping_pong_secure_1MB\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 0, \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"server_type\": \"ASYNC_SERVER\"}, \"num_clients\": 1, \"client_config\": {\"client_type\": \"ASYNC_CLIENT\", \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"payload_config\": {\"simple_params\": {\"resp_size\": 1048576, \"req_size\": 1048576}}, \"client_channels\": 1, \"async_client_threads\": 1, \"outstanding_rpcs_per_channel\": 1, \"rpc_type\": \"UNARY\", \"load_params\": {\"closed_loop\": {}}, \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
     ], 
     "boringssl": true, 
     "ci_platforms": [
@@ -41475,7 +41541,7 @@
     "platforms": [
       "linux"
     ], 
-    "shortname": "json_run_localhost:cpp_protobuf_async_unary_ping_pong_secure_1mb", 
+    "shortname": "json_run_localhost:cpp_protobuf_async_unary_ping_pong_secure_1MB", 
     "timeout_seconds": 360
   }, 
   {
@@ -42035,7 +42101,7 @@
   {
     "args": [
       "--scenarios_json", 
-      "{\"scenarios\": [{\"name\": \"cpp_protobuf_async_unary_ping_pong_insecure_1mb\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 0, \"security_params\": null, \"server_type\": \"ASYNC_SERVER\"}, \"num_clients\": 1, \"client_config\": {\"client_type\": \"ASYNC_CLIENT\", \"security_params\": null, \"payload_config\": {\"simple_params\": {\"resp_size\": 1048576, \"req_size\": 1048576}}, \"client_channels\": 1, \"async_client_threads\": 1, \"outstanding_rpcs_per_channel\": 1, \"rpc_type\": \"UNARY\", \"load_params\": {\"closed_loop\": {}}, \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+      "{\"scenarios\": [{\"name\": \"cpp_protobuf_async_unary_ping_pong_insecure_1MB\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 0, \"security_params\": null, \"server_type\": \"ASYNC_SERVER\"}, \"num_clients\": 1, \"client_config\": {\"client_type\": \"ASYNC_CLIENT\", \"security_params\": null, \"payload_config\": {\"simple_params\": {\"resp_size\": 1048576, \"req_size\": 1048576}}, \"client_channels\": 1, \"async_client_threads\": 1, \"outstanding_rpcs_per_channel\": 1, \"rpc_type\": \"UNARY\", \"load_params\": {\"closed_loop\": {}}, \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
     ], 
     "boringssl": true, 
     "ci_platforms": [
@@ -42054,7 +42120,7 @@
     "platforms": [
       "linux"
     ], 
-    "shortname": "json_run_localhost:cpp_protobuf_async_unary_ping_pong_insecure_1mb", 
+    "shortname": "json_run_localhost:cpp_protobuf_async_unary_ping_pong_insecure_1MB", 
     "timeout_seconds": 360
   }, 
   {
@@ -42734,7 +42800,7 @@
   {
     "args": [
       "--scenarios_json", 
-      "{\"scenarios\": [{\"name\": \"cpp_protobuf_async_unary_ping_pong_secure_1mb\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 0, \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"server_type\": \"ASYNC_SERVER\"}, \"num_clients\": 1, \"client_config\": {\"client_type\": \"ASYNC_CLIENT\", \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"payload_config\": {\"simple_params\": {\"resp_size\": 1048576, \"req_size\": 1048576}}, \"client_channels\": 1, \"async_client_threads\": 1, \"outstanding_rpcs_per_channel\": 1, \"rpc_type\": \"UNARY\", \"load_params\": {\"closed_loop\": {}}, \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+      "{\"scenarios\": [{\"name\": \"cpp_protobuf_async_unary_ping_pong_secure_1MB\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 0, \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"server_type\": \"ASYNC_SERVER\"}, \"num_clients\": 1, \"client_config\": {\"client_type\": \"ASYNC_CLIENT\", \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"payload_config\": {\"simple_params\": {\"resp_size\": 1048576, \"req_size\": 1048576}}, \"client_channels\": 1, \"async_client_threads\": 1, \"outstanding_rpcs_per_channel\": 1, \"rpc_type\": \"UNARY\", \"load_params\": {\"closed_loop\": {}}, \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
     ], 
     "boringssl": true, 
     "ci_platforms": [
@@ -42765,7 +42831,7 @@
     "platforms": [
       "linux"
     ], 
-    "shortname": "json_run_localhost:cpp_protobuf_async_unary_ping_pong_secure_1mb_low_thread_count", 
+    "shortname": "json_run_localhost:cpp_protobuf_async_unary_ping_pong_secure_1MB_low_thread_count", 
     "timeout_seconds": 360
   }, 
   {
@@ -43589,7 +43655,7 @@
   {
     "args": [
       "--scenarios_json", 
-      "{\"scenarios\": [{\"name\": \"cpp_protobuf_async_unary_ping_pong_insecure_1mb\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 0, \"security_params\": null, \"server_type\": \"ASYNC_SERVER\"}, \"num_clients\": 1, \"client_config\": {\"client_type\": \"ASYNC_CLIENT\", \"security_params\": null, \"payload_config\": {\"simple_params\": {\"resp_size\": 1048576, \"req_size\": 1048576}}, \"client_channels\": 1, \"async_client_threads\": 1, \"outstanding_rpcs_per_channel\": 1, \"rpc_type\": \"UNARY\", \"load_params\": {\"closed_loop\": {}}, \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+      "{\"scenarios\": [{\"name\": \"cpp_protobuf_async_unary_ping_pong_insecure_1MB\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 0, \"security_params\": null, \"server_type\": \"ASYNC_SERVER\"}, \"num_clients\": 1, \"client_config\": {\"client_type\": \"ASYNC_CLIENT\", \"security_params\": null, \"payload_config\": {\"simple_params\": {\"resp_size\": 1048576, \"req_size\": 1048576}}, \"client_channels\": 1, \"async_client_threads\": 1, \"outstanding_rpcs_per_channel\": 1, \"rpc_type\": \"UNARY\", \"load_params\": {\"closed_loop\": {}}, \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
     ], 
     "boringssl": true, 
     "ci_platforms": [
@@ -43620,7 +43686,7 @@
     "platforms": [
       "linux"
     ], 
-    "shortname": "json_run_localhost:cpp_protobuf_async_unary_ping_pong_insecure_1mb_low_thread_count", 
+    "shortname": "json_run_localhost:cpp_protobuf_async_unary_ping_pong_insecure_1MB_low_thread_count", 
     "timeout_seconds": 360
   }, 
   {
@@ -85055,6 +85121,29 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/api_fuzzer_corpus/clusterfuzz-testcase-5867145026076672"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "api_fuzzer_one_entry", 
+    "platforms": [
+      "mac", 
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/api_fuzzer_corpus/clusterfuzz-testcase-5965570207907840"
     ], 
     "ci_platforms": [
@@ -150789,6 +150878,29 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/server_fuzzer_corpus/clusterfuzz-testcase-5595941564317696"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "server_fuzzer_one_entry", 
+    "platforms": [
+      "mac", 
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/server_fuzzer_corpus/clusterfuzz-testcase-6312731374256128"
     ], 
     "ci_platforms": [
diff --git a/tools/run_tests/performance/scenario_config.py b/tools/run_tests/performance/scenario_config.py
index dca3fba..200da5e 100644
--- a/tools/run_tests/performance/scenario_config.py
+++ b/tools/run_tests/performance/scenario_config.py
@@ -304,11 +304,11 @@
           excluded_poll_engines = ['poll-cv'])
 
       yield _ping_pong_scenario(
-        'cpp_protobuf_async_unary_ping_pong_%s_1mb' % secstr, rpc_type='UNARY',
+        'cpp_protobuf_async_unary_ping_pong_%s_1MB' % secstr, rpc_type='UNARY',
         client_type='ASYNC_CLIENT', server_type='ASYNC_SERVER',
         req_size=1024*1024, resp_size=1024*1024,
         secure=secure,
-        categories=smoketest_categories)
+        categories=smoketest_categories + [SCALABLE])
 
       for rpc_type in ['unary', 'streaming']:
         for synchronicity in ['sync', 'async']:
@@ -464,10 +464,10 @@
         categories=[SCALABLE])
 
     yield _ping_pong_scenario(
-        'csharp_protobuf_async_unary_ping_pong_1mb', rpc_type='UNARY',
+        'csharp_protobuf_async_unary_ping_pong_1MB', rpc_type='UNARY',
         client_type='ASYNC_CLIENT', server_type='ASYNC_SERVER',
         req_size=1024*1024, resp_size=1024*1024,
-        categories=[SMOKETEST])
+        categories=[SMOKETEST, SCALABLE])
 
 
   def __str__(self):
@@ -510,10 +510,10 @@
         client_language='c++')
 
     yield _ping_pong_scenario(
-        'node_protobuf_async_unary_ping_pong_1mb', rpc_type='UNARY',
+        'node_protobuf_unary_ping_pong_1MB', rpc_type='UNARY',
         client_type='ASYNC_CLIENT', server_type='ASYNC_SERVER',
         req_size=1024*1024, resp_size=1024*1024,
-        categories=[SMOKETEST])
+        categories=[SCALABLE, SMOKETEST])
 
     # TODO(murgatroid99): fix bugs with this scenario and re-enable it
     # yield _ping_pong_scenario(
@@ -596,10 +596,10 @@
         server_language='c++', async_server_threads=1)
 
     yield _ping_pong_scenario(
-        'python_protobuf_sync_unary_ping_pong_1mb', rpc_type='UNARY',
+        'python_protobuf_sync_unary_ping_pong_1MB', rpc_type='UNARY',
         client_type='SYNC_CLIENT', server_type='ASYNC_SERVER',
         req_size=1024*1024, resp_size=1024*1024,
-        categories=[SMOKETEST])
+        categories=[SMOKETEST, SCALABLE])
 
   def __str__(self):
     return 'python'
@@ -648,10 +648,10 @@
         server_language='c++', async_server_threads=1)
 
     yield _ping_pong_scenario(
-        'ruby_protobuf_async_unary_ping_pong_1mb', rpc_type='UNARY',
+        'ruby_protobuf_unary_ping_pong_1MB', rpc_type='UNARY',
         client_type='SYNC_CLIENT', server_type='SYNC_SERVER',
         req_size=1024*1024, resp_size=1024*1024,
-        categories=[SMOKETEST])
+        categories=[SMOKETEST, SCALABLE])
 
   def __str__(self):
     return 'ruby'
diff --git a/vsprojects/buildtests_c.sln b/vsprojects/buildtests_c.sln
index c8fcacf..6ae8bfa 100644
--- a/vsprojects/buildtests_c.sln
+++ b/vsprojects/buildtests_c.sln
@@ -317,6 +317,17 @@
 		{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} = {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}
 	EndProjectSection
 EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fake_resolver_test", "vcxproj\test\fake_resolver_test\fake_resolver_test.vcxproj", "{2F59EB2E-CEF9-A291-9480-1F737C3E5E57}"
+	ProjectSection(myProperties) = preProject
+        	lib = "False"
+	EndProjectSection
+	ProjectSection(ProjectDependencies) = postProject
+		{17BCAFC0-5FDC-4C94-AEB9-95F3E220614B} = {17BCAFC0-5FDC-4C94-AEB9-95F3E220614B}
+		{29D16885-7228-4C31-81ED-5F9187C7F2A9} = {29D16885-7228-4C31-81ED-5F9187C7F2A9}
+		{EAB0A629-17A9-44DB-B5FF-E91A721FE037} = {EAB0A629-17A9-44DB-B5FF-E91A721FE037}
+		{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} = {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}
+	EndProjectSection
+EndProject
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fling_client", "vcxproj\test\fling_client\fling_client.vcxproj", "{0647D598-9611-F659-EA36-DF995C9F736B}"
 	ProjectSection(myProperties) = preProject
         	lib = "False"
@@ -1242,6 +1253,17 @@
 		{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} = {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}
 	EndProjectSection
 EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "minimal_stack_is_minimal_test", "vcxproj\test\minimal_stack_is_minimal_test\minimal_stack_is_minimal_test.vcxproj", "{68A54124-DFA3-4FF3-081F-70356222C977}"
+	ProjectSection(myProperties) = preProject
+        	lib = "False"
+	EndProjectSection
+	ProjectSection(ProjectDependencies) = postProject
+		{17BCAFC0-5FDC-4C94-AEB9-95F3E220614B} = {17BCAFC0-5FDC-4C94-AEB9-95F3E220614B}
+		{29D16885-7228-4C31-81ED-5F9187C7F2A9} = {29D16885-7228-4C31-81ED-5F9187C7F2A9}
+		{EAB0A629-17A9-44DB-B5FF-E91A721FE037} = {EAB0A629-17A9-44DB-B5FF-E91A721FE037}
+		{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} = {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}
+	EndProjectSection
+EndProject
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mlog_test", "vcxproj\test\mlog_test\mlog_test.vcxproj", "{9345E329-80F3-DED4-FDC3-BF63FCEA2C03}"
 	ProjectSection(myProperties) = preProject
         	lib = "False"
@@ -2105,6 +2127,22 @@
 		{42720233-A6D4-66BC-CCA2-06B57261D0B3}.Release-DLL|Win32.Build.0 = Release|Win32
 		{42720233-A6D4-66BC-CCA2-06B57261D0B3}.Release-DLL|x64.ActiveCfg = Release|x64
 		{42720233-A6D4-66BC-CCA2-06B57261D0B3}.Release-DLL|x64.Build.0 = Release|x64
+		{2F59EB2E-CEF9-A291-9480-1F737C3E5E57}.Debug|Win32.ActiveCfg = Debug|Win32
+		{2F59EB2E-CEF9-A291-9480-1F737C3E5E57}.Debug|x64.ActiveCfg = Debug|x64
+		{2F59EB2E-CEF9-A291-9480-1F737C3E5E57}.Release|Win32.ActiveCfg = Release|Win32
+		{2F59EB2E-CEF9-A291-9480-1F737C3E5E57}.Release|x64.ActiveCfg = Release|x64
+		{2F59EB2E-CEF9-A291-9480-1F737C3E5E57}.Debug|Win32.Build.0 = Debug|Win32
+		{2F59EB2E-CEF9-A291-9480-1F737C3E5E57}.Debug|x64.Build.0 = Debug|x64
+		{2F59EB2E-CEF9-A291-9480-1F737C3E5E57}.Release|Win32.Build.0 = Release|Win32
+		{2F59EB2E-CEF9-A291-9480-1F737C3E5E57}.Release|x64.Build.0 = Release|x64
+		{2F59EB2E-CEF9-A291-9480-1F737C3E5E57}.Debug-DLL|Win32.ActiveCfg = Debug|Win32
+		{2F59EB2E-CEF9-A291-9480-1F737C3E5E57}.Debug-DLL|Win32.Build.0 = Debug|Win32
+		{2F59EB2E-CEF9-A291-9480-1F737C3E5E57}.Debug-DLL|x64.ActiveCfg = Debug|x64
+		{2F59EB2E-CEF9-A291-9480-1F737C3E5E57}.Debug-DLL|x64.Build.0 = Debug|x64
+		{2F59EB2E-CEF9-A291-9480-1F737C3E5E57}.Release-DLL|Win32.ActiveCfg = Release|Win32
+		{2F59EB2E-CEF9-A291-9480-1F737C3E5E57}.Release-DLL|Win32.Build.0 = Release|Win32
+		{2F59EB2E-CEF9-A291-9480-1F737C3E5E57}.Release-DLL|x64.ActiveCfg = Release|x64
+		{2F59EB2E-CEF9-A291-9480-1F737C3E5E57}.Release-DLL|x64.Build.0 = Release|x64
 		{0647D598-9611-F659-EA36-DF995C9F736B}.Debug|Win32.ActiveCfg = Debug|Win32
 		{0647D598-9611-F659-EA36-DF995C9F736B}.Debug|x64.ActiveCfg = Debug|x64
 		{0647D598-9611-F659-EA36-DF995C9F736B}.Release|Win32.ActiveCfg = Release|Win32
@@ -3513,6 +3551,22 @@
 		{07170557-CCB0-D23C-8018-C2909D115DF9}.Release-DLL|Win32.Build.0 = Release|Win32
 		{07170557-CCB0-D23C-8018-C2909D115DF9}.Release-DLL|x64.ActiveCfg = Release|x64
 		{07170557-CCB0-D23C-8018-C2909D115DF9}.Release-DLL|x64.Build.0 = Release|x64
+		{68A54124-DFA3-4FF3-081F-70356222C977}.Debug|Win32.ActiveCfg = Debug|Win32
+		{68A54124-DFA3-4FF3-081F-70356222C977}.Debug|x64.ActiveCfg = Debug|x64
+		{68A54124-DFA3-4FF3-081F-70356222C977}.Release|Win32.ActiveCfg = Release|Win32
+		{68A54124-DFA3-4FF3-081F-70356222C977}.Release|x64.ActiveCfg = Release|x64
+		{68A54124-DFA3-4FF3-081F-70356222C977}.Debug|Win32.Build.0 = Debug|Win32
+		{68A54124-DFA3-4FF3-081F-70356222C977}.Debug|x64.Build.0 = Debug|x64
+		{68A54124-DFA3-4FF3-081F-70356222C977}.Release|Win32.Build.0 = Release|Win32
+		{68A54124-DFA3-4FF3-081F-70356222C977}.Release|x64.Build.0 = Release|x64
+		{68A54124-DFA3-4FF3-081F-70356222C977}.Debug-DLL|Win32.ActiveCfg = Debug|Win32
+		{68A54124-DFA3-4FF3-081F-70356222C977}.Debug-DLL|Win32.Build.0 = Debug|Win32
+		{68A54124-DFA3-4FF3-081F-70356222C977}.Debug-DLL|x64.ActiveCfg = Debug|x64
+		{68A54124-DFA3-4FF3-081F-70356222C977}.Debug-DLL|x64.Build.0 = Debug|x64
+		{68A54124-DFA3-4FF3-081F-70356222C977}.Release-DLL|Win32.ActiveCfg = Release|Win32
+		{68A54124-DFA3-4FF3-081F-70356222C977}.Release-DLL|Win32.Build.0 = Release|Win32
+		{68A54124-DFA3-4FF3-081F-70356222C977}.Release-DLL|x64.ActiveCfg = Release|x64
+		{68A54124-DFA3-4FF3-081F-70356222C977}.Release-DLL|x64.Build.0 = Release|x64
 		{9345E329-80F3-DED4-FDC3-BF63FCEA2C03}.Debug|Win32.ActiveCfg = Debug|Win32
 		{9345E329-80F3-DED4-FDC3-BF63FCEA2C03}.Debug|x64.ActiveCfg = Debug|x64
 		{9345E329-80F3-DED4-FDC3-BF63FCEA2C03}.Release|Win32.ActiveCfg = Release|Win32
diff --git a/vsprojects/grpc.sln b/vsprojects/grpc.sln
index fbb19c2..97378e0 100644
--- a/vsprojects/grpc.sln
+++ b/vsprojects/grpc.sln
@@ -57,6 +57,14 @@
 		{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} = {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}
 	EndProjectSection
 EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "grpc++_error_details", "vcxproj\.\grpc++_error_details\grpc++_error_details.vcxproj", "{9F58AD72-49E1-4D10-B826-9E190AB0AAC0}"
+	ProjectSection(myProperties) = preProject
+        	lib = "True"
+	EndProjectSection
+	ProjectSection(ProjectDependencies) = postProject
+		{C187A093-A0FE-489D-A40A-6E33DE0F9FEB} = {C187A093-A0FE-489D-A40A-6E33DE0F9FEB}
+	EndProjectSection
+EndProject
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "grpc++_unsecure", "vcxproj\.\grpc++_unsecure\grpc++_unsecure.vcxproj", "{6EE56155-DF7C-4F6E-BFC4-F6F776BEB211}"
 	ProjectSection(myProperties) = preProject
         	lib = "True"
@@ -294,6 +302,22 @@
 		{C187A093-A0FE-489D-A40A-6E33DE0F9FEB}.Release-DLL|Win32.Build.0 = Release-DLL|Win32
 		{C187A093-A0FE-489D-A40A-6E33DE0F9FEB}.Release-DLL|x64.ActiveCfg = Release-DLL|x64
 		{C187A093-A0FE-489D-A40A-6E33DE0F9FEB}.Release-DLL|x64.Build.0 = Release-DLL|x64
+		{9F58AD72-49E1-4D10-B826-9E190AB0AAC0}.Debug|Win32.ActiveCfg = Debug|Win32
+		{9F58AD72-49E1-4D10-B826-9E190AB0AAC0}.Debug|x64.ActiveCfg = Debug|x64
+		{9F58AD72-49E1-4D10-B826-9E190AB0AAC0}.Release|Win32.ActiveCfg = Release|Win32
+		{9F58AD72-49E1-4D10-B826-9E190AB0AAC0}.Release|x64.ActiveCfg = Release|x64
+		{9F58AD72-49E1-4D10-B826-9E190AB0AAC0}.Debug|Win32.Build.0 = Debug|Win32
+		{9F58AD72-49E1-4D10-B826-9E190AB0AAC0}.Debug|x64.Build.0 = Debug|x64
+		{9F58AD72-49E1-4D10-B826-9E190AB0AAC0}.Release|Win32.Build.0 = Release|Win32
+		{9F58AD72-49E1-4D10-B826-9E190AB0AAC0}.Release|x64.Build.0 = Release|x64
+		{9F58AD72-49E1-4D10-B826-9E190AB0AAC0}.Debug-DLL|Win32.ActiveCfg = Debug|Win32
+		{9F58AD72-49E1-4D10-B826-9E190AB0AAC0}.Debug-DLL|Win32.Build.0 = Debug|Win32
+		{9F58AD72-49E1-4D10-B826-9E190AB0AAC0}.Debug-DLL|x64.ActiveCfg = Debug|x64
+		{9F58AD72-49E1-4D10-B826-9E190AB0AAC0}.Debug-DLL|x64.Build.0 = Debug|x64
+		{9F58AD72-49E1-4D10-B826-9E190AB0AAC0}.Release-DLL|Win32.ActiveCfg = Release|Win32
+		{9F58AD72-49E1-4D10-B826-9E190AB0AAC0}.Release-DLL|Win32.Build.0 = Release|Win32
+		{9F58AD72-49E1-4D10-B826-9E190AB0AAC0}.Release-DLL|x64.ActiveCfg = Release|x64
+		{9F58AD72-49E1-4D10-B826-9E190AB0AAC0}.Release-DLL|x64.Build.0 = Release|x64
 		{6EE56155-DF7C-4F6E-BFC4-F6F776BEB211}.Debug|Win32.ActiveCfg = Debug|Win32
 		{6EE56155-DF7C-4F6E-BFC4-F6F776BEB211}.Debug|x64.ActiveCfg = Debug|x64
 		{6EE56155-DF7C-4F6E-BFC4-F6F776BEB211}.Release|Win32.ActiveCfg = Release|Win32
diff --git a/vsprojects/vcxproj/grpc++/grpc++.vcxproj b/vsprojects/vcxproj/grpc++/grpc++.vcxproj
index cae44c5..d62b554 100644
--- a/vsprojects/vcxproj/grpc++/grpc++.vcxproj
+++ b/vsprojects/vcxproj/grpc++/grpc++.vcxproj
@@ -380,16 +380,11 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\channel_args.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\channel_stack.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\channel_stack_builder.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\compress_filter.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\connected_channel.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\context.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\deadline_filter.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\handshaker.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\handshaker_factory.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\handshaker_registry.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\http_client_filter.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\http_server_filter.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\message_size_filter.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\compression\algorithm_metadata.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\compression\message_compress.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\debug\trace.h" />
@@ -582,24 +577,14 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\channel_stack_builder.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\compress_filter.c">
-    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\connected_channel.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\deadline_filter.c">
-    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\handshaker.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\handshaker_factory.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\handshaker_registry.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\http_client_filter.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\http_server_filter.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\message_size_filter.c">
-    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\compression\compression.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\compression\message_compress.c">
diff --git a/vsprojects/vcxproj/grpc++/grpc++.vcxproj.filters b/vsprojects/vcxproj/grpc++/grpc++.vcxproj.filters
index 36da089..ef3862d 100644
--- a/vsprojects/vcxproj/grpc++/grpc++.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc++/grpc++.vcxproj.filters
@@ -133,15 +133,9 @@
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\channel_stack_builder.c">
       <Filter>src\core\lib\channel</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\compress_filter.c">
-      <Filter>src\core\lib\channel</Filter>
-    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\connected_channel.c">
       <Filter>src\core\lib\channel</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\deadline_filter.c">
-      <Filter>src\core\lib\channel</Filter>
-    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\handshaker.c">
       <Filter>src\core\lib\channel</Filter>
     </ClCompile>
@@ -151,15 +145,6 @@
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\handshaker_registry.c">
       <Filter>src\core\lib\channel</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\http_client_filter.c">
-      <Filter>src\core\lib\channel</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\http_server_filter.c">
-      <Filter>src\core\lib\channel</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\message_size_filter.c">
-      <Filter>src\core\lib\channel</Filter>
-    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\compression\compression.c">
       <Filter>src\core\lib\compression</Filter>
     </ClCompile>
@@ -875,18 +860,12 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\channel_stack_builder.h">
       <Filter>src\core\lib\channel</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\compress_filter.h">
-      <Filter>src\core\lib\channel</Filter>
-    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\connected_channel.h">
       <Filter>src\core\lib\channel</Filter>
     </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\context.h">
       <Filter>src\core\lib\channel</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\deadline_filter.h">
-      <Filter>src\core\lib\channel</Filter>
-    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\handshaker.h">
       <Filter>src\core\lib\channel</Filter>
     </ClInclude>
@@ -896,15 +875,6 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\handshaker_registry.h">
       <Filter>src\core\lib\channel</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\http_client_filter.h">
-      <Filter>src\core\lib\channel</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\http_server_filter.h">
-      <Filter>src\core\lib\channel</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\message_size_filter.h">
-      <Filter>src\core\lib\channel</Filter>
-    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\compression\algorithm_metadata.h">
       <Filter>src\core\lib\compression</Filter>
     </ClInclude>
diff --git a/vsprojects/vcxproj/grpc++_error_details/grpc++_error_details.vcxproj b/vsprojects/vcxproj/grpc++_error_details/grpc++_error_details.vcxproj
new file mode 100644
index 0000000..6bb3d47
--- /dev/null
+++ b/vsprojects/vcxproj/grpc++_error_details/grpc++_error_details.vcxproj
@@ -0,0 +1,178 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|Win32">
+      <Configuration>Debug</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Debug|x64">
+      <Configuration>Debug</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|Win32">
+      <Configuration>Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|x64">
+      <Configuration>Release</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{9F58AD72-49E1-4D10-B826-9E190AB0AAC0}</ProjectGuid>
+    <IgnoreWarnIntDirInTempDetected>true</IgnoreWarnIntDirInTempDetected>
+    <IntDir>$(SolutionDir)IntDir\$(MSBuildProjectName)\</IntDir>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '10.0'" Label="Configuration">
+    <PlatformToolset>v100</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '11.0'" Label="Configuration">
+    <PlatformToolset>v110</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '12.0'" Label="Configuration">
+    <PlatformToolset>v120</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '14.0'" Label="Configuration">
+    <PlatformToolset>v140</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration">
+    <ConfigurationType>StaticLibrary</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration">
+    <ConfigurationType>StaticLibrary</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+    <Import Project="$(SolutionDir)\..\vsprojects\global.props" />
+    <Import Project="$(SolutionDir)\..\vsprojects\winsock.props" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup Condition="'$(Configuration)'=='Debug'">
+    <TargetName>grpc++_error_details</TargetName>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)'=='Release'">
+    <TargetName>grpc++_error_details</TargetName>
+  </PropertyGroup>
+    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+
+    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+
+    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>MaxSpeed</Optimization>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+  </ItemDefinitionGroup>
+
+    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>MaxSpeed</Optimization>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+  </ItemDefinitionGroup>
+
+  <ItemGroup>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\support\error_details.h" />
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="$(SolutionDir)\..\src\proto\grpc\status\status.pb.cc">
+    </ClCompile>
+    <ClInclude Include="$(SolutionDir)\..\src\proto\grpc\status\status.pb.h">
+    </ClInclude>
+    <ClCompile Include="$(SolutionDir)\..\src\proto\grpc\status\status.grpc.pb.cc">
+    </ClCompile>
+    <ClInclude Include="$(SolutionDir)\..\src\proto\grpc\status\status.grpc.pb.h">
+    </ClInclude>
+    <ClCompile Include="$(SolutionDir)\..\src\cpp\util\error_details.cc">
+    </ClCompile>
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc++\grpc++.vcxproj">
+      <Project>{C187A093-A0FE-489D-A40A-6E33DE0F9FEB}</Project>
+    </ProjectReference>
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+  </ImportGroup>
+  <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
+    <PropertyGroup>
+      <ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them.  For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
+    </PropertyGroup>
+  </Target>
+</Project>
+
diff --git a/vsprojects/vcxproj/grpc++_error_details/grpc++_error_details.vcxproj.filters b/vsprojects/vcxproj/grpc++_error_details/grpc++_error_details.vcxproj.filters
new file mode 100644
index 0000000..e1814ee
--- /dev/null
+++ b/vsprojects/vcxproj/grpc++_error_details/grpc++_error_details.vcxproj.filters
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup>
+    <ClCompile Include="$(SolutionDir)\..\src\proto\grpc\status\status.proto">
+      <Filter>src\proto\grpc\status</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\cpp\util\error_details.cc">
+      <Filter>src\cpp\util</Filter>
+    </ClCompile>
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\support\error_details.h">
+      <Filter>include\grpc++\support</Filter>
+    </ClInclude>
+  </ItemGroup>
+
+  <ItemGroup>
+    <Filter Include="include">
+      <UniqueIdentifier>{013272b5-4742-ba38-7cb6-25ff3484ac1d}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="include\grpc++">
+      <UniqueIdentifier>{f589296d-1ee4-913f-0345-7d8bf51f657b}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="include\grpc++\support">
+      <UniqueIdentifier>{3455fa30-ad44-8790-9dc2-ff4ac7dd9e6c}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src">
+      <UniqueIdentifier>{cf07aafe-1d45-af88-81fb-0bbd5afd247f}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\cpp">
+      <UniqueIdentifier>{00726556-da02-06d8-bb32-902f55133c6b}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\cpp\util">
+      <UniqueIdentifier>{fd90d13e-cc1f-e8cc-56ee-650231b08f56}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\proto">
+      <UniqueIdentifier>{ec6be373-4683-335e-03d9-dc636e34d7ef}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\proto\grpc">
+      <UniqueIdentifier>{8200edf2-9498-6cd9-d8f3-81ad881ca82c}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\proto\grpc\status">
+      <UniqueIdentifier>{79c5c1ea-19a8-bf5a-5e0a-3de6ad3a0465}</UniqueIdentifier>
+    </Filter>
+  </ItemGroup>
+</Project>
+
diff --git a/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj b/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj
index 4d28400..6727688 100644
--- a/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj
+++ b/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj
@@ -374,16 +374,11 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\channel_args.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\channel_stack.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\channel_stack_builder.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\compress_filter.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\connected_channel.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\context.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\deadline_filter.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\handshaker.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\handshaker_factory.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\handshaker_registry.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\http_client_filter.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\http_server_filter.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\message_size_filter.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\compression\algorithm_metadata.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\compression\message_compress.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\debug\trace.h" />
@@ -566,24 +561,14 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\channel_stack_builder.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\compress_filter.c">
-    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\connected_channel.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\deadline_filter.c">
-    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\handshaker.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\handshaker_factory.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\handshaker_registry.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\http_client_filter.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\http_server_filter.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\message_size_filter.c">
-    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\compression\compression.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\compression\message_compress.c">
diff --git a/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj.filters b/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj.filters
index 9d64155..d39756b 100644
--- a/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj.filters
@@ -118,15 +118,9 @@
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\channel_stack_builder.c">
       <Filter>src\core\lib\channel</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\compress_filter.c">
-      <Filter>src\core\lib\channel</Filter>
-    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\connected_channel.c">
       <Filter>src\core\lib\channel</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\deadline_filter.c">
-      <Filter>src\core\lib\channel</Filter>
-    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\handshaker.c">
       <Filter>src\core\lib\channel</Filter>
     </ClCompile>
@@ -136,15 +130,6 @@
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\handshaker_registry.c">
       <Filter>src\core\lib\channel</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\http_client_filter.c">
-      <Filter>src\core\lib\channel</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\http_server_filter.c">
-      <Filter>src\core\lib\channel</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\message_size_filter.c">
-      <Filter>src\core\lib\channel</Filter>
-    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\compression\compression.c">
       <Filter>src\core\lib\compression</Filter>
     </ClCompile>
@@ -842,18 +827,12 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\channel_stack_builder.h">
       <Filter>src\core\lib\channel</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\compress_filter.h">
-      <Filter>src\core\lib\channel</Filter>
-    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\connected_channel.h">
       <Filter>src\core\lib\channel</Filter>
     </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\context.h">
       <Filter>src\core\lib\channel</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\deadline_filter.h">
-      <Filter>src\core\lib\channel</Filter>
-    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\handshaker.h">
       <Filter>src\core\lib\channel</Filter>
     </ClInclude>
@@ -863,15 +842,6 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\handshaker_registry.h">
       <Filter>src\core\lib\channel</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\http_client_filter.h">
-      <Filter>src\core\lib\channel</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\http_server_filter.h">
-      <Filter>src\core\lib\channel</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\message_size_filter.h">
-      <Filter>src\core\lib\channel</Filter>
-    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\compression\algorithm_metadata.h">
       <Filter>src\core\lib\compression</Filter>
     </ClInclude>
diff --git a/vsprojects/vcxproj/grpc/grpc.vcxproj b/vsprojects/vcxproj/grpc/grpc.vcxproj
index dd6fdd8..ca70dde 100644
--- a/vsprojects/vcxproj/grpc/grpc.vcxproj
+++ b/vsprojects/vcxproj/grpc/grpc.vcxproj
@@ -303,16 +303,11 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\channel_args.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\channel_stack.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\channel_stack_builder.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\compress_filter.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\connected_channel.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\context.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\deadline_filter.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\handshaker.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\handshaker_factory.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\handshaker_registry.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\http_client_filter.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\http_server_filter.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\message_size_filter.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\compression\algorithm_metadata.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\compression\message_compress.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\debug\trace.h" />
@@ -424,12 +419,16 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\hpack_encoder.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\hpack_parser.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\hpack_table.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\http2_settings.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\huffsyms.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\incoming_metadata.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\internal.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\stream_map.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\varint.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\alpn\alpn.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\http\client\http_client_filter.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\http\message_compress\message_compress_filter.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\http\server\http_server_filter.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\security\context\security_context.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\security\credentials\composite\composite_credentials.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\security\credentials\credentials.h" />
@@ -473,6 +472,7 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\subchannel.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\subchannel_index.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\uri_parser.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\deadline\deadline_filter.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\client\chttp2_connector.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy\grpclb\grpclb.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy\grpclb\grpclb_channel.h" />
@@ -503,6 +503,7 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\trace_string.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\tracing.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\max_age\max_age_filter.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\message_size\message_size_filter.h" />
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\init.c">
@@ -513,24 +514,14 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\channel_stack_builder.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\compress_filter.c">
-    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\connected_channel.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\deadline_filter.c">
-    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\handshaker.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\handshaker_factory.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\handshaker_registry.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\http_client_filter.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\http_server_filter.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\message_size_filter.c">
-    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\compression\compression.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\compression\message_compress.c">
@@ -785,6 +776,8 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\hpack_table.c">
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\http2_settings.c">
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\huffsyms.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\incoming_metadata.c">
@@ -801,6 +794,14 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\alpn\alpn.c">
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\http\client\http_client_filter.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\http\http_filters_plugin.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\http\message_compress\message_compress_filter.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\http\server\http_server_filter.c">
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\http\httpcli_security_connector.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\security\context\security_context.c">
@@ -899,6 +900,8 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\uri_parser.c">
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\deadline\deadline_filter.c">
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\client\chttp2_connector.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\server\insecure\server_chttp2.c">
@@ -971,6 +974,8 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\max_age\max_age_filter.c">
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\message_size\message_size_filter.c">
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\plugin_registry\grpc_plugin_registry.c">
     </ClCompile>
   </ItemGroup>
diff --git a/vsprojects/vcxproj/grpc/grpc.vcxproj.filters b/vsprojects/vcxproj/grpc/grpc.vcxproj.filters
index 51c9b72..acadc0a 100644
--- a/vsprojects/vcxproj/grpc/grpc.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc/grpc.vcxproj.filters
@@ -13,15 +13,9 @@
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\channel_stack_builder.c">
       <Filter>src\core\lib\channel</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\compress_filter.c">
-      <Filter>src\core\lib\channel</Filter>
-    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\connected_channel.c">
       <Filter>src\core\lib\channel</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\deadline_filter.c">
-      <Filter>src\core\lib\channel</Filter>
-    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\handshaker.c">
       <Filter>src\core\lib\channel</Filter>
     </ClCompile>
@@ -31,15 +25,6 @@
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\handshaker_registry.c">
       <Filter>src\core\lib\channel</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\http_client_filter.c">
-      <Filter>src\core\lib\channel</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\http_server_filter.c">
-      <Filter>src\core\lib\channel</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\message_size_filter.c">
-      <Filter>src\core\lib\channel</Filter>
-    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\compression\compression.c">
       <Filter>src\core\lib\compression</Filter>
     </ClCompile>
@@ -421,6 +406,9 @@
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\hpack_table.c">
       <Filter>src\core\ext\transport\chttp2\transport</Filter>
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\http2_settings.c">
+      <Filter>src\core\ext\transport\chttp2\transport</Filter>
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\huffsyms.c">
       <Filter>src\core\ext\transport\chttp2\transport</Filter>
     </ClCompile>
@@ -445,6 +433,18 @@
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\alpn\alpn.c">
       <Filter>src\core\ext\transport\chttp2\alpn</Filter>
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\http\client\http_client_filter.c">
+      <Filter>src\core\ext\filters\http\client</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\http\http_filters_plugin.c">
+      <Filter>src\core\ext\filters\http</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\http\message_compress\message_compress_filter.c">
+      <Filter>src\core\ext\filters\http\message_compress</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\http\server\http_server_filter.c">
+      <Filter>src\core\ext\filters\http\server</Filter>
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\http\httpcli_security_connector.c">
       <Filter>src\core\lib\http</Filter>
     </ClCompile>
@@ -592,6 +592,9 @@
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\uri_parser.c">
       <Filter>src\core\ext\filters\client_channel</Filter>
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\deadline\deadline_filter.c">
+      <Filter>src\core\ext\filters\deadline</Filter>
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\client\chttp2_connector.c">
       <Filter>src\core\ext\transport\chttp2\client</Filter>
     </ClCompile>
@@ -700,6 +703,9 @@
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\max_age\max_age_filter.c">
       <Filter>src\core\ext\filters\max_age</Filter>
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\message_size\message_size_filter.c">
+      <Filter>src\core\ext\filters\message_size</Filter>
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\plugin_registry\grpc_plugin_registry.c">
       <Filter>src\core\plugin_registry</Filter>
     </ClCompile>
@@ -809,18 +815,12 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\channel_stack_builder.h">
       <Filter>src\core\lib\channel</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\compress_filter.h">
-      <Filter>src\core\lib\channel</Filter>
-    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\connected_channel.h">
       <Filter>src\core\lib\channel</Filter>
     </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\context.h">
       <Filter>src\core\lib\channel</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\deadline_filter.h">
-      <Filter>src\core\lib\channel</Filter>
-    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\handshaker.h">
       <Filter>src\core\lib\channel</Filter>
     </ClInclude>
@@ -830,15 +830,6 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\handshaker_registry.h">
       <Filter>src\core\lib\channel</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\http_client_filter.h">
-      <Filter>src\core\lib\channel</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\http_server_filter.h">
-      <Filter>src\core\lib\channel</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\message_size_filter.h">
-      <Filter>src\core\lib\channel</Filter>
-    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\compression\algorithm_metadata.h">
       <Filter>src\core\lib\compression</Filter>
     </ClInclude>
@@ -1172,6 +1163,9 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\hpack_table.h">
       <Filter>src\core\ext\transport\chttp2\transport</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\http2_settings.h">
+      <Filter>src\core\ext\transport\chttp2\transport</Filter>
+    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\huffsyms.h">
       <Filter>src\core\ext\transport\chttp2\transport</Filter>
     </ClInclude>
@@ -1190,6 +1184,15 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\alpn\alpn.h">
       <Filter>src\core\ext\transport\chttp2\alpn</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\http\client\http_client_filter.h">
+      <Filter>src\core\ext\filters\http\client</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\http\message_compress\message_compress_filter.h">
+      <Filter>src\core\ext\filters\http\message_compress</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\http\server\http_server_filter.h">
+      <Filter>src\core\ext\filters\http\server</Filter>
+    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\security\context\security_context.h">
       <Filter>src\core\lib\security\context</Filter>
     </ClInclude>
@@ -1319,6 +1322,9 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\uri_parser.h">
       <Filter>src\core\ext\filters\client_channel</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\deadline\deadline_filter.h">
+      <Filter>src\core\ext\filters\deadline</Filter>
+    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\client\chttp2_connector.h">
       <Filter>src\core\ext\transport\chttp2\client</Filter>
     </ClInclude>
@@ -1409,6 +1415,9 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\max_age\max_age_filter.h">
       <Filter>src\core\ext\filters\max_age</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\message_size\message_size_filter.h">
+      <Filter>src\core\ext\filters\message_size</Filter>
+    </ClInclude>
   </ItemGroup>
 
   <ItemGroup>
@@ -1484,12 +1493,30 @@
     <Filter Include="src\core\ext\filters\client_channel\resolver\sockaddr">
       <UniqueIdentifier>{bd317dd5-323e-5b27-4c05-d85786be36ab}</UniqueIdentifier>
     </Filter>
+    <Filter Include="src\core\ext\filters\deadline">
+      <UniqueIdentifier>{c8dcda4e-dbaa-1ae8-67a9-0dd26046f652}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\core\ext\filters\http">
+      <UniqueIdentifier>{2e3ab9f3-39ca-db39-cb3e-2196cbc68098}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\core\ext\filters\http\client">
+      <UniqueIdentifier>{e4f7616b-2b49-7df9-8ca3-eb7848d4609d}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\core\ext\filters\http\message_compress">
+      <UniqueIdentifier>{7b595f5a-c5b5-29fe-74c2-5ec5fd5c94d2}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\core\ext\filters\http\server">
+      <UniqueIdentifier>{a40e82ca-0c04-35b8-898d-7ad5f323d110}</UniqueIdentifier>
+    </Filter>
     <Filter Include="src\core\ext\filters\load_reporting">
       <UniqueIdentifier>{12559ba7-9445-92ae-0c5a-2d79570d4c9b}</UniqueIdentifier>
     </Filter>
     <Filter Include="src\core\ext\filters\max_age">
       <UniqueIdentifier>{5369e83c-4625-fc14-cc40-9db5da3a7af4}</UniqueIdentifier>
     </Filter>
+    <Filter Include="src\core\ext\filters\message_size">
+      <UniqueIdentifier>{5ca3f38c-539f-3c4f-b68c-38b31ba339ba}</UniqueIdentifier>
+    </Filter>
     <Filter Include="src\core\ext\transport">
       <UniqueIdentifier>{e3abfd0a-064e-0f2f-c8e8-7c5a7e98142a}</UniqueIdentifier>
     </Filter>
diff --git a/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj b/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj
index b1db7e5..a5ec4ae 100644
--- a/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj
+++ b/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj
@@ -198,16 +198,11 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\channel_args.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\channel_stack.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\channel_stack_builder.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\compress_filter.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\connected_channel.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\context.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\deadline_filter.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\handshaker.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\handshaker_factory.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\handshaker_registry.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\http_client_filter.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\http_server_filter.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\message_size_filter.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\compression\algorithm_metadata.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\compression\message_compress.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\debug\trace.h" />
@@ -354,24 +349,14 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\channel_stack_builder.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\compress_filter.c">
-    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\connected_channel.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\deadline_filter.c">
-    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\handshaker.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\handshaker_factory.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\handshaker_registry.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\http_client_filter.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\http_server_filter.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\message_size_filter.c">
-    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\compression\compression.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\compression\message_compress.c">
diff --git a/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj.filters b/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj.filters
index a7ecbea..4078ebd 100644
--- a/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj.filters
@@ -70,15 +70,9 @@
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\channel_stack_builder.c">
       <Filter>src\core\lib\channel</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\compress_filter.c">
-      <Filter>src\core\lib\channel</Filter>
-    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\connected_channel.c">
       <Filter>src\core\lib\channel</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\deadline_filter.c">
-      <Filter>src\core\lib\channel</Filter>
-    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\handshaker.c">
       <Filter>src\core\lib\channel</Filter>
     </ClCompile>
@@ -88,15 +82,6 @@
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\handshaker_registry.c">
       <Filter>src\core\lib\channel</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\http_client_filter.c">
-      <Filter>src\core\lib\channel</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\http_server_filter.c">
-      <Filter>src\core\lib\channel</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\message_size_filter.c">
-      <Filter>src\core\lib\channel</Filter>
-    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\compression\compression.c">
       <Filter>src\core\lib\compression</Filter>
     </ClCompile>
@@ -587,18 +572,12 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\channel_stack_builder.h">
       <Filter>src\core\lib\channel</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\compress_filter.h">
-      <Filter>src\core\lib\channel</Filter>
-    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\connected_channel.h">
       <Filter>src\core\lib\channel</Filter>
     </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\context.h">
       <Filter>src\core\lib\channel</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\deadline_filter.h">
-      <Filter>src\core\lib\channel</Filter>
-    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\handshaker.h">
       <Filter>src\core\lib\channel</Filter>
     </ClInclude>
@@ -608,15 +587,6 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\handshaker_registry.h">
       <Filter>src\core\lib\channel</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\http_client_filter.h">
-      <Filter>src\core\lib\channel</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\http_server_filter.h">
-      <Filter>src\core\lib\channel</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\message_size_filter.h">
-      <Filter>src\core\lib\channel</Filter>
-    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\compression\algorithm_metadata.h">
       <Filter>src\core\lib\compression</Filter>
     </ClInclude>
diff --git a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj
index 8614b11..c844e15 100644
--- a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj
+++ b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj
@@ -293,16 +293,11 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\channel_args.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\channel_stack.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\channel_stack_builder.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\compress_filter.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\connected_channel.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\context.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\deadline_filter.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\handshaker.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\handshaker_factory.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\handshaker_registry.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\http_client_filter.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\http_server_filter.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\message_size_filter.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\compression\algorithm_metadata.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\compression\message_compress.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\debug\trace.h" />
@@ -414,12 +409,16 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\hpack_encoder.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\hpack_parser.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\hpack_table.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\http2_settings.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\huffsyms.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\incoming_metadata.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\internal.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\stream_map.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\varint.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\alpn\alpn.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\http\client\http_client_filter.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\http\message_compress\message_compress_filter.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\http\server\http_server_filter.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\server\chttp2_server.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\client\chttp2_connector.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\client_channel.h" />
@@ -440,6 +439,7 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\subchannel.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\subchannel_index.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\uri_parser.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\deadline\deadline_filter.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver\dns\c_ares\grpc_ares_ev_driver.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver\dns\c_ares\grpc_ares_wrapper.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\load_reporting\load_reporting.h" />
@@ -469,6 +469,7 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\trace_string.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\tracing.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\max_age\max_age_filter.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\message_size\message_size_filter.h" />
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\init.c">
@@ -481,24 +482,14 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\channel_stack_builder.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\compress_filter.c">
-    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\connected_channel.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\deadline_filter.c">
-    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\handshaker.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\handshaker_factory.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\handshaker_registry.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\http_client_filter.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\http_server_filter.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\message_size_filter.c">
-    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\compression\compression.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\compression\message_compress.c">
@@ -755,6 +746,8 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\hpack_table.c">
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\http2_settings.c">
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\huffsyms.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\incoming_metadata.c">
@@ -771,6 +764,14 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\alpn\alpn.c">
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\http\client\http_client_filter.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\http\http_filters_plugin.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\http\message_compress\message_compress_filter.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\http\server\http_server_filter.c">
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\server\chttp2_server.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\client\insecure\channel_create.c">
@@ -819,6 +820,8 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\uri_parser.c">
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\deadline\deadline_filter.c">
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver\dns\c_ares\dns_resolver_ares.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver\dns\c_ares\grpc_ares_ev_driver_posix.c">
@@ -881,6 +884,8 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\max_age\max_age_filter.c">
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\message_size\message_size_filter.c">
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\plugin_registry\grpc_unsecure_plugin_registry.c">
     </ClCompile>
   </ItemGroup>
diff --git a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters
index e7aa9fb..43d27b4 100644
--- a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters
@@ -16,15 +16,9 @@
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\channel_stack_builder.c">
       <Filter>src\core\lib\channel</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\compress_filter.c">
-      <Filter>src\core\lib\channel</Filter>
-    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\connected_channel.c">
       <Filter>src\core\lib\channel</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\deadline_filter.c">
-      <Filter>src\core\lib\channel</Filter>
-    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\handshaker.c">
       <Filter>src\core\lib\channel</Filter>
     </ClCompile>
@@ -34,15 +28,6 @@
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\handshaker_registry.c">
       <Filter>src\core\lib\channel</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\http_client_filter.c">
-      <Filter>src\core\lib\channel</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\http_server_filter.c">
-      <Filter>src\core\lib\channel</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\message_size_filter.c">
-      <Filter>src\core\lib\channel</Filter>
-    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\compression\compression.c">
       <Filter>src\core\lib\compression</Filter>
     </ClCompile>
@@ -427,6 +412,9 @@
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\hpack_table.c">
       <Filter>src\core\ext\transport\chttp2\transport</Filter>
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\http2_settings.c">
+      <Filter>src\core\ext\transport\chttp2\transport</Filter>
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\huffsyms.c">
       <Filter>src\core\ext\transport\chttp2\transport</Filter>
     </ClCompile>
@@ -451,6 +439,18 @@
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\alpn\alpn.c">
       <Filter>src\core\ext\transport\chttp2\alpn</Filter>
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\http\client\http_client_filter.c">
+      <Filter>src\core\ext\filters\http\client</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\http\http_filters_plugin.c">
+      <Filter>src\core\ext\filters\http</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\http\message_compress\message_compress_filter.c">
+      <Filter>src\core\ext\filters\http\message_compress</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\http\server\http_server_filter.c">
+      <Filter>src\core\ext\filters\http\server</Filter>
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\server\chttp2_server.c">
       <Filter>src\core\ext\transport\chttp2\server</Filter>
     </ClCompile>
@@ -523,6 +523,9 @@
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\uri_parser.c">
       <Filter>src\core\ext\filters\client_channel</Filter>
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\deadline\deadline_filter.c">
+      <Filter>src\core\ext\filters\deadline</Filter>
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver\dns\c_ares\dns_resolver_ares.c">
       <Filter>src\core\ext\filters\client_channel\resolver\dns\c_ares</Filter>
     </ClCompile>
@@ -616,6 +619,9 @@
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\max_age\max_age_filter.c">
       <Filter>src\core\ext\filters\max_age</Filter>
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\message_size\message_size_filter.c">
+      <Filter>src\core\ext\filters\message_size</Filter>
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\plugin_registry\grpc_unsecure_plugin_registry.c">
       <Filter>src\core\plugin_registry</Filter>
     </ClCompile>
@@ -722,18 +728,12 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\channel_stack_builder.h">
       <Filter>src\core\lib\channel</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\compress_filter.h">
-      <Filter>src\core\lib\channel</Filter>
-    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\connected_channel.h">
       <Filter>src\core\lib\channel</Filter>
     </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\context.h">
       <Filter>src\core\lib\channel</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\deadline_filter.h">
-      <Filter>src\core\lib\channel</Filter>
-    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\handshaker.h">
       <Filter>src\core\lib\channel</Filter>
     </ClInclude>
@@ -743,15 +743,6 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\handshaker_registry.h">
       <Filter>src\core\lib\channel</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\http_client_filter.h">
-      <Filter>src\core\lib\channel</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\http_server_filter.h">
-      <Filter>src\core\lib\channel</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\message_size_filter.h">
-      <Filter>src\core\lib\channel</Filter>
-    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\compression\algorithm_metadata.h">
       <Filter>src\core\lib\compression</Filter>
     </ClInclude>
@@ -1085,6 +1076,9 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\hpack_table.h">
       <Filter>src\core\ext\transport\chttp2\transport</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\http2_settings.h">
+      <Filter>src\core\ext\transport\chttp2\transport</Filter>
+    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\huffsyms.h">
       <Filter>src\core\ext\transport\chttp2\transport</Filter>
     </ClInclude>
@@ -1103,6 +1097,15 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\alpn\alpn.h">
       <Filter>src\core\ext\transport\chttp2\alpn</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\http\client\http_client_filter.h">
+      <Filter>src\core\ext\filters\http\client</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\http\message_compress\message_compress_filter.h">
+      <Filter>src\core\ext\filters\http\message_compress</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\http\server\http_server_filter.h">
+      <Filter>src\core\ext\filters\http\server</Filter>
+    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\server\chttp2_server.h">
       <Filter>src\core\ext\transport\chttp2\server</Filter>
     </ClInclude>
@@ -1163,6 +1166,9 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\uri_parser.h">
       <Filter>src\core\ext\filters\client_channel</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\deadline\deadline_filter.h">
+      <Filter>src\core\ext\filters\deadline</Filter>
+    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver\dns\c_ares\grpc_ares_ev_driver.h">
       <Filter>src\core\ext\filters\client_channel\resolver\dns\c_ares</Filter>
     </ClInclude>
@@ -1250,6 +1256,9 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\max_age\max_age_filter.h">
       <Filter>src\core\ext\filters\max_age</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\message_size\message_size_filter.h">
+      <Filter>src\core\ext\filters\message_size</Filter>
+    </ClInclude>
   </ItemGroup>
 
   <ItemGroup>
@@ -1325,12 +1334,30 @@
     <Filter Include="src\core\ext\filters\client_channel\resolver\sockaddr">
       <UniqueIdentifier>{99210f5e-b2a0-ecd1-024f-fc152db68a11}</UniqueIdentifier>
     </Filter>
+    <Filter Include="src\core\ext\filters\deadline">
+      <UniqueIdentifier>{ac374be1-7a3f-14a8-69fe-badac2d9f9ec}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\core\ext\filters\http">
+      <UniqueIdentifier>{33287f7d-739b-d30d-a9f3-b338103456b0}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\core\ext\filters\http\client">
+      <UniqueIdentifier>{95cd5972-7339-6f09-2332-e6769b3cba3f}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\core\ext\filters\http\message_compress">
+      <UniqueIdentifier>{cf8cb886-3020-e143-317e-730ff9bbddc3}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\core\ext\filters\http\server">
+      <UniqueIdentifier>{2c1e7897-6f69-f8b9-0b90-5c3fae59a48f}</UniqueIdentifier>
+    </Filter>
     <Filter Include="src\core\ext\filters\load_reporting">
       <UniqueIdentifier>{0aef07b4-39d2-f862-15ac-65b4bf00dabb}</UniqueIdentifier>
     </Filter>
     <Filter Include="src\core\ext\filters\max_age">
       <UniqueIdentifier>{d3bc80c1-5f2d-e842-42ac-43d8a6ada8de}</UniqueIdentifier>
     </Filter>
+    <Filter Include="src\core\ext\filters\message_size">
+      <UniqueIdentifier>{8cbe7444-caac-49dc-be89-d4c4d1c7966a}</UniqueIdentifier>
+    </Filter>
     <Filter Include="src\core\ext\transport">
       <UniqueIdentifier>{967c89fe-c97c-27e2-aac0-9ba5854cb5fa}</UniqueIdentifier>
     </Filter>
diff --git a/vsprojects/vcxproj/test/error_details_test/error_details_test.vcxproj b/vsprojects/vcxproj/test/error_details_test/error_details_test.vcxproj
new file mode 100644
index 0000000..e146d9c
--- /dev/null
+++ b/vsprojects/vcxproj/test/error_details_test/error_details_test.vcxproj
@@ -0,0 +1,203 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.props" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\1.0.204.1.props')" />
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|Win32">
+      <Configuration>Debug</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Debug|x64">
+      <Configuration>Debug</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|Win32">
+      <Configuration>Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|x64">
+      <Configuration>Release</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{2DE1AE9E-D53C-5854-9122-317E34F90C31}</ProjectGuid>
+    <IgnoreWarnIntDirInTempDetected>true</IgnoreWarnIntDirInTempDetected>
+    <IntDir>$(SolutionDir)IntDir\$(MSBuildProjectName)\</IntDir>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '10.0'" Label="Configuration">
+    <PlatformToolset>v100</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '11.0'" Label="Configuration">
+    <PlatformToolset>v110</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '12.0'" Label="Configuration">
+    <PlatformToolset>v120</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '14.0'" Label="Configuration">
+    <PlatformToolset>v140</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+    <Import Project="$(SolutionDir)\..\vsprojects\cpptest.props" />
+    <Import Project="$(SolutionDir)\..\vsprojects\global.props" />
+    <Import Project="$(SolutionDir)\..\vsprojects\openssl.props" />
+    <Import Project="$(SolutionDir)\..\vsprojects\protobuf.props" />
+    <Import Project="$(SolutionDir)\..\vsprojects\winsock.props" />
+    <Import Project="$(SolutionDir)\..\vsprojects\zlib.props" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup Condition="'$(Configuration)'=='Debug'">
+    <TargetName>error_details_test</TargetName>
+    <Linkage-grpc_dependencies_zlib>static</Linkage-grpc_dependencies_zlib>
+    <Configuration-grpc_dependencies_zlib>Debug</Configuration-grpc_dependencies_zlib>
+    <Linkage-grpc_dependencies_openssl>static</Linkage-grpc_dependencies_openssl>
+    <Configuration-grpc_dependencies_openssl>Debug</Configuration-grpc_dependencies_openssl>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)'=='Release'">
+    <TargetName>error_details_test</TargetName>
+    <Linkage-grpc_dependencies_zlib>static</Linkage-grpc_dependencies_zlib>
+    <Configuration-grpc_dependencies_zlib>Release</Configuration-grpc_dependencies_zlib>
+    <Linkage-grpc_dependencies_openssl>static</Linkage-grpc_dependencies_openssl>
+    <Configuration-grpc_dependencies_openssl>Release</Configuration-grpc_dependencies_openssl>
+  </PropertyGroup>
+    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+
+    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+
+    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>MaxSpeed</Optimization>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+  </ItemDefinitionGroup>
+
+    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>MaxSpeed</Optimization>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+  </ItemDefinitionGroup>
+
+  <ItemGroup>
+    <ClCompile Include="$(SolutionDir)\..\src\proto\grpc\testing\echo_messages.pb.cc">
+    </ClCompile>
+    <ClInclude Include="$(SolutionDir)\..\src\proto\grpc\testing\echo_messages.pb.h">
+    </ClInclude>
+    <ClCompile Include="$(SolutionDir)\..\src\proto\grpc\testing\echo_messages.grpc.pb.cc">
+    </ClCompile>
+    <ClInclude Include="$(SolutionDir)\..\src\proto\grpc\testing\echo_messages.grpc.pb.h">
+    </ClInclude>
+    <ClCompile Include="$(SolutionDir)\..\test\cpp\util\error_details_test.cc">
+    </ClCompile>
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc++_error_details\grpc++_error_details.vcxproj">
+      <Project>{9F58AD72-49E1-4D10-B826-9E190AB0AAC0}</Project>
+    </ProjectReference>
+    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc++\grpc++.vcxproj">
+      <Project>{C187A093-A0FE-489D-A40A-6E33DE0F9FEB}</Project>
+    </ProjectReference>
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="packages.config" />
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies.zlib.redist.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies\grpc.dependencies.zlib.targets')" />
+  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies.zlib.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies\grpc.dependencies.zlib.targets')" />
+  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies.openssl.redist.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies\grpc.dependencies.openssl.targets')" />
+  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies\grpc.dependencies.openssl.targets')" />
+  </ImportGroup>
+  <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
+    <PropertyGroup>
+      <ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them.  For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
+    </PropertyGroup>
+    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies.zlib.redist.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies.zlib.redist.targets')" />
+    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies.zlib.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies.zlib.targets')" />
+    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies.openssl.redist.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies.openssl.redist.targets')" />
+    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.props')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.props')" />
+    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.targets')" />
+  </Target>
+</Project>
+
diff --git a/vsprojects/vcxproj/test/error_details_test/error_details_test.vcxproj.filters b/vsprojects/vcxproj/test/error_details_test/error_details_test.vcxproj.filters
new file mode 100644
index 0000000..c83e0ae
--- /dev/null
+++ b/vsprojects/vcxproj/test/error_details_test/error_details_test.vcxproj.filters
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup>
+    <ClCompile Include="$(SolutionDir)\..\src\proto\grpc\testing\echo_messages.proto">
+      <Filter>src\proto\grpc\testing</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\test\cpp\util\error_details_test.cc">
+      <Filter>test\cpp\util</Filter>
+    </ClCompile>
+  </ItemGroup>
+
+  <ItemGroup>
+    <Filter Include="src">
+      <UniqueIdentifier>{35c957dd-436b-c57a-791d-2737bc179e41}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\proto">
+      <UniqueIdentifier>{c8721123-0390-f97d-5aad-0dd4979d5030}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\proto\grpc">
+      <UniqueIdentifier>{6dbad4a6-6b97-b25a-4f89-6edb20a1e7e0}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\proto\grpc\testing">
+      <UniqueIdentifier>{5f343032-7701-4924-a1d2-06f46d52d1b3}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="test">
+      <UniqueIdentifier>{688e4f7d-b9aa-342c-ffa7-2ee3ca51cd42}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="test\cpp">
+      <UniqueIdentifier>{a4e0ed0a-c1bb-60d6-003b-91c3989f6e6e}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="test\cpp\util">
+      <UniqueIdentifier>{60a99fd3-4904-d29f-b456-7f601092d055}</UniqueIdentifier>
+    </Filter>
+  </ItemGroup>
+</Project>
+
diff --git a/vsprojects/vcxproj/test/fake_resolver_test/fake_resolver_test.vcxproj b/vsprojects/vcxproj/test/fake_resolver_test/fake_resolver_test.vcxproj
new file mode 100644
index 0000000..8ea721d
--- /dev/null
+++ b/vsprojects/vcxproj/test/fake_resolver_test/fake_resolver_test.vcxproj
@@ -0,0 +1,199 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.props" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\1.0.204.1.props')" />
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|Win32">
+      <Configuration>Debug</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Debug|x64">
+      <Configuration>Debug</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|Win32">
+      <Configuration>Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|x64">
+      <Configuration>Release</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{2F59EB2E-CEF9-A291-9480-1F737C3E5E57}</ProjectGuid>
+    <IgnoreWarnIntDirInTempDetected>true</IgnoreWarnIntDirInTempDetected>
+    <IntDir>$(SolutionDir)IntDir\$(MSBuildProjectName)\</IntDir>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '10.0'" Label="Configuration">
+    <PlatformToolset>v100</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '11.0'" Label="Configuration">
+    <PlatformToolset>v110</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '12.0'" Label="Configuration">
+    <PlatformToolset>v120</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '14.0'" Label="Configuration">
+    <PlatformToolset>v140</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+    <Import Project="$(SolutionDir)\..\vsprojects\global.props" />
+    <Import Project="$(SolutionDir)\..\vsprojects\openssl.props" />
+    <Import Project="$(SolutionDir)\..\vsprojects\winsock.props" />
+    <Import Project="$(SolutionDir)\..\vsprojects\zlib.props" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup Condition="'$(Configuration)'=='Debug'">
+    <TargetName>fake_resolver_test</TargetName>
+    <Linkage-grpc_dependencies_zlib>static</Linkage-grpc_dependencies_zlib>
+    <Configuration-grpc_dependencies_zlib>Debug</Configuration-grpc_dependencies_zlib>
+    <Linkage-grpc_dependencies_openssl>static</Linkage-grpc_dependencies_openssl>
+    <Configuration-grpc_dependencies_openssl>Debug</Configuration-grpc_dependencies_openssl>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)'=='Release'">
+    <TargetName>fake_resolver_test</TargetName>
+    <Linkage-grpc_dependencies_zlib>static</Linkage-grpc_dependencies_zlib>
+    <Configuration-grpc_dependencies_zlib>Release</Configuration-grpc_dependencies_zlib>
+    <Linkage-grpc_dependencies_openssl>static</Linkage-grpc_dependencies_openssl>
+    <Configuration-grpc_dependencies_openssl>Release</Configuration-grpc_dependencies_openssl>
+  </PropertyGroup>
+    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+
+    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+
+    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>MaxSpeed</Optimization>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+  </ItemDefinitionGroup>
+
+    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>MaxSpeed</Optimization>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+  </ItemDefinitionGroup>
+
+  <ItemGroup>
+    <ClCompile Include="$(SolutionDir)\..\test\core\client_channel\resolvers\fake_resolver_test.c">
+    </ClCompile>
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc_test_util\grpc_test_util.vcxproj">
+      <Project>{17BCAFC0-5FDC-4C94-AEB9-95F3E220614B}</Project>
+    </ProjectReference>
+    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc\grpc.vcxproj">
+      <Project>{29D16885-7228-4C31-81ED-5F9187C7F2A9}</Project>
+    </ProjectReference>
+    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\gpr_test_util\gpr_test_util.vcxproj">
+      <Project>{EAB0A629-17A9-44DB-B5FF-E91A721FE037}</Project>
+    </ProjectReference>
+    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\gpr\gpr.vcxproj">
+      <Project>{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}</Project>
+    </ProjectReference>
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="packages.config" />
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies.zlib.redist.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies\grpc.dependencies.zlib.targets')" />
+  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies.zlib.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies\grpc.dependencies.zlib.targets')" />
+  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies.openssl.redist.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies\grpc.dependencies.openssl.targets')" />
+  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies\grpc.dependencies.openssl.targets')" />
+  </ImportGroup>
+  <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
+    <PropertyGroup>
+      <ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them.  For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
+    </PropertyGroup>
+    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies.zlib.redist.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies.zlib.redist.targets')" />
+    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies.zlib.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies.zlib.targets')" />
+    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies.openssl.redist.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies.openssl.redist.targets')" />
+    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.props')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.props')" />
+    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.targets')" />
+  </Target>
+</Project>
+
diff --git a/vsprojects/vcxproj/test/fake_resolver_test/fake_resolver_test.vcxproj.filters b/vsprojects/vcxproj/test/fake_resolver_test/fake_resolver_test.vcxproj.filters
new file mode 100644
index 0000000..353cae2
--- /dev/null
+++ b/vsprojects/vcxproj/test/fake_resolver_test/fake_resolver_test.vcxproj.filters
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup>
+    <ClCompile Include="$(SolutionDir)\..\test\core\client_channel\resolvers\fake_resolver_test.c">
+      <Filter>test\core\client_channel\resolvers</Filter>
+    </ClCompile>
+  </ItemGroup>
+
+  <ItemGroup>
+    <Filter Include="test">
+      <UniqueIdentifier>{05f58640-4b7c-c233-bf86-f119fe270ba1}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="test\core">
+      <UniqueIdentifier>{caeef88d-baf6-603c-83b0-84b1009be480}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="test\core\client_channel">
+      <UniqueIdentifier>{c5bba556-fd85-f7b4-99b7-8b1eeb4dfcb2}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="test\core\client_channel\resolvers">
+      <UniqueIdentifier>{eff74a86-6a4c-b68c-0330-6901d992c5c7}</UniqueIdentifier>
+    </Filter>
+  </ItemGroup>
+</Project>
+
diff --git a/vsprojects/vcxproj/test/minimal_stack_is_minimal_test/minimal_stack_is_minimal_test.vcxproj b/vsprojects/vcxproj/test/minimal_stack_is_minimal_test/minimal_stack_is_minimal_test.vcxproj
new file mode 100644
index 0000000..0473fa9
--- /dev/null
+++ b/vsprojects/vcxproj/test/minimal_stack_is_minimal_test/minimal_stack_is_minimal_test.vcxproj
@@ -0,0 +1,199 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.props" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\1.0.204.1.props')" />
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|Win32">
+      <Configuration>Debug</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Debug|x64">
+      <Configuration>Debug</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|Win32">
+      <Configuration>Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|x64">
+      <Configuration>Release</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{68A54124-DFA3-4FF3-081F-70356222C977}</ProjectGuid>
+    <IgnoreWarnIntDirInTempDetected>true</IgnoreWarnIntDirInTempDetected>
+    <IntDir>$(SolutionDir)IntDir\$(MSBuildProjectName)\</IntDir>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '10.0'" Label="Configuration">
+    <PlatformToolset>v100</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '11.0'" Label="Configuration">
+    <PlatformToolset>v110</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '12.0'" Label="Configuration">
+    <PlatformToolset>v120</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '14.0'" Label="Configuration">
+    <PlatformToolset>v140</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+    <Import Project="$(SolutionDir)\..\vsprojects\global.props" />
+    <Import Project="$(SolutionDir)\..\vsprojects\openssl.props" />
+    <Import Project="$(SolutionDir)\..\vsprojects\winsock.props" />
+    <Import Project="$(SolutionDir)\..\vsprojects\zlib.props" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup Condition="'$(Configuration)'=='Debug'">
+    <TargetName>minimal_stack_is_minimal_test</TargetName>
+    <Linkage-grpc_dependencies_zlib>static</Linkage-grpc_dependencies_zlib>
+    <Configuration-grpc_dependencies_zlib>Debug</Configuration-grpc_dependencies_zlib>
+    <Linkage-grpc_dependencies_openssl>static</Linkage-grpc_dependencies_openssl>
+    <Configuration-grpc_dependencies_openssl>Debug</Configuration-grpc_dependencies_openssl>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)'=='Release'">
+    <TargetName>minimal_stack_is_minimal_test</TargetName>
+    <Linkage-grpc_dependencies_zlib>static</Linkage-grpc_dependencies_zlib>
+    <Configuration-grpc_dependencies_zlib>Release</Configuration-grpc_dependencies_zlib>
+    <Linkage-grpc_dependencies_openssl>static</Linkage-grpc_dependencies_openssl>
+    <Configuration-grpc_dependencies_openssl>Release</Configuration-grpc_dependencies_openssl>
+  </PropertyGroup>
+    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+
+    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+
+    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>MaxSpeed</Optimization>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+  </ItemDefinitionGroup>
+
+    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>MaxSpeed</Optimization>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+  </ItemDefinitionGroup>
+
+  <ItemGroup>
+    <ClCompile Include="$(SolutionDir)\..\test\core\channel\minimal_stack_is_minimal_test.c">
+    </ClCompile>
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc_test_util\grpc_test_util.vcxproj">
+      <Project>{17BCAFC0-5FDC-4C94-AEB9-95F3E220614B}</Project>
+    </ProjectReference>
+    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc\grpc.vcxproj">
+      <Project>{29D16885-7228-4C31-81ED-5F9187C7F2A9}</Project>
+    </ProjectReference>
+    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\gpr_test_util\gpr_test_util.vcxproj">
+      <Project>{EAB0A629-17A9-44DB-B5FF-E91A721FE037}</Project>
+    </ProjectReference>
+    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\gpr\gpr.vcxproj">
+      <Project>{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}</Project>
+    </ProjectReference>
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="packages.config" />
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies.zlib.redist.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies\grpc.dependencies.zlib.targets')" />
+  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies.zlib.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies\grpc.dependencies.zlib.targets')" />
+  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies.openssl.redist.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies\grpc.dependencies.openssl.targets')" />
+  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies\grpc.dependencies.openssl.targets')" />
+  </ImportGroup>
+  <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
+    <PropertyGroup>
+      <ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them.  For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
+    </PropertyGroup>
+    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies.zlib.redist.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies.zlib.redist.targets')" />
+    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies.zlib.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies.zlib.targets')" />
+    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies.openssl.redist.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies.openssl.redist.targets')" />
+    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.props')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.props')" />
+    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.targets')" />
+  </Target>
+</Project>
+
diff --git a/vsprojects/vcxproj/test/minimal_stack_is_minimal_test/minimal_stack_is_minimal_test.vcxproj.filters b/vsprojects/vcxproj/test/minimal_stack_is_minimal_test/minimal_stack_is_minimal_test.vcxproj.filters
new file mode 100644
index 0000000..7eb2ba5
--- /dev/null
+++ b/vsprojects/vcxproj/test/minimal_stack_is_minimal_test/minimal_stack_is_minimal_test.vcxproj.filters
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup>
+    <ClCompile Include="$(SolutionDir)\..\test\core\channel\minimal_stack_is_minimal_test.c">
+      <Filter>test\core\channel</Filter>
+    </ClCompile>
+  </ItemGroup>
+
+  <ItemGroup>
+    <Filter Include="test">
+      <UniqueIdentifier>{52e0de0c-9f7d-1497-1339-b0ed30ed41f8}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="test\core">
+      <UniqueIdentifier>{2cd01454-1131-89cc-68a2-10365fa32bb0}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="test\core\channel">
+      <UniqueIdentifier>{f473b99d-5602-d2df-2d85-99648d00ba4f}</UniqueIdentifier>
+    </Filter>
+  </ItemGroup>
+</Project>
+