diff --git a/BUILD b/BUILD
index 14322881b6c2a743359bdba238a73e5f4b9b3ad1..a660bd5cf88df605e8dd5d690b42f5297a067d26 100644
--- a/BUILD
+++ b/BUILD
@@ -980,6 +980,7 @@ grpc_cc_library(
         "src/core/ext/transport/chttp2/transport/frame_ping.c",
         "src/core/ext/transport/chttp2/transport/frame_rst_stream.c",
         "src/core/ext/transport/chttp2/transport/frame_settings.c",
+        "src/core/ext/transport/chttp2/transport/http2_settings.c",
         "src/core/ext/transport/chttp2/transport/frame_window_update.c",
         "src/core/ext/transport/chttp2/transport/hpack_encoder.c",
         "src/core/ext/transport/chttp2/transport/hpack_parser.c",
@@ -1002,6 +1003,7 @@ grpc_cc_library(
         "src/core/ext/transport/chttp2/transport/frame_ping.h",
         "src/core/ext/transport/chttp2/transport/frame_rst_stream.h",
         "src/core/ext/transport/chttp2/transport/frame_settings.h",
+        "src/core/ext/transport/chttp2/transport/http2_settings.h",
         "src/core/ext/transport/chttp2/transport/frame_window_update.h",
         "src/core/ext/transport/chttp2/transport/hpack_encoder.h",
         "src/core/ext/transport/chttp2/transport/hpack_parser.h",
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 2b94f861f845f027ff34764fca5706e8883a8871..4f09fda1da88756cc974558293c30c4ed1b063f8 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1046,6 +1046,7 @@ add_library(grpc
   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
@@ -1372,6 +1373,7 @@ add_library(grpc_cronet
   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
@@ -1940,6 +1942,7 @@ add_library(grpc_unsecure
   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
@@ -2693,6 +2696,7 @@ add_library(grpc++_cronet
   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
diff --git a/Makefile b/Makefile
index 1fb0ad16dc3708f8bf1366cd351ece1285d386f2..02840b3c26ce6b769f670b8445f924ee449a2573 100644
--- a/Makefile
+++ b/Makefile
@@ -2953,6 +2953,7 @@ LIBGRPC_SRC = \
     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 \
@@ -3277,6 +3278,7 @@ LIBGRPC_CRONET_SRC = \
     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 \
@@ -3816,6 +3818,7 @@ LIBGRPC_UNSECURE_SRC = \
     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 \
@@ -4554,6 +4557,7 @@ LIBGRPC++_CRONET_SRC = \
     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 \
diff --git a/binding.gyp b/binding.gyp
index 7553de15d14738f9c4b55bd9a9746db5b3df3258..b33cef5a4ec168822cbacaa2ca3230255e80b7e7 100644
--- a/binding.gyp
+++ b/binding.gyp
@@ -789,6 +789,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',
diff --git a/build.yaml b/build.yaml
index 2dca6526a67996eaa4dce1e1582c7d3279277de4..414950cd6fc4b5fd87820acd1724eaf0a0570a70 100644
--- a/build.yaml
+++ b/build.yaml
@@ -666,6 +666,7 @@ filegroups:
   - 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 +686,7 @@ filegroups:
   - 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
diff --git a/config.m4 b/config.m4
index 9470e43aaa0ffa42644a6b2a6e70d474df17a400..c414fc3620fb7cd077b1108e4b2df0dabd9e302d 100644
--- a/config.m4
+++ b/config.m4
@@ -222,6 +222,7 @@ if test "$PHP_GRPC" != "no"; then
     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 \
diff --git a/gRPC-Core.podspec b/gRPC-Core.podspec
index 2e260189fbdfec6d80ba12cb5b14ee6e1d5f4a71..aed17ae9c3dcf2a6c8976ec1dff7a5c537b7d13b 100644
--- a/gRPC-Core.podspec
+++ b/gRPC-Core.podspec
@@ -379,6 +379,7 @@ Pod::Spec.new do |s|
                       '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',
@@ -598,6 +599,7 @@ Pod::Spec.new do |s|
                       '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',
@@ -831,6 +833,7 @@ Pod::Spec.new do |s|
                               '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',
diff --git a/grpc.gemspec b/grpc.gemspec
index cd4f07886563874b2bf565031f05246632ae7950..4912872933bd35748e7aaf31330348860728b062 100755
--- a/grpc.gemspec
+++ b/grpc.gemspec
@@ -295,6 +295,7 @@ Gem::Specification.new do |s|
   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 )
@@ -514,6 +515,7 @@ Gem::Specification.new do |s|
   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 )
diff --git a/include/grpc/impl/codegen/grpc_types.h b/include/grpc/impl/codegen/grpc_types.h
index fdedf0a84f3cb61c74a6a2ae344a01af79c0497f..8fa76fc032804752a4e835c9a5d1f01c8b9080c6 100644
--- a/include/grpc/impl/codegen/grpc_types.h
+++ b/include/grpc/impl/codegen/grpc_types.h
@@ -217,6 +217,9 @@ typedef struct {
 /** 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"
diff --git a/package.xml b/package.xml
index c6b86a66a2bc2d7b6b19ca6edaa328526db3277c..57e50725e8eb71b92c7d1d9a221ea88d75d6502a 100644
--- a/package.xml
+++ b/package.xml
@@ -304,6 +304,7 @@
     <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" />
@@ -523,6 +524,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" />
diff --git a/src/core/ext/transport/chttp2/transport/chttp2_transport.c b/src/core/ext/transport/chttp2/transport/chttp2_transport.c
index 097b3794e5d04e74b615b7cf41b6b37ac0f549d7..29ed4bf90e5b037904516108ee87e19fed279bd2 100644
--- a/src/core/ext/transport/chttp2/transport/chttp2_transport.c
+++ b/src/core/ext/transport/chttp2/transport/chttp2_transport.c
@@ -365,6 +365,8 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
                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,
@@ -495,26 +497,31 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
           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)) {
diff --git a/src/core/ext/transport/chttp2/transport/frame_settings.c b/src/core/ext/transport/chttp2/transport/frame_settings.c
index 16881c0707a4624823efcb25be14a19a3a2bee3b..4f2b82783268fa7b9cdf975eac4d34a7302fa0c0 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 @@ grpc_slice grpc_chttp2_settings_create(uint32_t *old, const uint32_t *new,
 
   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 @@ grpc_error *grpc_chttp2_settings_parser_parse(grpc_exec_ctx *exec_ctx, void *p,
   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 @@ grpc_error *grpc_chttp2_settings_parser_parse(grpc_exec_ctx *exec_ctx, void *p,
         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 @@ grpc_error *grpc_chttp2_settings_parser_parse(grpc_exec_ctx *exec_ctx, void *p,
                 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 44137798c064b0e3a3f5c980eb72c9bdb2498266..2a85d0dba7688296ee90629ca6fc52b4b2ebd56c 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 @@ typedef enum {
   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 @@ typedef struct {
   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 84586cd99887416ca88c53dd383310a302c87a53..b1bc677a7a48bd6922b63faba966fd3521919b61 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 @@ typedef struct {
   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 @@ static void emit_indexed(grpc_chttp2_hpack_compressor *c, uint32_t elem_index,
                            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_hpack_compressor_set_max_table_size(
 
 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 @@ void grpc_chttp2_encode_header(grpc_exec_ctx *exec_ctx,
     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 83ba5b1b3e0107b76a57e52cecb0c46868105cb8..6ce3209604601aade6836be8d699b9b49e47e464 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_table_size(
 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 5099d736bf4d06e88ba67d426768fb0e56fb86d4..1846a85fc65f37bc5de2fe31b0cc9f73c066e31f 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 @@ static grpc_error *append_string(grpc_exec_ctx *exec_ctx,
     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 @@ static grpc_error *finish_str(grpc_exec_ctx *exec_ctx,
   switch ((binary_state)p->binary) {
     case NOT_BINARY:
       break;
+    case BINARY_BEGIN:
+      break;
     case B64_BYTE0:
       break;
     case B64_BYTE1:
@@ -1571,7 +1579,7 @@ static grpc_error *parse_value_string(grpc_exec_ctx *exec_ctx,
                                       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 0000000000000000000000000000000000000000..d4905107efe9e71a6ae61b83fda0c8707d3dc662
--- /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 0000000000000000000000000000000000000000..9781cdc9893ac794fdb7f1454101f9e9013b1589
--- /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/writing.c b/src/core/ext/transport/chttp2/transport/writing.c
index be41b3d1865b2976a6dd11fa2ce391bd9e3ea960..ae9df175ffd5c6e748c99c6fde98634c85ca3473 100644
--- a/src/core/ext/transport/chttp2/transport/writing.c
+++ b/src/core/ext/transport/chttp2/transport/writing.c
@@ -219,10 +219,18 @@ bool grpc_chttp2_begin_write(grpc_exec_ctx *exec_ctx,
 
     /* 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_ACKED_SETTINGS]
+                  [GRPC_CHTTP2_SETTINGS_GRPC_ALLOW_TRUE_BINARY_METADATA] != 0,
+          .max_frame_size = t->settings[GRPC_ACKED_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;
@@ -315,11 +323,21 @@ bool grpc_chttp2_begin_write(grpc_exec_ctx *exec_ctx,
           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_ACKED_SETTINGS]
+                      [GRPC_CHTTP2_SETTINGS_GRPC_ALLOW_TRUE_BINARY_METADATA] !=
+                  0,
+              .max_frame_size =
+                  t->settings[GRPC_ACKED_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/python/grpcio/grpc_core_dependencies.py b/src/python/grpcio/grpc_core_dependencies.py
index 0d0a5fb0887d98d9fc304bd84b097e0fd009233f..7f810bd0b4759f85edaaec26bb36d85dbd54b2c9 100644
--- a/src/python/grpcio/grpc_core_dependencies.py
+++ b/src/python/grpcio/grpc_core_dependencies.py
@@ -216,6 +216,7 @@ CORE_SOURCE_FILES = [
   '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',
diff --git a/test/core/transport/chttp2/hpack_encoder_test.c b/test/core/transport/chttp2/hpack_encoder_test.c
index d572d79a7ffec08f206ec7360221b08b77660ab7..f4ccc71b395b179cb81106fe485a0c38299fe407 100644
--- a/test/core/transport/chttp2/hpack_encoder_test.c
+++ b/test/core/transport/chttp2/hpack_encoder_test.c
@@ -60,9 +60,9 @@ size_t cap_to_delete = 0;
 
 /* 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 @@ static void verify(grpc_exec_ctx *exec_ctx, size_t window_available, int eof,
 
   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 verify(grpc_exec_ctx *exec_ctx, size_t window_available, int eof,
 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 @@ static void test_decode_table_overflow(grpc_exec_ctx *exec_ctx) {
     }
 
     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 @@ static void verify_table_size_change_match_elem_size(grpc_exec_ctx *exec_ctx,
 
   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/microbenchmarks/bm_chttp2_hpack.cc b/test/cpp/microbenchmarks/bm_chttp2_hpack.cc
index 55d2d2f58d010f6933a90a1aff6f8a2f513bee14..581440682aa0887d4bf386a5b9752855d1c0e112 100644
--- a/test/cpp/microbenchmarks/bm_chttp2_hpack.cc
+++ b/test/cpp/microbenchmarks/bm_chttp2_hpack.cc
@@ -90,10 +90,15 @@ static void BM_HpackEncoderEncodeHeader(benchmark::State &state) {
   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 @@ namespace hpack_encoder_fixtures {
 
 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 EmptyBatch {
 
 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 SingleStaticElem {
 
 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 @@ class SingleInternedElem {
   }
 };
 
-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 SingleInternedBinaryElem {
 
 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 SingleInternedKeyElem {
 
 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 @@ class SingleNonInternedElem {
   }
 };
 
-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 SingleNonInternedBinaryElem {
 
 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 RepresentativeClientInitialMetadata {
 
 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 RepresentativeServerInitialMetadata {
 
 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 @@ BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader, SingleInternedKeyElem)
     ->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, false>)
+    ->Args({0, 16384});
+BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader,
+                   SingleInternedBinaryElem<10, false>)
+    ->Args({0, 16384});
+BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader,
+                   SingleInternedBinaryElem<31, false>)
+    ->Args({0, 16384});
+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>)
+BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader,
+                   SingleInternedBinaryElem<3, true>)
     ->Args({0, 16384});
-BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader, SingleInternedBinaryElem<10>)
+BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader,
+                   SingleInternedBinaryElem<10, true>)
     ->Args({0, 16384});
-BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader, SingleInternedBinaryElem<31>)
+BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader,
+                   SingleInternedBinaryElem<31, true>)
     ->Args({0, 16384});
-BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader, SingleInternedBinaryElem<100>)
+BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader,
+                   SingleInternedBinaryElem<100, true>)
     ->Args({0, 16384});
 BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader, SingleNonInternedElem)
     ->Args({0, 16384});
-BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader, SingleNonInternedBinaryElem<1>)
+BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader,
+                   SingleNonInternedBinaryElem<1, false>)
+    ->Args({0, 16384});
+BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader,
+                   SingleNonInternedBinaryElem<3, false>)
     ->Args({0, 16384});
-BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader, SingleNonInternedBinaryElem<3>)
+BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader,
+                   SingleNonInternedBinaryElem<10, false>)
     ->Args({0, 16384});
-BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader, SingleNonInternedBinaryElem<10>)
+BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader,
+                   SingleNonInternedBinaryElem<31, false>)
     ->Args({0, 16384});
-BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader, SingleNonInternedBinaryElem<31>)
+BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader,
+                   SingleNonInternedBinaryElem<100, false>)
     ->Args({0, 16384});
 BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader,
-                   SingleNonInternedBinaryElem<100>)
+                   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 NonIndexedElem {
   }
 };
 
-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 NonIndexedBinaryElem1 {
   }
 };
 
-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 NonIndexedBinaryElem3 {
   }
 };
 
-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 NonIndexedBinaryElem10 {
   }
 };
 
-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 NonIndexedBinaryElem31 {
   }
 };
 
-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, IndexedSingleInternedElem);
 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 @@ BENCHMARK_TEMPLATE(BM_HpackParserParseHeader,
 
 }  // 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/tools/codegen/core/gen_settings_ids.py b/tools/codegen/core/gen_settings_ids.py
new file mode 100755
index 0000000000000000000000000000000000000000..a9861383371fb16e4588ffe0f023f9730e10b7e5
--- /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/doxygen/Doxyfile.core.internal b/tools/doxygen/Doxyfile.core.internal
index ee1fd1b242f4dd3606712fcb85e7cf881aa0c8c1..915648640f6b77eb825ce1f816463a8590ec3bca 100644
--- a/tools/doxygen/Doxyfile.core.internal
+++ b/tools/doxygen/Doxyfile.core.internal
@@ -1005,6 +1005,8 @@ src/core/ext/transport/chttp2/transport/hpack_parser.c \
 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 \
diff --git a/tools/run_tests/generated/sources_and_headers.json b/tools/run_tests/generated/sources_and_headers.json
index 5ee5d0be90a552ace25aecd6ad6f17c909d92bae..8c229af020e8c6ede9257195a091ad0e4614cc60 100644
--- a/tools/run_tests/generated/sources_and_headers.json
+++ b/tools/run_tests/generated/sources_and_headers.json
@@ -8348,6 +8348,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 +8385,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", 
diff --git a/vsprojects/vcxproj/grpc/grpc.vcxproj b/vsprojects/vcxproj/grpc/grpc.vcxproj
index dd6fdd861e41884afe1877aa0089a0eb3f4b15e2..a956a4f2be3fc3bfc584d8f0119569134e364138 100644
--- a/vsprojects/vcxproj/grpc/grpc.vcxproj
+++ b/vsprojects/vcxproj/grpc/grpc.vcxproj
@@ -424,6 +424,7 @@
     <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" />
@@ -785,6 +786,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">
diff --git a/vsprojects/vcxproj/grpc/grpc.vcxproj.filters b/vsprojects/vcxproj/grpc/grpc.vcxproj.filters
index 51c9b7201dc4a989aee78a26239cebeefc053b7e..2ccac30d7adf53161a119f27477819c1437b721a 100644
--- a/vsprojects/vcxproj/grpc/grpc.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc/grpc.vcxproj.filters
@@ -421,6 +421,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>
@@ -1172,6 +1175,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>
diff --git a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj
index 8614b1158981a4dd5c8d96d09894647e1cbcb183..e3e62da213ee9c54fe97551fb8c227bd9ff50a10 100644
--- a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj
+++ b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj
@@ -414,6 +414,7 @@
     <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" />
@@ -755,6 +756,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">
diff --git a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters
index e7aa9fb8d6f8dfef789f603507f31567e0938b7c..e79d212f9c42db19c0efaa412f3ac937e9c51059 100644
--- a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters
@@ -427,6 +427,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>
@@ -1085,6 +1088,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>