diff --git a/BUILD b/BUILD
index a134d28a562c5ed08992d1dbebca8b7daaa7c69e..5053860baf45bdebd30d29bb21392816806bb6a6 100644
--- a/BUILD
+++ b/BUILD
@@ -672,11 +672,14 @@ grpc_cc_library(
         "src/core/ext/client_channel/connector.c",
         "src/core/ext/client_channel/default_initial_connect_string.c",
         "src/core/ext/client_channel/http_connect_handshaker.c",
+        "src/core/ext/client_channel/http_proxy.c",
         "src/core/ext/client_channel/initial_connect_string.c",
         "src/core/ext/client_channel/lb_policy.c",
         "src/core/ext/client_channel/lb_policy_factory.c",
         "src/core/ext/client_channel/lb_policy_registry.c",
         "src/core/ext/client_channel/parse_address.c",
+        "src/core/ext/client_channel/proxy_mapper.c",
+        "src/core/ext/client_channel/proxy_mapper_registry.c",
         "src/core/ext/client_channel/resolver.c",
         "src/core/ext/client_channel/resolver_factory.c",
         "src/core/ext/client_channel/resolver_registry.c",
@@ -689,11 +692,14 @@ grpc_cc_library(
         "src/core/ext/client_channel/client_channel_factory.h",
         "src/core/ext/client_channel/connector.h",
         "src/core/ext/client_channel/http_connect_handshaker.h",
+        "src/core/ext/client_channel/http_proxy.h",
         "src/core/ext/client_channel/initial_connect_string.h",
         "src/core/ext/client_channel/lb_policy.h",
         "src/core/ext/client_channel/lb_policy_factory.h",
         "src/core/ext/client_channel/lb_policy_registry.h",
         "src/core/ext/client_channel/parse_address.h",
+        "src/core/ext/client_channel/proxy_mapper.h",
+        "src/core/ext/client_channel/proxy_mapper_registry.h",
         "src/core/ext/client_channel/resolver.h",
         "src/core/ext/client_channel/resolver_factory.h",
         "src/core/ext/client_channel/resolver_registry.h",
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 23c5f7bdd79289391ee9cc8b871f220457cf9177..f2328e5c624e3deeb58df74c4b0a013d5b3ab0a1 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -573,11 +573,14 @@ add_library(grpc
   src/core/ext/client_channel/connector.c
   src/core/ext/client_channel/default_initial_connect_string.c
   src/core/ext/client_channel/http_connect_handshaker.c
+  src/core/ext/client_channel/http_proxy.c
   src/core/ext/client_channel/initial_connect_string.c
   src/core/ext/client_channel/lb_policy.c
   src/core/ext/client_channel/lb_policy_factory.c
   src/core/ext/client_channel/lb_policy_registry.c
   src/core/ext/client_channel/parse_address.c
+  src/core/ext/client_channel/proxy_mapper.c
+  src/core/ext/client_channel/proxy_mapper_registry.c
   src/core/ext/client_channel/resolver.c
   src/core/ext/client_channel/resolver_factory.c
   src/core/ext/client_channel/resolver_registry.c
@@ -836,11 +839,14 @@ add_library(grpc_cronet
   src/core/ext/client_channel/connector.c
   src/core/ext/client_channel/default_initial_connect_string.c
   src/core/ext/client_channel/http_connect_handshaker.c
+  src/core/ext/client_channel/http_proxy.c
   src/core/ext/client_channel/initial_connect_string.c
   src/core/ext/client_channel/lb_policy.c
   src/core/ext/client_channel/lb_policy_factory.c
   src/core/ext/client_channel/lb_policy_registry.c
   src/core/ext/client_channel/parse_address.c
+  src/core/ext/client_channel/proxy_mapper.c
+  src/core/ext/client_channel/proxy_mapper_registry.c
   src/core/ext/client_channel/resolver.c
   src/core/ext/client_channel/resolver_factory.c
   src/core/ext/client_channel/resolver_registry.c
@@ -1335,11 +1341,14 @@ add_library(grpc_unsecure
   src/core/ext/client_channel/connector.c
   src/core/ext/client_channel/default_initial_connect_string.c
   src/core/ext/client_channel/http_connect_handshaker.c
+  src/core/ext/client_channel/http_proxy.c
   src/core/ext/client_channel/initial_connect_string.c
   src/core/ext/client_channel/lb_policy.c
   src/core/ext/client_channel/lb_policy_factory.c
   src/core/ext/client_channel/lb_policy_registry.c
   src/core/ext/client_channel/parse_address.c
+  src/core/ext/client_channel/proxy_mapper.c
+  src/core/ext/client_channel/proxy_mapper_registry.c
   src/core/ext/client_channel/resolver.c
   src/core/ext/client_channel/resolver_factory.c
   src/core/ext/client_channel/resolver_registry.c
@@ -1841,11 +1850,14 @@ add_library(grpc++_cronet
   src/core/ext/client_channel/connector.c
   src/core/ext/client_channel/default_initial_connect_string.c
   src/core/ext/client_channel/http_connect_handshaker.c
+  src/core/ext/client_channel/http_proxy.c
   src/core/ext/client_channel/initial_connect_string.c
   src/core/ext/client_channel/lb_policy.c
   src/core/ext/client_channel/lb_policy_factory.c
   src/core/ext/client_channel/lb_policy_registry.c
   src/core/ext/client_channel/parse_address.c
+  src/core/ext/client_channel/proxy_mapper.c
+  src/core/ext/client_channel/proxy_mapper_registry.c
   src/core/ext/client_channel/resolver.c
   src/core/ext/client_channel/resolver_factory.c
   src/core/ext/client_channel/resolver_registry.c
@@ -8508,12 +8520,12 @@ target_include_directories(grpclb_test
 )
 
 target_link_libraries(grpclb_test
-  gpr
-  gpr_test_util
-  grpc
-  grpc++
   grpc++_test_util
   grpc_test_util
+  grpc++
+  grpc
+  gpr_test_util
+  gpr
   ${_gRPC_GFLAGS_LIBRARIES}
 )
 
diff --git a/Makefile b/Makefile
index f903d273f0a4fb56d565c560678212a36cd61cef..f04be5a9e879c2e643677dbc3862e813acd1eef1 100644
--- a/Makefile
+++ b/Makefile
@@ -2803,11 +2803,14 @@ LIBGRPC_SRC = \
     src/core/ext/client_channel/connector.c \
     src/core/ext/client_channel/default_initial_connect_string.c \
     src/core/ext/client_channel/http_connect_handshaker.c \
+    src/core/ext/client_channel/http_proxy.c \
     src/core/ext/client_channel/initial_connect_string.c \
     src/core/ext/client_channel/lb_policy.c \
     src/core/ext/client_channel/lb_policy_factory.c \
     src/core/ext/client_channel/lb_policy_registry.c \
     src/core/ext/client_channel/parse_address.c \
+    src/core/ext/client_channel/proxy_mapper.c \
+    src/core/ext/client_channel/proxy_mapper_registry.c \
     src/core/ext/client_channel/resolver.c \
     src/core/ext/client_channel/resolver_factory.c \
     src/core/ext/client_channel/resolver_registry.c \
@@ -3082,11 +3085,14 @@ LIBGRPC_CRONET_SRC = \
     src/core/ext/client_channel/connector.c \
     src/core/ext/client_channel/default_initial_connect_string.c \
     src/core/ext/client_channel/http_connect_handshaker.c \
+    src/core/ext/client_channel/http_proxy.c \
     src/core/ext/client_channel/initial_connect_string.c \
     src/core/ext/client_channel/lb_policy.c \
     src/core/ext/client_channel/lb_policy_factory.c \
     src/core/ext/client_channel/lb_policy_registry.c \
     src/core/ext/client_channel/parse_address.c \
+    src/core/ext/client_channel/proxy_mapper.c \
+    src/core/ext/client_channel/proxy_mapper_registry.c \
     src/core/ext/client_channel/resolver.c \
     src/core/ext/client_channel/resolver_factory.c \
     src/core/ext/client_channel/resolver_registry.c \
@@ -3603,11 +3609,14 @@ LIBGRPC_UNSECURE_SRC = \
     src/core/ext/client_channel/connector.c \
     src/core/ext/client_channel/default_initial_connect_string.c \
     src/core/ext/client_channel/http_connect_handshaker.c \
+    src/core/ext/client_channel/http_proxy.c \
     src/core/ext/client_channel/initial_connect_string.c \
     src/core/ext/client_channel/lb_policy.c \
     src/core/ext/client_channel/lb_policy_factory.c \
     src/core/ext/client_channel/lb_policy_registry.c \
     src/core/ext/client_channel/parse_address.c \
+    src/core/ext/client_channel/proxy_mapper.c \
+    src/core/ext/client_channel/proxy_mapper_registry.c \
     src/core/ext/client_channel/resolver.c \
     src/core/ext/client_channel/resolver_factory.c \
     src/core/ext/client_channel/resolver_registry.c \
@@ -4164,11 +4173,14 @@ LIBGRPC++_CRONET_SRC = \
     src/core/ext/client_channel/connector.c \
     src/core/ext/client_channel/default_initial_connect_string.c \
     src/core/ext/client_channel/http_connect_handshaker.c \
+    src/core/ext/client_channel/http_proxy.c \
     src/core/ext/client_channel/initial_connect_string.c \
     src/core/ext/client_channel/lb_policy.c \
     src/core/ext/client_channel/lb_policy_factory.c \
     src/core/ext/client_channel/lb_policy_registry.c \
     src/core/ext/client_channel/parse_address.c \
+    src/core/ext/client_channel/proxy_mapper.c \
+    src/core/ext/client_channel/proxy_mapper_registry.c \
     src/core/ext/client_channel/resolver.c \
     src/core/ext/client_channel/resolver_factory.c \
     src/core/ext/client_channel/resolver_registry.c \
@@ -13394,18 +13406,18 @@ $(BINDIR)/$(CONFIG)/grpclb_test: protobuf_dep_error
 
 else
 
-$(BINDIR)/$(CONFIG)/grpclb_test: $(PROTOBUF_DEP) $(GRPCLB_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a
+$(BINDIR)/$(CONFIG)/grpclb_test: $(PROTOBUF_DEP) $(GRPCLB_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(LDXX) $(LDFLAGS) $(GRPCLB_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/grpclb_test
+	$(Q) $(LDXX) $(LDFLAGS) $(GRPCLB_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/grpclb_test
 
 endif
 
 endif
 
-$(OBJDIR)/$(CONFIG)/src/proto/grpc/lb/v1/load_balancer.o:  $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a
+$(OBJDIR)/$(CONFIG)/src/proto/grpc/lb/v1/load_balancer.o:  $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
 
-$(OBJDIR)/$(CONFIG)/test/cpp/grpclb/grpclb_test.o:  $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a
+$(OBJDIR)/$(CONFIG)/test/cpp/grpclb/grpclb_test.o:  $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
 
 deps_grpclb_test: $(GRPCLB_TEST_OBJS:.o=.dep)
 
diff --git a/binding.gyp b/binding.gyp
index 54958dbf4fa47d077c73830f099a43ee211ebd4a..fe9c425bffb5ca1b95aabbe07eb21f1d4b4f5fc9 100644
--- a/binding.gyp
+++ b/binding.gyp
@@ -777,11 +777,14 @@
         'src/core/ext/client_channel/connector.c',
         'src/core/ext/client_channel/default_initial_connect_string.c',
         'src/core/ext/client_channel/http_connect_handshaker.c',
+        'src/core/ext/client_channel/http_proxy.c',
         'src/core/ext/client_channel/initial_connect_string.c',
         'src/core/ext/client_channel/lb_policy.c',
         'src/core/ext/client_channel/lb_policy_factory.c',
         'src/core/ext/client_channel/lb_policy_registry.c',
         'src/core/ext/client_channel/parse_address.c',
+        'src/core/ext/client_channel/proxy_mapper.c',
+        'src/core/ext/client_channel/proxy_mapper_registry.c',
         'src/core/ext/client_channel/resolver.c',
         'src/core/ext/client_channel/resolver_factory.c',
         'src/core/ext/client_channel/resolver_registry.c',
diff --git a/build.yaml b/build.yaml
index 7b3e64e9bb44f4abeb1162328a2149882a51baf3..5b9dcbbd26508045fde6e56c7f8e1c41af9d1557 100644
--- a/build.yaml
+++ b/build.yaml
@@ -397,11 +397,14 @@ filegroups:
   - src/core/ext/client_channel/client_channel_factory.h
   - src/core/ext/client_channel/connector.h
   - src/core/ext/client_channel/http_connect_handshaker.h
+  - src/core/ext/client_channel/http_proxy.h
   - src/core/ext/client_channel/initial_connect_string.h
   - src/core/ext/client_channel/lb_policy.h
   - src/core/ext/client_channel/lb_policy_factory.h
   - src/core/ext/client_channel/lb_policy_registry.h
   - src/core/ext/client_channel/parse_address.h
+  - src/core/ext/client_channel/proxy_mapper.h
+  - src/core/ext/client_channel/proxy_mapper_registry.h
   - src/core/ext/client_channel/resolver.h
   - src/core/ext/client_channel/resolver_factory.h
   - src/core/ext/client_channel/resolver_registry.h
@@ -416,11 +419,14 @@ filegroups:
   - src/core/ext/client_channel/connector.c
   - src/core/ext/client_channel/default_initial_connect_string.c
   - src/core/ext/client_channel/http_connect_handshaker.c
+  - src/core/ext/client_channel/http_proxy.c
   - src/core/ext/client_channel/initial_connect_string.c
   - src/core/ext/client_channel/lb_policy.c
   - src/core/ext/client_channel/lb_policy_factory.c
   - src/core/ext/client_channel/lb_policy_registry.c
   - src/core/ext/client_channel/parse_address.c
+  - src/core/ext/client_channel/proxy_mapper.c
+  - src/core/ext/client_channel/proxy_mapper_registry.c
   - src/core/ext/client_channel/resolver.c
   - src/core/ext/client_channel/resolver_factory.c
   - src/core/ext/client_channel/resolver_registry.c
@@ -3244,12 +3250,12 @@ targets:
   - src/proto/grpc/lb/v1/load_balancer.proto
   - test/cpp/grpclb/grpclb_test.cc
   deps:
-  - gpr
-  - gpr_test_util
-  - grpc
-  - grpc++
   - grpc++_test_util
   - grpc_test_util
+  - grpc++
+  - grpc
+  - gpr_test_util
+  - gpr
 - name: http2_client
   build: test
   run: false
diff --git a/config.m4 b/config.m4
index e9f02523cdfa8671b98609120c55edb7bdbd4e81..2a3ba5502d727e04a2be4d51e2484f229aa7c379 100644
--- a/config.m4
+++ b/config.m4
@@ -256,11 +256,14 @@ if test "$PHP_GRPC" != "no"; then
     src/core/ext/client_channel/connector.c \
     src/core/ext/client_channel/default_initial_connect_string.c \
     src/core/ext/client_channel/http_connect_handshaker.c \
+    src/core/ext/client_channel/http_proxy.c \
     src/core/ext/client_channel/initial_connect_string.c \
     src/core/ext/client_channel/lb_policy.c \
     src/core/ext/client_channel/lb_policy_factory.c \
     src/core/ext/client_channel/lb_policy_registry.c \
     src/core/ext/client_channel/parse_address.c \
+    src/core/ext/client_channel/proxy_mapper.c \
+    src/core/ext/client_channel/proxy_mapper_registry.c \
     src/core/ext/client_channel/resolver.c \
     src/core/ext/client_channel/resolver_factory.c \
     src/core/ext/client_channel/resolver_registry.c \
diff --git a/gRPC-Core.podspec b/gRPC-Core.podspec
index f15fcc778232850db39ffb9123063e6d8c5b85dd..39e0c340ea3f5463b72a28930f4104b2c9dd53bb 100644
--- a/gRPC-Core.podspec
+++ b/gRPC-Core.podspec
@@ -403,11 +403,14 @@ Pod::Spec.new do |s|
                       'src/core/ext/client_channel/client_channel_factory.h',
                       'src/core/ext/client_channel/connector.h',
                       'src/core/ext/client_channel/http_connect_handshaker.h',
+                      'src/core/ext/client_channel/http_proxy.h',
                       'src/core/ext/client_channel/initial_connect_string.h',
                       'src/core/ext/client_channel/lb_policy.h',
                       'src/core/ext/client_channel/lb_policy_factory.h',
                       'src/core/ext/client_channel/lb_policy_registry.h',
                       'src/core/ext/client_channel/parse_address.h',
+                      'src/core/ext/client_channel/proxy_mapper.h',
+                      'src/core/ext/client_channel/proxy_mapper_registry.h',
                       'src/core/ext/client_channel/resolver.h',
                       'src/core/ext/client_channel/resolver_factory.h',
                       'src/core/ext/client_channel/resolver_registry.h',
@@ -611,11 +614,14 @@ Pod::Spec.new do |s|
                       'src/core/ext/client_channel/connector.c',
                       'src/core/ext/client_channel/default_initial_connect_string.c',
                       'src/core/ext/client_channel/http_connect_handshaker.c',
+                      'src/core/ext/client_channel/http_proxy.c',
                       'src/core/ext/client_channel/initial_connect_string.c',
                       'src/core/ext/client_channel/lb_policy.c',
                       'src/core/ext/client_channel/lb_policy_factory.c',
                       'src/core/ext/client_channel/lb_policy_registry.c',
                       'src/core/ext/client_channel/parse_address.c',
+                      'src/core/ext/client_channel/proxy_mapper.c',
+                      'src/core/ext/client_channel/proxy_mapper_registry.c',
                       'src/core/ext/client_channel/resolver.c',
                       'src/core/ext/client_channel/resolver_factory.c',
                       'src/core/ext/client_channel/resolver_registry.c',
@@ -820,11 +826,14 @@ Pod::Spec.new do |s|
                               'src/core/ext/client_channel/client_channel_factory.h',
                               'src/core/ext/client_channel/connector.h',
                               'src/core/ext/client_channel/http_connect_handshaker.h',
+                              'src/core/ext/client_channel/http_proxy.h',
                               'src/core/ext/client_channel/initial_connect_string.h',
                               'src/core/ext/client_channel/lb_policy.h',
                               'src/core/ext/client_channel/lb_policy_factory.h',
                               'src/core/ext/client_channel/lb_policy_registry.h',
                               'src/core/ext/client_channel/parse_address.h',
+                              'src/core/ext/client_channel/proxy_mapper.h',
+                              'src/core/ext/client_channel/proxy_mapper_registry.h',
                               'src/core/ext/client_channel/resolver.h',
                               'src/core/ext/client_channel/resolver_factory.h',
                               'src/core/ext/client_channel/resolver_registry.h',
diff --git a/grpc.gemspec b/grpc.gemspec
index a85be4e7850389a5fb512aa3a573d53b0a2ec66f..874af6be41c4a7f677c4d4448828a395b98df35a 100755
--- a/grpc.gemspec
+++ b/grpc.gemspec
@@ -320,11 +320,14 @@ Gem::Specification.new do |s|
   s.files += %w( src/core/ext/client_channel/client_channel_factory.h )
   s.files += %w( src/core/ext/client_channel/connector.h )
   s.files += %w( src/core/ext/client_channel/http_connect_handshaker.h )
+  s.files += %w( src/core/ext/client_channel/http_proxy.h )
   s.files += %w( src/core/ext/client_channel/initial_connect_string.h )
   s.files += %w( src/core/ext/client_channel/lb_policy.h )
   s.files += %w( src/core/ext/client_channel/lb_policy_factory.h )
   s.files += %w( src/core/ext/client_channel/lb_policy_registry.h )
   s.files += %w( src/core/ext/client_channel/parse_address.h )
+  s.files += %w( src/core/ext/client_channel/proxy_mapper.h )
+  s.files += %w( src/core/ext/client_channel/proxy_mapper_registry.h )
   s.files += %w( src/core/ext/client_channel/resolver.h )
   s.files += %w( src/core/ext/client_channel/resolver_factory.h )
   s.files += %w( src/core/ext/client_channel/resolver_registry.h )
@@ -528,11 +531,14 @@ Gem::Specification.new do |s|
   s.files += %w( src/core/ext/client_channel/connector.c )
   s.files += %w( src/core/ext/client_channel/default_initial_connect_string.c )
   s.files += %w( src/core/ext/client_channel/http_connect_handshaker.c )
+  s.files += %w( src/core/ext/client_channel/http_proxy.c )
   s.files += %w( src/core/ext/client_channel/initial_connect_string.c )
   s.files += %w( src/core/ext/client_channel/lb_policy.c )
   s.files += %w( src/core/ext/client_channel/lb_policy_factory.c )
   s.files += %w( src/core/ext/client_channel/lb_policy_registry.c )
   s.files += %w( src/core/ext/client_channel/parse_address.c )
+  s.files += %w( src/core/ext/client_channel/proxy_mapper.c )
+  s.files += %w( src/core/ext/client_channel/proxy_mapper_registry.c )
   s.files += %w( src/core/ext/client_channel/resolver.c )
   s.files += %w( src/core/ext/client_channel/resolver_factory.c )
   s.files += %w( src/core/ext/client_channel/resolver_registry.c )
diff --git a/package.xml b/package.xml
index 70384de6a0e2da762151098177ab51334202fa9f..d369aba059335a8101be1aa6de6240aa501b85d3 100644
--- a/package.xml
+++ b/package.xml
@@ -329,11 +329,14 @@
     <file baseinstalldir="/" name="src/core/ext/client_channel/client_channel_factory.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/client_channel/connector.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/client_channel/http_connect_handshaker.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/client_channel/http_proxy.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/client_channel/initial_connect_string.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/client_channel/lb_policy.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/client_channel/lb_policy_factory.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/client_channel/lb_policy_registry.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/client_channel/parse_address.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/client_channel/proxy_mapper.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/client_channel/proxy_mapper_registry.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/client_channel/resolver.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/client_channel/resolver_factory.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/client_channel/resolver_registry.h" role="src" />
@@ -537,11 +540,14 @@
     <file baseinstalldir="/" name="src/core/ext/client_channel/connector.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/client_channel/default_initial_connect_string.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/client_channel/http_connect_handshaker.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/client_channel/http_proxy.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/client_channel/initial_connect_string.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/client_channel/lb_policy.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/client_channel/lb_policy_factory.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/client_channel/lb_policy_registry.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/client_channel/parse_address.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/client_channel/proxy_mapper.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/client_channel/proxy_mapper_registry.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/client_channel/resolver.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/client_channel/resolver_factory.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/client_channel/resolver_registry.c" role="src" />
diff --git a/src/core/ext/client_channel/client_channel.c b/src/core/ext/client_channel/client_channel.c
index 74350d9feeae19d5a5a817a0ff5772c470c2bace..07eb68a3eb1aba343f0126bb31d1e301c7f35ed5 100644
--- a/src/core/ext/client_channel/client_channel.c
+++ b/src/core/ext/client_channel/client_channel.c
@@ -43,6 +43,8 @@
 #include <grpc/support/sync.h>
 #include <grpc/support/useful.h>
 
+#include "src/core/ext/client_channel/http_connect_handshaker.h"
+#include "src/core/ext/client_channel/http_proxy.h"
 #include "src/core/ext/client_channel/lb_policy_registry.h"
 #include "src/core/ext/client_channel/resolver_registry.h"
 #include "src/core/ext/client_channel/subchannel.h"
@@ -151,6 +153,10 @@ static void *method_parameters_create_from_json(const grpc_json *json) {
  */
 
 typedef struct client_channel_channel_data {
+  /** server name */
+  char *server_name;
+  /** HTTP CONNECT proxy to use, if any */
+  char *proxy_name;
   /** resolver for this channel */
   grpc_resolver *resolver;
   /** have we started resolving this channel */
@@ -311,6 +317,17 @@ static void on_resolver_result_changed(grpc_exec_ctx *exec_ctx, void *arg,
     // Use pick_first if nothing was specified and we didn't select grpclb
     // above.
     if (lb_policy_name == NULL) lb_policy_name = "pick_first";
+    // If using a proxy, add channel arg for server in HTTP CONNECT request.
+    if (chand->proxy_name != NULL) {
+      grpc_arg new_arg;
+      new_arg.key = GRPC_ARG_HTTP_CONNECT_SERVER;
+      new_arg.type = GRPC_ARG_STRING;
+      new_arg.value.string = chand->server_name;
+      grpc_channel_args *tmp_args = chand->resolver_result;
+      chand->resolver_result =
+          grpc_channel_args_copy_and_add(chand->resolver_result, &new_arg, 1);
+      grpc_channel_args_destroy(exec_ctx, tmp_args);
+    }
     // Instantiate LB policy.
     grpc_lb_policy_args lb_policy_args;
     lb_policy_args.args = chand->resolver_result;
@@ -529,9 +546,12 @@ static grpc_error *cc_init_channel_elem(grpc_exec_ctx *exec_ctx,
   arg = grpc_channel_args_find(args->channel_args, GRPC_ARG_SERVER_URI);
   GPR_ASSERT(arg != NULL);
   GPR_ASSERT(arg->type == GRPC_ARG_STRING);
-  chand->resolver =
-      grpc_resolver_create(exec_ctx, arg->value.string, args->channel_args,
-                           chand->interested_parties);
+  chand->server_name = gpr_strdup(arg->value.string);
+  chand->proxy_name = grpc_get_http_proxy_server();
+  char *name_to_resolve =
+      chand->proxy_name == NULL ? chand->server_name : chand->proxy_name;
+  chand->resolver = grpc_resolver_create(
+      exec_ctx, name_to_resolve, args->channel_args, chand->interested_parties);
   if (chand->resolver == NULL) {
     return GRPC_ERROR_CREATE("resolver creation failed");
   }
@@ -542,7 +562,8 @@ static grpc_error *cc_init_channel_elem(grpc_exec_ctx *exec_ctx,
 static void cc_destroy_channel_elem(grpc_exec_ctx *exec_ctx,
                                     grpc_channel_element *elem) {
   channel_data *chand = elem->channel_data;
-
+  gpr_free(chand->server_name);
+  gpr_free(chand->proxy_name);
   if (chand->resolver != NULL) {
     grpc_resolver_shutdown(exec_ctx, chand->resolver);
     GRPC_RESOLVER_UNREF(exec_ctx, chand->resolver, "channel");
diff --git a/src/core/ext/client_channel/client_channel_plugin.c b/src/core/ext/client_channel/client_channel_plugin.c
index d50bba60f6a28a0cb201d00013c2c60b708d15f1..7f75233727e44fc6d08fb541e11ea7788b35cc02 100644
--- a/src/core/ext/client_channel/client_channel_plugin.c
+++ b/src/core/ext/client_channel/client_channel_plugin.c
@@ -40,6 +40,7 @@
 #include "src/core/ext/client_channel/client_channel.h"
 #include "src/core/ext/client_channel/http_connect_handshaker.h"
 #include "src/core/ext/client_channel/lb_policy_registry.h"
+#include "src/core/ext/client_channel/proxy_mapper_registry.h"
 #include "src/core/ext/client_channel/resolver_registry.h"
 #include "src/core/ext/client_channel/subchannel_index.h"
 #include "src/core/lib/surface/channel_init.h"
@@ -80,6 +81,7 @@ static bool set_default_host_if_unset(grpc_exec_ctx *exec_ctx,
 void grpc_client_channel_init(void) {
   grpc_lb_policy_registry_init();
   grpc_resolver_registry_init();
+  grpc_proxy_mapper_registry_init();
   grpc_subchannel_index_init();
   grpc_channel_init_register_stage(GRPC_CLIENT_CHANNEL, INT_MIN,
                                    set_default_host_if_unset, NULL);
@@ -91,6 +93,7 @@ void grpc_client_channel_init(void) {
 void grpc_client_channel_shutdown(void) {
   grpc_subchannel_index_shutdown();
   grpc_channel_init_shutdown();
+  grpc_proxy_mapper_registry_shutdown();
   grpc_resolver_registry_shutdown();
   grpc_lb_policy_registry_shutdown();
 }
diff --git a/src/core/ext/client_channel/http_connect_handshaker.c b/src/core/ext/client_channel/http_connect_handshaker.c
index fba32561acf822b04c776ced5815df6c8a98d0cc..622d236320f3a717440b2c8c22a8d18d230dd20b 100644
--- a/src/core/ext/client_channel/http_connect_handshaker.c
+++ b/src/core/ext/client_channel/http_connect_handshaker.c
@@ -49,15 +49,12 @@
 #include "src/core/lib/http/parser.h"
 #include "src/core/lib/slice/slice_internal.h"
 #include "src/core/lib/support/env.h"
+#include "src/core/lib/support/string.h"
 
 typedef struct http_connect_handshaker {
   // Base class.  Must be first.
   grpc_handshaker base;
 
-  char* proxy_server;
-  grpc_http_header* headers;
-  size_t num_headers;
-
   gpr_refcount refcount;
   gpr_mu mu;
 
@@ -91,12 +88,6 @@ static void http_connect_handshaker_unref(grpc_exec_ctx* exec_ctx,
                                          handshaker->read_buffer_to_destroy);
       gpr_free(handshaker->read_buffer_to_destroy);
     }
-    gpr_free(handshaker->proxy_server);
-    for (size_t i = 0; i < handshaker->num_headers; ++i) {
-      gpr_free(handshaker->headers[i].key);
-      gpr_free(handshaker->headers[i].value);
-    }
-    gpr_free(handshaker->headers);
     grpc_slice_buffer_destroy_internal(exec_ctx, &handshaker->write_buffer);
     grpc_http_parser_destroy(&handshaker->http_parser);
     grpc_http_response_destroy(&handshaker->http_response);
@@ -276,64 +267,88 @@ static void http_connect_handshaker_do_handshake(
     grpc_tcp_server_acceptor* acceptor, grpc_closure* on_handshake_done,
     grpc_handshaker_args* args) {
   http_connect_handshaker* handshaker = (http_connect_handshaker*)handshaker_in;
-  // Get server name from channel args.
-  const grpc_arg* arg = grpc_channel_args_find(args->args, GRPC_ARG_SERVER_URI);
-  GPR_ASSERT(arg != NULL);
+  // Check for HTTP CONNECT channel arg.
+  // If not found, invoke on_handshake_done without doing anything.
+  const grpc_arg* arg =
+      grpc_channel_args_find(args->args, GRPC_ARG_HTTP_CONNECT_SERVER);
+  if (arg == NULL) {
+    // Set shutdown to true so that subsequent calls to
+    // http_connect_handshaker_shutdown() do nothing.
+    gpr_mu_lock(&handshaker->mu);
+    handshaker->shutdown = true;
+    gpr_mu_unlock(&handshaker->mu);
+    grpc_closure_sched(exec_ctx, on_handshake_done, GRPC_ERROR_NONE);
+    return;
+  }
   GPR_ASSERT(arg->type == GRPC_ARG_STRING);
-  char* canonical_uri =
-      grpc_resolver_factory_add_default_prefix_if_needed(arg->value.string);
-  grpc_uri* uri = grpc_uri_parse(canonical_uri, 1);
-  char* server_name = uri->path;
-  if (server_name[0] == '/') ++server_name;
+  char* server_name = arg->value.string;
+  // Get headers from channel args.
+  arg = grpc_channel_args_find(args->args, GRPC_ARG_HTTP_CONNECT_HEADERS);
+  grpc_http_header* headers = NULL;
+  size_t num_headers = 0;
+  char** header_strings = NULL;
+  size_t num_header_strings = 0;
+  if (arg != NULL) {
+    GPR_ASSERT(arg->type == GRPC_ARG_STRING);
+    gpr_string_split(arg->value.string, "\n", &header_strings,
+                     &num_header_strings);
+    headers = gpr_malloc(sizeof(grpc_http_header) * num_header_strings);
+    for (size_t i = 0; i < num_header_strings; ++i) {
+      char* sep = strchr(header_strings[i], ':');
+      if (sep == NULL) {
+        gpr_log(GPR_ERROR, "skipping unparseable HTTP CONNECT header: %s",
+                header_strings[i]);
+        continue;
+      }
+      *sep = '\0';
+      headers[num_headers].key = header_strings[i];
+      headers[num_headers].value = sep + 1;
+      ++num_headers;
+    }
+  }
   // Save state in the handshaker object.
   gpr_mu_lock(&handshaker->mu);
   handshaker->args = args;
   handshaker->on_handshake_done = on_handshake_done;
-  // Send HTTP CONNECT request.
+  // Log connection via proxy.
+  char* proxy_name = grpc_endpoint_get_peer(args->endpoint);
   gpr_log(GPR_INFO, "Connecting to server %s via HTTP proxy %s", server_name,
-          handshaker->proxy_server);
+          proxy_name);
+  gpr_free(proxy_name);
+  // Construct HTTP CONNECT request.
   grpc_httpcli_request request;
   memset(&request, 0, sizeof(request));
   request.host = server_name;
   request.http.method = "CONNECT";
   request.http.path = server_name;
-  request.http.hdrs = handshaker->headers;
-  request.http.hdr_count = handshaker->num_headers;
+  request.http.hdrs = headers;
+  request.http.hdr_count = num_headers;
   request.handshaker = &grpc_httpcli_plaintext;
   grpc_slice request_slice = grpc_httpcli_format_connect_request(&request);
   grpc_slice_buffer_add(&handshaker->write_buffer, request_slice);
+  // Clean up.
+  gpr_free(headers);
+  for (size_t i = 0; i < num_header_strings; ++i) {
+    gpr_free(header_strings[i]);
+  }
+  gpr_free(header_strings);
   // Take a new ref to be held by the write callback.
   gpr_ref(&handshaker->refcount);
   grpc_endpoint_write(exec_ctx, args->endpoint, &handshaker->write_buffer,
                       &handshaker->request_done_closure);
   gpr_mu_unlock(&handshaker->mu);
-  // Clean up.
-  gpr_free(canonical_uri);
-  grpc_uri_destroy(uri);
 }
 
 static const grpc_handshaker_vtable http_connect_handshaker_vtable = {
     http_connect_handshaker_destroy, http_connect_handshaker_shutdown,
     http_connect_handshaker_do_handshake};
 
-grpc_handshaker* grpc_http_connect_handshaker_create(const char* proxy_server,
-                                                     grpc_http_header* headers,
-                                                     size_t num_headers) {
-  GPR_ASSERT(proxy_server != NULL);
+static grpc_handshaker* grpc_http_connect_handshaker_create() {
   http_connect_handshaker* handshaker = gpr_malloc(sizeof(*handshaker));
   memset(handshaker, 0, sizeof(*handshaker));
   grpc_handshaker_init(&http_connect_handshaker_vtable, &handshaker->base);
   gpr_mu_init(&handshaker->mu);
   gpr_ref_init(&handshaker->refcount, 1);
-  handshaker->proxy_server = gpr_strdup(proxy_server);
-  if (num_headers > 0) {
-    handshaker->headers = gpr_malloc(sizeof(grpc_http_header) * num_headers);
-    for (size_t i = 0; i < num_headers; ++i) {
-      handshaker->headers[i].key = gpr_strdup(headers[i].key);
-      handshaker->headers[i].value = gpr_strdup(headers[i].value);
-    }
-    handshaker->num_headers = num_headers;
-  }
   grpc_slice_buffer_init(&handshaker->write_buffer);
   grpc_closure_init(&handshaker->request_done_closure, on_write_done,
                     handshaker, grpc_schedule_on_exec_ctx);
@@ -344,30 +359,6 @@ grpc_handshaker* grpc_http_connect_handshaker_create(const char* proxy_server,
   return &handshaker->base;
 }
 
-char* grpc_get_http_proxy_server() {
-  char* uri_str = gpr_getenv("http_proxy");
-  if (uri_str == NULL) return NULL;
-  grpc_uri* uri = grpc_uri_parse(uri_str, false /* suppress_errors */);
-  char* proxy_name = NULL;
-  if (uri == NULL || uri->authority == NULL) {
-    gpr_log(GPR_ERROR, "cannot parse value of 'http_proxy' env var");
-    goto done;
-  }
-  if (strcmp(uri->scheme, "http") != 0) {
-    gpr_log(GPR_ERROR, "'%s' scheme not supported in proxy URI", uri->scheme);
-    goto done;
-  }
-  if (strchr(uri->authority, '@') != NULL) {
-    gpr_log(GPR_ERROR, "userinfo not supported in proxy URI");
-    goto done;
-  }
-  proxy_name = gpr_strdup(uri->authority);
-done:
-  gpr_free(uri_str);
-  grpc_uri_destroy(uri);
-  return proxy_name;
-}
-
 //
 // handshaker factory
 //
@@ -375,13 +366,8 @@ done:
 static void handshaker_factory_add_handshakers(
     grpc_exec_ctx* exec_ctx, grpc_handshaker_factory* factory,
     const grpc_channel_args* args, grpc_handshake_manager* handshake_mgr) {
-  char* proxy_name = grpc_get_http_proxy_server();
-  if (proxy_name != NULL) {
-    grpc_handshake_manager_add(
-        handshake_mgr,
-        grpc_http_connect_handshaker_create(proxy_name, NULL, 0));
-    gpr_free(proxy_name);
-  }
+  grpc_handshake_manager_add(handshake_mgr,
+                             grpc_http_connect_handshaker_create());
 }
 
 static void handshaker_factory_destroy(grpc_exec_ctx* exec_ctx,
diff --git a/src/core/ext/client_channel/http_connect_handshaker.h b/src/core/ext/client_channel/http_connect_handshaker.h
index c2e68de7167bff20cb65b033268a519886f5cc74..3059d551e34391a027b8c032c58ec017caf23fa7 100644
--- a/src/core/ext/client_channel/http_connect_handshaker.h
+++ b/src/core/ext/client_channel/http_connect_handshaker.h
@@ -34,17 +34,14 @@
 #ifndef GRPC_CORE_EXT_CLIENT_CHANNEL_HTTP_CONNECT_HANDSHAKER_H
 #define GRPC_CORE_EXT_CLIENT_CHANNEL_HTTP_CONNECT_HANDSHAKER_H
 
-#include "src/core/lib/channel/handshaker.h"
-#include "src/core/lib/http/parser.h"
+/// Channel arg indicating the server in HTTP CONNECT request (string).
+/// The presence of this arg triggers the use of HTTP CONNECT.
+#define GRPC_ARG_HTTP_CONNECT_SERVER "grpc.http_connect_server"
 
-/// Creates a new HTTP CONNECT handshaker.
-grpc_handshaker* grpc_http_connect_handshaker_create(const char* proxy_server,
-                                                     grpc_http_header* headers,
-                                                     size_t num_headers);
-
-/// Returns the name of the proxy to use, or NULL if no proxy is configured.
-/// Caller takes ownership of result.
-char* grpc_get_http_proxy_server();
+/// Channel arg indicating HTTP CONNECT headers (string).
+/// Multiple headers are separated by newlines.  Key/value pairs are
+/// seperated by colons.
+#define GRPC_ARG_HTTP_CONNECT_HEADERS "grpc.http_connect_headers"
 
 /// Registers handshaker factory.
 void grpc_http_connect_register_handshaker_factory();
diff --git a/src/core/ext/client_channel/http_proxy.c b/src/core/ext/client_channel/http_proxy.c
new file mode 100644
index 0000000000000000000000000000000000000000..9a6c818c4ee85cdf366defff6140fd4b953228fb
--- /dev/null
+++ b/src/core/ext/client_channel/http_proxy.c
@@ -0,0 +1,68 @@
+/*
+ *
+ * Copyright 2016, 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 "src/core/ext/client_channel/http_proxy.h"
+
+#include <stdbool.h>
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
+
+#include "src/core/ext/client_channel/uri_parser.h"
+#include "src/core/lib/support/env.h"
+
+char* grpc_get_http_proxy_server() {
+  char* uri_str = gpr_getenv("http_proxy");
+  if (uri_str == NULL) return NULL;
+  grpc_uri* uri = grpc_uri_parse(uri_str, false /* suppress_errors */);
+  char* proxy_name = NULL;
+  if (uri == NULL || uri->authority == NULL) {
+    gpr_log(GPR_ERROR, "cannot parse value of 'http_proxy' env var");
+    goto done;
+  }
+  if (strcmp(uri->scheme, "http") != 0) {
+    gpr_log(GPR_ERROR, "'%s' scheme not supported in proxy URI", uri->scheme);
+    goto done;
+  }
+  if (strchr(uri->authority, '@') != NULL) {
+    gpr_log(GPR_ERROR, "userinfo not supported in proxy URI");
+    goto done;
+  }
+  proxy_name = gpr_strdup(uri->authority);
+done:
+  gpr_free(uri_str);
+  grpc_uri_destroy(uri);
+  return proxy_name;
+}
diff --git a/src/core/ext/client_channel/http_proxy.h b/src/core/ext/client_channel/http_proxy.h
new file mode 100644
index 0000000000000000000000000000000000000000..0d77ae253b083cfe142dbf5fb53b783c00aa954f
--- /dev/null
+++ b/src/core/ext/client_channel/http_proxy.h
@@ -0,0 +1,41 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_EXT_CLIENT_CHANNEL_HTTP_PROXY_H
+#define GRPC_CORE_EXT_CLIENT_CHANNEL_HTTP_PROXY_H
+
+/// Returns the name of the proxy to use, or NULL if no proxy is configured.
+/// Caller takes ownership of result.
+char* grpc_get_http_proxy_server();
+
+#endif /* GRPC_CORE_EXT_CLIENT_CHANNEL_HTTP_PROXY_H */
diff --git a/src/core/ext/client_channel/proxy_mapper.c b/src/core/ext/client_channel/proxy_mapper.c
new file mode 100644
index 0000000000000000000000000000000000000000..6b6f328d3ce1a8dfb41279d2412244f002dbe5f6
--- /dev/null
+++ b/src/core/ext/client_channel/proxy_mapper.c
@@ -0,0 +1,52 @@
+/*
+ *
+ * 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 "src/core/ext/client_channel/proxy_mapper.h"
+
+void grpc_proxy_mapper_init(const grpc_proxy_mapper_vtable* vtable,
+                            grpc_proxy_mapper* mapper) {
+  mapper->vtable = vtable;
+}
+
+bool grpc_proxy_mapper_map(grpc_exec_ctx* exec_ctx, grpc_proxy_mapper* mapper,
+                           const grpc_resolved_address* address,
+                           const grpc_channel_args* args,
+                           grpc_resolved_address** new_address,
+                           grpc_channel_args** new_args) {
+  return mapper->vtable->map(exec_ctx, mapper, address, args, new_address,
+                             new_args);
+}
+
+void grpc_proxy_mapper_destroy(grpc_proxy_mapper* mapper) {
+  mapper->vtable->destroy(mapper);
+}
diff --git a/src/core/ext/client_channel/proxy_mapper.h b/src/core/ext/client_channel/proxy_mapper.h
new file mode 100644
index 0000000000000000000000000000000000000000..fa930379e70673572a8de2d75474edb08585dbbd
--- /dev/null
+++ b/src/core/ext/client_channel/proxy_mapper.h
@@ -0,0 +1,73 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+#ifndef GRPC_CORE_EXT_CLIENT_CHANNEL_PROXY_MAPPER_H
+#define GRPC_CORE_EXT_CLIENT_CHANNEL_PROXY_MAPPER_H
+
+#include <stdbool.h>
+
+#include <grpc/impl/codegen/grpc_types.h>
+
+#include "src/core/lib/iomgr/resolve_address.h"
+
+typedef struct grpc_proxy_mapper grpc_proxy_mapper;
+
+typedef struct {
+  /// Determines the proxy address to use to contact \a address.
+  /// If no proxy is needed, returns false.
+  /// Otherwise, sets \a new_address, optionally sets \a new_args, and
+  /// returns true.
+  bool (*map)(grpc_exec_ctx* exec_ctx, grpc_proxy_mapper* mapper,
+              const grpc_resolved_address* address,
+              const grpc_channel_args* args,
+              grpc_resolved_address** new_address,
+              grpc_channel_args** new_args);
+  /// Destroys \a mapper.
+  void (*destroy)(grpc_proxy_mapper* mapper);
+} grpc_proxy_mapper_vtable;
+
+struct grpc_proxy_mapper {
+  const grpc_proxy_mapper_vtable* vtable;
+};
+
+void grpc_proxy_mapper_init(const grpc_proxy_mapper_vtable* vtable,
+                            grpc_proxy_mapper* mapper);
+
+bool grpc_proxy_mapper_map(grpc_exec_ctx* exec_ctx, grpc_proxy_mapper* mapper,
+                           const grpc_resolved_address* address,
+                           const grpc_channel_args* args,
+                           grpc_resolved_address** new_address,
+                           grpc_channel_args** new_args);
+void grpc_proxy_mapper_destroy(grpc_proxy_mapper* mapper);
+
+#endif /* GRPC_CORE_EXT_CLIENT_CHANNEL_PROXY_MAPPER_H */
diff --git a/src/core/ext/client_channel/proxy_mapper_registry.c b/src/core/ext/client_channel/proxy_mapper_registry.c
new file mode 100644
index 0000000000000000000000000000000000000000..0a156c8b1c1e5eb0d19baab3dddb296b28cb355e
--- /dev/null
+++ b/src/core/ext/client_channel/proxy_mapper_registry.c
@@ -0,0 +1,111 @@
+/*
+ *
+ * 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 "src/core/ext/client_channel/proxy_mapper_registry.h"
+
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+
+//
+// grpc_proxy_mapper_list
+//
+
+typedef struct {
+  grpc_proxy_mapper** list;
+  size_t num_mappers;
+} grpc_proxy_mapper_list;
+
+static void grpc_proxy_mapper_list_register(grpc_proxy_mapper_list* list,
+                                            bool at_start,
+                                            grpc_proxy_mapper* mapper) {
+  list->list = gpr_realloc(
+      list->list, (list->num_mappers + 1) * sizeof(grpc_proxy_mapper*));
+  if (at_start) {
+    memmove(list->list + 1, list->list,
+            sizeof(grpc_proxy_mapper*) * list->num_mappers);
+    list->list[0] = mapper;
+  } else {
+    list->list[list->num_mappers] = mapper;
+  }
+  ++list->num_mappers;
+}
+
+static bool grpc_proxy_mapper_list_map(grpc_exec_ctx* exec_ctx,
+                                       grpc_proxy_mapper_list* list,
+                                       const grpc_resolved_address* address,
+                                       const grpc_channel_args* args,
+                                       grpc_resolved_address** new_address,
+                                       grpc_channel_args** new_args) {
+  for (size_t i = 0; i < list->num_mappers; ++i) {
+    if (grpc_proxy_mapper_map(exec_ctx, list->list[i], address, args,
+                              new_address, new_args)) {
+      return true;
+    }
+  }
+  return false;
+}
+
+static void grpc_proxy_mapper_list_destroy(grpc_proxy_mapper_list* list) {
+  for (size_t i = 0; i < list->num_mappers; ++i) {
+    grpc_proxy_mapper_destroy(list->list[i]);
+  }
+  gpr_free(list->list);
+}
+
+//
+// plugin
+//
+
+static grpc_proxy_mapper_list g_proxy_mapper_list;
+
+void grpc_proxy_mapper_registry_init() {
+  memset(&g_proxy_mapper_list, 0, sizeof(g_proxy_mapper_list));
+}
+
+void grpc_proxy_mapper_registry_shutdown() {
+  grpc_proxy_mapper_list_destroy(&g_proxy_mapper_list);
+}
+
+void grpc_proxy_mapper_register(bool at_start, grpc_proxy_mapper* mapper) {
+  grpc_proxy_mapper_list_register(&g_proxy_mapper_list, at_start, mapper);
+}
+
+bool grpc_proxy_mappers_map(grpc_exec_ctx* exec_ctx,
+                            const grpc_resolved_address* address,
+                            const grpc_channel_args* args,
+                            grpc_resolved_address** new_address,
+                            grpc_channel_args** new_args) {
+  return grpc_proxy_mapper_list_map(exec_ctx, &g_proxy_mapper_list, address,
+                                    args, new_address, new_args);
+}
diff --git a/src/core/ext/client_channel/proxy_mapper_registry.h b/src/core/ext/client_channel/proxy_mapper_registry.h
new file mode 100644
index 0000000000000000000000000000000000000000..b76af8d4564c6a14af0740c32a97ffcfbff84c8f
--- /dev/null
+++ b/src/core/ext/client_channel/proxy_mapper_registry.h
@@ -0,0 +1,53 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+#ifndef GRPC_CORE_EXT_CLIENT_CHANNEL_PROXY_MAPPER_REGISTRY_H
+#define GRPC_CORE_EXT_CLIENT_CHANNEL_PROXY_MAPPER_REGISTRY_H
+
+#include "src/core/ext/client_channel/proxy_mapper.h"
+
+void grpc_proxy_mapper_registry_init();
+void grpc_proxy_mapper_registry_shutdown();
+
+/// Registers a new proxy mapper.  Takes ownership.
+/// If \a at_start is true, the new mapper will be at the beginning of
+/// the list.  Otherwise, it will be added to the end.
+void grpc_proxy_mapper_register(bool at_start, grpc_proxy_mapper* mapper);
+
+bool grpc_proxy_mappers_map(grpc_exec_ctx* exec_ctx,
+                            const grpc_resolved_address* address,
+                            const grpc_channel_args* args,
+                            grpc_resolved_address** new_address,
+                            grpc_channel_args** new_args);
+
+#endif /* GRPC_CORE_EXT_CLIENT_CHANNEL_PROXY_MAPPER_REGISTRY_H */
diff --git a/src/core/ext/client_channel/subchannel.c b/src/core/ext/client_channel/subchannel.c
index b7379b30b3af2ca90fca02240c8a6f821e4060b2..c5041f6924f8773c00ef0d2bdb5d7d548ebc97c4 100644
--- a/src/core/ext/client_channel/subchannel.c
+++ b/src/core/ext/client_channel/subchannel.c
@@ -43,6 +43,7 @@
 #include "src/core/ext/client_channel/client_channel.h"
 #include "src/core/ext/client_channel/initial_connect_string.h"
 #include "src/core/ext/client_channel/parse_address.h"
+#include "src/core/ext/client_channel/proxy_mapper_registry.h"
 #include "src/core/ext/client_channel/subchannel_index.h"
 #include "src/core/ext/client_channel/uri_parser.h"
 #include "src/core/lib/channel/channel_args.h"
@@ -332,13 +333,24 @@ grpc_subchannel *grpc_subchannel_create(grpc_exec_ctx *exec_ctx,
   grpc_resolved_address *addr = gpr_malloc(sizeof(*addr));
   grpc_get_subchannel_address_arg(args->args, addr);
   grpc_set_initial_connect_string(&addr, &c->initial_connect_string);
-  static const char *keys_to_remove[] = {GRPC_ARG_SUBCHANNEL_ADDRESS};
-  grpc_arg new_arg = grpc_create_subchannel_address_arg(addr);
+  grpc_resolved_address *new_address = NULL;
+  grpc_channel_args *new_args = NULL;
+  if (grpc_proxy_mappers_map(exec_ctx, addr, args->args, &new_address,
+                             &new_args)) {
+    GPR_ASSERT(new_address != NULL);
+    gpr_free(addr);
+    addr = new_address;
+    if (new_args != NULL) c->args = new_args;
+  }
+  if (c->args == NULL) {
+    static const char *keys_to_remove[] = {GRPC_ARG_SUBCHANNEL_ADDRESS};
+    grpc_arg new_arg = grpc_create_subchannel_address_arg(addr);
+    c->args = grpc_channel_args_copy_and_add_and_remove(
+        args->args, keys_to_remove, GPR_ARRAY_SIZE(keys_to_remove), &new_arg,
+        1);
+    gpr_free(new_arg.value.string);
+  }
   gpr_free(addr);
-  c->args = grpc_channel_args_copy_and_add_and_remove(
-      args->args, keys_to_remove, GPR_ARRAY_SIZE(keys_to_remove), &new_arg, 1);
-  gpr_free(new_arg.value.string);
-
   c->root_external_state_watcher.next = c->root_external_state_watcher.prev =
       &c->root_external_state_watcher;
   grpc_closure_init(&c->connected, subchannel_connected, c,
diff --git a/src/core/ext/resolver/dns/native/dns_resolver.c b/src/core/ext/resolver/dns/native/dns_resolver.c
index 58fe9d39852d48c94be72825ae24fc45a295a48c..2c9623211b3523ac4782bb0698891a104ca960e4 100644
--- a/src/core/ext/resolver/dns/native/dns_resolver.c
+++ b/src/core/ext/resolver/dns/native/dns_resolver.c
@@ -37,7 +37,6 @@
 #include <grpc/support/host_port.h>
 #include <grpc/support/string_util.h>
 
-#include "src/core/ext/client_channel/http_connect_handshaker.h"
 #include "src/core/ext/client_channel/lb_policy_registry.h"
 #include "src/core/ext/client_channel/resolver_registry.h"
 #include "src/core/lib/channel/channel_args.h"
@@ -260,16 +259,14 @@ static grpc_resolver *dns_create(grpc_exec_ctx *exec_ctx,
     return NULL;
   }
   // Get name from args.
-  const char *path = args->uri->path;
+  char *path = args->uri->path;
   if (path[0] == '/') ++path;
-  // Get proxy name, if any.
-  char *proxy_name = grpc_get_http_proxy_server();
   // Create resolver.
   dns_resolver *r = gpr_malloc(sizeof(dns_resolver));
   memset(r, 0, sizeof(*r));
   gpr_mu_init(&r->mu);
   grpc_resolver_init(&r->base, &dns_resolver_vtable);
-  r->name_to_resolve = proxy_name == NULL ? gpr_strdup(path) : proxy_name;
+  r->name_to_resolve = gpr_strdup(path);
   r->default_port = gpr_strdup(default_port);
   r->channel_args = grpc_channel_args_copy(args->args);
   r->interested_parties = grpc_pollset_set_create();
diff --git a/src/core/ext/transport/chttp2/transport/writing.c b/src/core/ext/transport/chttp2/transport/writing.c
index 182aff1e3ffc34e6ce8cca977cbe8b14b0c19bb5..148e3844b5d0e3b9ac09565e676bb734dca25bc7 100644
--- a/src/core/ext/transport/chttp2/transport/writing.c
+++ b/src/core/ext/transport/chttp2/transport/writing.c
@@ -74,6 +74,15 @@ static void update_list(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
   GRPC_ERROR_UNREF(error);
 }
 
+static bool stream_ref_if_not_destroyed(gpr_refcount *r) {
+  gpr_atm count;
+  do {
+    count = gpr_atm_acq_load(&r->count);
+    if (count == 0) return false;
+  } while (!gpr_atm_rel_cas(&r->count, count, count + 1));
+  return true;
+}
+
 bool grpc_chttp2_begin_write(grpc_exec_ctx *exec_ctx,
                              grpc_chttp2_transport *t) {
   grpc_chttp2_stream *s;
@@ -101,8 +110,11 @@ bool grpc_chttp2_begin_write(grpc_exec_ctx *exec_ctx,
 
   if (t->outgoing_window > 0) {
     while (grpc_chttp2_list_pop_stalled_by_transport(t, &s)) {
-      grpc_chttp2_become_writable(exec_ctx, t, s, false,
-                                  "transport.read_flow_control");
+      if (!t->closed && grpc_chttp2_list_add_writable_stream(t, s) &&
+          stream_ref_if_not_destroyed(&s->refcount->refs)) {
+        grpc_chttp2_initiate_write(exec_ctx, t, false,
+                                   "transport.read_flow_control");
+      }
     }
   }
 
diff --git a/src/core/lib/iomgr/ev_epoll_linux.c b/src/core/lib/iomgr/ev_epoll_linux.c
index 0a565565bdd2407b38ff4ad8635ddcdf3833a857..39b4d9cbd7b1f93d6da248a14733767a1dbb2d16 100644
--- a/src/core/lib/iomgr/ev_epoll_linux.c
+++ b/src/core/lib/iomgr/ev_epoll_linux.c
@@ -1527,7 +1527,8 @@ static void pollset_work_and_unlock(grpc_exec_ctx *exec_ctx,
         append_error(error, grpc_wakeup_fd_consume_wakeup(&global_wakeup_fd),
                      err_desc);
       } else if (data_ptr == &pi->workqueue_wakeup_fd) {
-        append_error(error, grpc_wakeup_fd_consume_wakeup(&global_wakeup_fd),
+        append_error(error,
+                     grpc_wakeup_fd_consume_wakeup(&pi->workqueue_wakeup_fd),
                      err_desc);
         maybe_do_workqueue_work(exec_ctx, pi);
       } else if (data_ptr == &polling_island_wakeup_fd) {
diff --git a/src/python/grpcio/grpc_core_dependencies.py b/src/python/grpcio/grpc_core_dependencies.py
index 0b86661db87dad498285b8ca3e782e0dc9448758..68e40da4cf3a475942c39ebfb1933415588f3cdd 100644
--- a/src/python/grpcio/grpc_core_dependencies.py
+++ b/src/python/grpcio/grpc_core_dependencies.py
@@ -250,11 +250,14 @@ CORE_SOURCE_FILES = [
   'src/core/ext/client_channel/connector.c',
   'src/core/ext/client_channel/default_initial_connect_string.c',
   'src/core/ext/client_channel/http_connect_handshaker.c',
+  'src/core/ext/client_channel/http_proxy.c',
   'src/core/ext/client_channel/initial_connect_string.c',
   'src/core/ext/client_channel/lb_policy.c',
   'src/core/ext/client_channel/lb_policy_factory.c',
   'src/core/ext/client_channel/lb_policy_registry.c',
   'src/core/ext/client_channel/parse_address.c',
+  'src/core/ext/client_channel/proxy_mapper.c',
+  'src/core/ext/client_channel/proxy_mapper_registry.c',
   'src/core/ext/client_channel/resolver.c',
   'src/core/ext/client_channel/resolver_factory.c',
   'src/core/ext/client_channel/resolver_registry.c',
diff --git a/tools/doxygen/Doxyfile.core.internal b/tools/doxygen/Doxyfile.core.internal
index 9fa2916ca91dc36cef48833314ded285ae2bd186..106817d229b9074e490163c12532ced9398d5a1e 100644
--- a/tools/doxygen/Doxyfile.core.internal
+++ b/tools/doxygen/Doxyfile.core.internal
@@ -897,6 +897,8 @@ src/core/ext/client_channel/connector.h \
 src/core/ext/client_channel/default_initial_connect_string.c \
 src/core/ext/client_channel/http_connect_handshaker.c \
 src/core/ext/client_channel/http_connect_handshaker.h \
+src/core/ext/client_channel/http_proxy.c \
+src/core/ext/client_channel/http_proxy.h \
 src/core/ext/client_channel/initial_connect_string.c \
 src/core/ext/client_channel/initial_connect_string.h \
 src/core/ext/client_channel/lb_policy.c \
@@ -907,6 +909,10 @@ src/core/ext/client_channel/lb_policy_registry.c \
 src/core/ext/client_channel/lb_policy_registry.h \
 src/core/ext/client_channel/parse_address.c \
 src/core/ext/client_channel/parse_address.h \
+src/core/ext/client_channel/proxy_mapper.c \
+src/core/ext/client_channel/proxy_mapper.h \
+src/core/ext/client_channel/proxy_mapper_registry.c \
+src/core/ext/client_channel/proxy_mapper_registry.h \
 src/core/ext/client_channel/resolver.c \
 src/core/ext/client_channel/resolver.h \
 src/core/ext/client_channel/resolver_factory.c \
diff --git a/tools/run_tests/generated/sources_and_headers.json b/tools/run_tests/generated/sources_and_headers.json
index e392a42949a7ed1ef02e7601600d51bd643934b5..6111aa8278ce61770a510a4cac0c59a30eab2031 100644
--- a/tools/run_tests/generated/sources_and_headers.json
+++ b/tools/run_tests/generated/sources_and_headers.json
@@ -7342,11 +7342,14 @@
       "src/core/ext/client_channel/client_channel_factory.h", 
       "src/core/ext/client_channel/connector.h", 
       "src/core/ext/client_channel/http_connect_handshaker.h", 
+      "src/core/ext/client_channel/http_proxy.h", 
       "src/core/ext/client_channel/initial_connect_string.h", 
       "src/core/ext/client_channel/lb_policy.h", 
       "src/core/ext/client_channel/lb_policy_factory.h", 
       "src/core/ext/client_channel/lb_policy_registry.h", 
       "src/core/ext/client_channel/parse_address.h", 
+      "src/core/ext/client_channel/proxy_mapper.h", 
+      "src/core/ext/client_channel/proxy_mapper_registry.h", 
       "src/core/ext/client_channel/resolver.h", 
       "src/core/ext/client_channel/resolver_factory.h", 
       "src/core/ext/client_channel/resolver_registry.h", 
@@ -7369,6 +7372,8 @@
       "src/core/ext/client_channel/default_initial_connect_string.c", 
       "src/core/ext/client_channel/http_connect_handshaker.c", 
       "src/core/ext/client_channel/http_connect_handshaker.h", 
+      "src/core/ext/client_channel/http_proxy.c", 
+      "src/core/ext/client_channel/http_proxy.h", 
       "src/core/ext/client_channel/initial_connect_string.c", 
       "src/core/ext/client_channel/initial_connect_string.h", 
       "src/core/ext/client_channel/lb_policy.c", 
@@ -7379,6 +7384,10 @@
       "src/core/ext/client_channel/lb_policy_registry.h", 
       "src/core/ext/client_channel/parse_address.c", 
       "src/core/ext/client_channel/parse_address.h", 
+      "src/core/ext/client_channel/proxy_mapper.c", 
+      "src/core/ext/client_channel/proxy_mapper.h", 
+      "src/core/ext/client_channel/proxy_mapper_registry.c", 
+      "src/core/ext/client_channel/proxy_mapper_registry.h", 
       "src/core/ext/client_channel/resolver.c", 
       "src/core/ext/client_channel/resolver.h", 
       "src/core/ext/client_channel/resolver_factory.c", 
diff --git a/vsprojects/vcxproj/grpc/grpc.vcxproj b/vsprojects/vcxproj/grpc/grpc.vcxproj
index 2d79ffebb4977c5331888d88057ef6d3a2d82cd9..13d825af681b49e8c5f8839dfd2b84a614de958d 100644
--- a/vsprojects/vcxproj/grpc/grpc.vcxproj
+++ b/vsprojects/vcxproj/grpc/grpc.vcxproj
@@ -452,11 +452,14 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\client_channel_factory.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\connector.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\http_connect_handshaker.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\http_proxy.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\initial_connect_string.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\lb_policy.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\lb_policy_factory.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\lb_policy_registry.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\parse_address.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\proxy_mapper.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\proxy_mapper_registry.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\resolver.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\resolver_factory.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\resolver_registry.h" />
@@ -838,6 +841,8 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\http_connect_handshaker.c">
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\http_proxy.c">
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\initial_connect_string.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\lb_policy.c">
@@ -848,6 +853,10 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\parse_address.c">
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\proxy_mapper.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\proxy_mapper_registry.c">
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\resolver.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\resolver_factory.c">
diff --git a/vsprojects/vcxproj/grpc/grpc.vcxproj.filters b/vsprojects/vcxproj/grpc/grpc.vcxproj.filters
index 044934998351f412fe3cb9f136edbf6a3c573cea..de2e82173fb9040e9042a6ce2ebf241d6cbf638f 100644
--- a/vsprojects/vcxproj/grpc/grpc.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc/grpc.vcxproj.filters
@@ -529,6 +529,9 @@
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\http_connect_handshaker.c">
       <Filter>src\core\ext\client_channel</Filter>
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\http_proxy.c">
+      <Filter>src\core\ext\client_channel</Filter>
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\initial_connect_string.c">
       <Filter>src\core\ext\client_channel</Filter>
     </ClCompile>
@@ -544,6 +547,12 @@
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\parse_address.c">
       <Filter>src\core\ext\client_channel</Filter>
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\proxy_mapper.c">
+      <Filter>src\core\ext\client_channel</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\proxy_mapper_registry.c">
+      <Filter>src\core\ext\client_channel</Filter>
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\resolver.c">
       <Filter>src\core\ext\client_channel</Filter>
     </ClCompile>
@@ -1211,6 +1220,9 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\http_connect_handshaker.h">
       <Filter>src\core\ext\client_channel</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\http_proxy.h">
+      <Filter>src\core\ext\client_channel</Filter>
+    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\initial_connect_string.h">
       <Filter>src\core\ext\client_channel</Filter>
     </ClInclude>
@@ -1226,6 +1238,12 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\parse_address.h">
       <Filter>src\core\ext\client_channel</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\proxy_mapper.h">
+      <Filter>src\core\ext\client_channel</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\proxy_mapper_registry.h">
+      <Filter>src\core\ext\client_channel</Filter>
+    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\resolver.h">
       <Filter>src\core\ext\client_channel</Filter>
     </ClInclude>
diff --git a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj
index 20a47cda8c74b1b52c7750a20e42932ed741f1eb..826c06576e957b158449fff31de48efdb0d72960 100644
--- a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj
+++ b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj
@@ -419,11 +419,14 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\client_channel_factory.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\connector.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\http_connect_handshaker.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\http_proxy.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\initial_connect_string.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\lb_policy.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\lb_policy_factory.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\lb_policy_registry.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\parse_address.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\proxy_mapper.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\proxy_mapper_registry.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\resolver.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\resolver_factory.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\resolver_registry.h" />
@@ -758,6 +761,8 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\http_connect_handshaker.c">
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\http_proxy.c">
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\initial_connect_string.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\lb_policy.c">
@@ -768,6 +773,10 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\parse_address.c">
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\proxy_mapper.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\proxy_mapper_registry.c">
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\resolver.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\resolver_factory.c">
diff --git a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters
index 8490ac7dfe5813e68ecdeeec0729047c8832cdca..06ddac9de719982b1fc1f68fc465d498a7f0b6ac 100644
--- a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters
@@ -460,6 +460,9 @@
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\http_connect_handshaker.c">
       <Filter>src\core\ext\client_channel</Filter>
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\http_proxy.c">
+      <Filter>src\core\ext\client_channel</Filter>
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\initial_connect_string.c">
       <Filter>src\core\ext\client_channel</Filter>
     </ClCompile>
@@ -475,6 +478,12 @@
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\parse_address.c">
       <Filter>src\core\ext\client_channel</Filter>
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\proxy_mapper.c">
+      <Filter>src\core\ext\client_channel</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\proxy_mapper_registry.c">
+      <Filter>src\core\ext\client_channel</Filter>
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\resolver.c">
       <Filter>src\core\ext\client_channel</Filter>
     </ClCompile>
@@ -1055,6 +1064,9 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\http_connect_handshaker.h">
       <Filter>src\core\ext\client_channel</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\http_proxy.h">
+      <Filter>src\core\ext\client_channel</Filter>
+    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\initial_connect_string.h">
       <Filter>src\core\ext\client_channel</Filter>
     </ClInclude>
@@ -1070,6 +1082,12 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\parse_address.h">
       <Filter>src\core\ext\client_channel</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\proxy_mapper.h">
+      <Filter>src\core\ext\client_channel</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\proxy_mapper_registry.h">
+      <Filter>src\core\ext\client_channel</Filter>
+    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\resolver.h">
       <Filter>src\core\ext\client_channel</Filter>
     </ClInclude>
diff --git a/vsprojects/vcxproj/test/grpclb_test/grpclb_test.vcxproj b/vsprojects/vcxproj/test/grpclb_test/grpclb_test.vcxproj
index 91b9a6eaccc9a1a678d09626926f3c028e701e61..cd5aa4c1de0d56355cdbc451df5076344ad11caf 100644
--- a/vsprojects/vcxproj/test/grpclb_test/grpclb_test.vcxproj
+++ b/vsprojects/vcxproj/test/grpclb_test/grpclb_test.vcxproj
@@ -172,23 +172,23 @@
     </ClCompile>
   </ItemGroup>
   <ItemGroup>
-    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\gpr\gpr.vcxproj">
-      <Project>{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}</Project>
-    </ProjectReference>
-    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\gpr_test_util\gpr_test_util.vcxproj">
-      <Project>{EAB0A629-17A9-44DB-B5FF-E91A721FE037}</Project>
+    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc++_test_util\grpc++_test_util.vcxproj">
+      <Project>{0BE77741-552A-929B-A497-4EF7ECE17A64}</Project>
     </ProjectReference>
-    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc\grpc.vcxproj">
-      <Project>{29D16885-7228-4C31-81ED-5F9187C7F2A9}</Project>
+    <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>{C187A093-A0FE-489D-A40A-6E33DE0F9FEB}</Project>
     </ProjectReference>
-    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc++_test_util\grpc++_test_util.vcxproj">
-      <Project>{0BE77741-552A-929B-A497-4EF7ECE17A64}</Project>
+    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc\grpc.vcxproj">
+      <Project>{29D16885-7228-4C31-81ED-5F9187C7F2A9}</Project>
     </ProjectReference>
-    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc_test_util\grpc_test_util.vcxproj">
-      <Project>{17BCAFC0-5FDC-4C94-AEB9-95F3E220614B}</Project>
+    <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>