Made significant progress on the test, but not working yet.
diff --git a/Makefile b/Makefile
index 8e89ece..76da2ca 100644
--- a/Makefile
+++ b/Makefile
@@ -3051,6 +3051,7 @@
     test/core/end2end/data/test_root_cert.c \
     test/core/security/oauth2_utils.c \
     test/core/end2end/cq_verifier.c \
+    test/core/end2end/fixtures/http_proxy.c \
     test/core/end2end/fixtures/proxy.c \
     test/core/iomgr/endpoint_tests.c \
     test/core/util/grpc_profiler.c \
@@ -3101,6 +3102,7 @@
 
 LIBGRPC_TEST_UTIL_UNSECURE_SRC = \
     test/core/end2end/cq_verifier.c \
+    test/core/end2end/fixtures/http_proxy.c \
     test/core/end2end/fixtures/proxy.c \
     test/core/iomgr/endpoint_tests.c \
     test/core/util/grpc_profiler.c \
diff --git a/build.yaml b/build.yaml
index 585d4de..1cb428d 100644
--- a/build.yaml
+++ b/build.yaml
@@ -484,6 +484,7 @@
   build: test
   headers:
   - test/core/end2end/cq_verifier.h
+  - test/core/end2end/fixtures/http_proxy.h
   - test/core/end2end/fixtures/proxy.h
   - test/core/iomgr/endpoint_tests.h
   - test/core/util/grpc_profiler.h
@@ -496,6 +497,7 @@
   - test/core/util/slice_splitter.h
   src:
   - test/core/end2end/cq_verifier.c
+  - test/core/end2end/fixtures/http_proxy.c
   - test/core/end2end/fixtures/proxy.c
   - test/core/iomgr/endpoint_tests.c
   - test/core/util/grpc_profiler.c
diff --git a/src/core/ext/client_config/http_connect_handshaker.c b/src/core/ext/client_config/http_connect_handshaker.c
index a5cb6d1..25246dd 100644
--- a/src/core/ext/client_config/http_connect_handshaker.c
+++ b/src/core/ext/client_config/http_connect_handshaker.c
@@ -103,6 +103,7 @@
     // complete (e.g., handling chunked transfer encoding or looking
     // at the Content-Length: header).
     if (h->http_parser.state != GRPC_HTTP_BODY) {
+      gpr_slice_buffer_reset_and_unref(&h->response_buffer);
       grpc_endpoint_read(exec_ctx, h->endpoint, &h->response_buffer,
                          &h->response_read_closure);
       return;
diff --git a/src/core/lib/iomgr/exec_ctx.h b/src/core/lib/iomgr/exec_ctx.h
index 917f332..65584ea 100644
--- a/src/core/lib/iomgr/exec_ctx.h
+++ b/src/core/lib/iomgr/exec_ctx.h
@@ -43,7 +43,6 @@
 struct grpc_workqueue;
 typedef struct grpc_workqueue grpc_workqueue;
 
-#ifndef GRPC_EXECUTION_CONTEXT_SANITIZER
 /** Execution context.
  *  A bag of data that collects information along a callstack.
  *  Generally created at public API entry points, and passed down as
@@ -58,12 +57,13 @@
  *    should actively try to finish up and get this thread back to its owner
  *
  *  CONVENTIONS:
- *  Instance of this must ALWAYS be constructed on the stack, never
- *  heap allocated. Instances and pointers to them must always be called
- *  exec_ctx. Instances are always passed as the first argument
- *  to a function that takes it, and always as a pointer (grpc_exec_ctx
- *  is never copied).
+ *  - Instance of this must ALWAYS be constructed on the stack, never
+ *    heap allocated.
+ *  - Instances and pointers to them must always be called exec_ctx.
+ *  - Instances are always passed as the first argument to a function that
+ *    takes it, and always as a pointer (grpc_exec_ctx is never copied).
  */
+#ifndef GRPC_EXECUTION_CONTEXT_SANITIZER
 struct grpc_exec_ctx {
   grpc_closure_list closure_list;
   bool cached_ready_to_finish;
diff --git a/test/core/end2end/fixtures/h2_http_proxy.c b/test/core/end2end/fixtures/h2_http_proxy.c
index 4578d75..d84f0b8 100644
--- a/test/core/end2end/fixtures/h2_http_proxy.c
+++ b/test/core/end2end/fixtures/h2_http_proxy.c
@@ -48,21 +48,24 @@
 #include "src/core/lib/channel/http_server_filter.h"
 #include "src/core/lib/surface/channel.h"
 #include "src/core/lib/surface/server.h"
+#include "test/core/end2end/fixtures/http_proxy.h"
 #include "test/core/util/port.h"
 #include "test/core/util/test_config.h"
 
 typedef struct fullstack_fixture_data {
-  char *localaddr;
+  char *server_addr;
+  grpc_end2end_http_proxy *proxy;
 } fullstack_fixture_data;
 
 static grpc_end2end_test_fixture chttp2_create_fixture_fullstack(
     grpc_channel_args *client_args, grpc_channel_args *server_args) {
   grpc_end2end_test_fixture f;
-  int port = grpc_pick_unused_port_or_die();
-  fullstack_fixture_data *ffd = gpr_malloc(sizeof(fullstack_fixture_data));
   memset(&f, 0, sizeof(f));
 
-  gpr_join_host_port(&ffd->localaddr, "localhost", port);
+  fullstack_fixture_data *ffd = gpr_malloc(sizeof(fullstack_fixture_data));
+  const int server_port = grpc_pick_unused_port_or_die();
+  gpr_join_host_port(&ffd->server_addr, "localhost", server_port);
+  ffd->proxy = grpc_end2end_http_proxy_create();
 
   f.fixture_data = ffd;
   f.cq = grpc_completion_queue_create(NULL);
@@ -73,10 +76,9 @@
 void chttp2_init_client_fullstack(grpc_end2end_test_fixture *f,
                                   grpc_channel_args *client_args) {
   fullstack_fixture_data *ffd = f->fixture_data;
-// FIXME: this requires a separate proxy running at localhost:9999.  need to
-// change this test to provide its own proxy.
   char *target_uri;
-  gpr_asprintf(&target_uri, "%s?http_proxy=127.0.0.1:9999", ffd->localaddr);
+  gpr_asprintf(&target_uri, "%s?http_proxy=%s", ffd->server_addr,
+               grpc_end2end_http_proxy_get_proxy_name(ffd->proxy));
   gpr_log(GPR_INFO, "target_uri: %s", target_uri);
   f->client = grpc_insecure_channel_create(target_uri, client_args, NULL);
   gpr_free(target_uri);
@@ -91,13 +93,14 @@
   }
   f->server = grpc_server_create(server_args, NULL);
   grpc_server_register_completion_queue(f->server, f->cq, NULL);
-  GPR_ASSERT(grpc_server_add_insecure_http2_port(f->server, ffd->localaddr));
+  GPR_ASSERT(grpc_server_add_insecure_http2_port(f->server, ffd->server_addr));
   grpc_server_start(f->server);
 }
 
 void chttp2_tear_down_fullstack(grpc_end2end_test_fixture *f) {
   fullstack_fixture_data *ffd = f->fixture_data;
-  gpr_free(ffd->localaddr);
+  gpr_free(ffd->server_addr);
+  grpc_end2end_http_proxy_destroy(ffd->proxy);
   gpr_free(ffd);
 }
 
diff --git a/test/core/end2end/fixtures/http_proxy.c b/test/core/end2end/fixtures/http_proxy.c
new file mode 100644
index 0000000..a8d68f0
--- /dev/null
+++ b/test/core/end2end/fixtures/http_proxy.c
@@ -0,0 +1,351 @@
+/*
+ *
+ * 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 "test/core/end2end/fixtures/http_proxy.h"
+
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/host_port.h>
+#include <grpc/support/log.h>
+#include <grpc/support/slice_buffer.h>
+#include <grpc/support/string_util.h>
+#include <grpc/support/sync.h>
+//#include <grpc/support/thd.h>
+#include <grpc/support/useful.h>
+
+#include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/http/parser.h"
+#include "src/core/lib/iomgr/closure.h"
+#include "src/core/lib/iomgr/endpoint.h"
+#include "src/core/lib/iomgr/error.h"
+#include "src/core/lib/iomgr/exec_ctx.h"
+#include "src/core/lib/iomgr/pollset.h"
+#include "src/core/lib/iomgr/pollset_set.h"
+#include "src/core/lib/iomgr/resolve_address.h"
+#include "src/core/lib/iomgr/sockaddr_utils.h"
+#include "src/core/lib/iomgr/tcp_client.h"
+#include "src/core/lib/iomgr/tcp_server.h"
+#include "test/core/util/port.h"
+
+//
+// Connection handling
+//
+
+typedef struct connection_data {
+  grpc_endpoint* client_endpoint;
+  grpc_endpoint* server_endpoint;
+
+  grpc_pollset_set* pollset_set;
+
+  grpc_closure on_read_request_done;
+  grpc_closure on_server_connect_done;
+  grpc_closure on_write_response_done;
+  grpc_closure on_client_read_done;
+  grpc_closure on_client_write_done;
+  grpc_closure on_server_read_done;
+  grpc_closure on_server_write_done;
+
+  gpr_slice_buffer client_read_buffer;
+  gpr_slice_buffer client_write_buffer;
+  gpr_slice_buffer server_read_buffer;
+  gpr_slice_buffer server_write_buffer;
+
+  grpc_http_parser http_parser;
+  grpc_http_request http_request;
+} connection_data;
+
+static void connection_data_destroy(grpc_exec_ctx* exec_ctx,
+                                    connection_data* cd) {
+  grpc_endpoint_destroy(exec_ctx, cd->client_endpoint);
+  if (cd->server_endpoint != NULL)
+    grpc_endpoint_destroy(exec_ctx, cd->server_endpoint);
+  grpc_pollset_set_destroy(cd->pollset_set);
+  gpr_slice_buffer_destroy(&cd->client_read_buffer);
+  gpr_slice_buffer_destroy(&cd->client_write_buffer);
+  gpr_slice_buffer_destroy(&cd->server_read_buffer);
+  gpr_slice_buffer_destroy(&cd->server_write_buffer);
+  grpc_http_parser_destroy(&cd->http_parser);
+  grpc_http_request_destroy(&cd->http_request);
+  gpr_free(cd);
+}
+
+static void connection_data_failed(grpc_exec_ctx* exec_ctx,
+                                   connection_data* cd, const char* prefix,
+                                   grpc_error* error) {
+  const char* msg = grpc_error_string(error);
+  gpr_log(GPR_ERROR, "%s: %s", prefix, msg);
+  grpc_error_free_string(msg);
+  GRPC_ERROR_UNREF(error);
+  grpc_endpoint_shutdown(exec_ctx, cd->client_endpoint);
+  if (cd->server_endpoint != NULL)
+    grpc_endpoint_shutdown(exec_ctx, cd->server_endpoint);
+  connection_data_destroy(exec_ctx, cd);
+}
+
+static void on_client_write_done(grpc_exec_ctx* exec_ctx, void* arg,
+                                 grpc_error* error) {
+  connection_data* cd = arg;
+  if (error != GRPC_ERROR_NONE)
+    connection_data_failed(exec_ctx, cd, "HTTP proxy client write", error);
+}
+
+static void on_server_write_done(grpc_exec_ctx* exec_ctx, void* arg,
+                                 grpc_error* error) {
+  connection_data* cd = arg;
+  if (error != GRPC_ERROR_NONE)
+    connection_data_failed(exec_ctx, cd, "HTTP proxy server write", error);
+}
+
+static void on_client_read_done(grpc_exec_ctx* exec_ctx, void* arg,
+                                grpc_error* error) {
+  connection_data* cd = arg;
+  if (error != GRPC_ERROR_NONE) {
+    connection_data_failed(exec_ctx, cd, "HTTP proxy client read", error);
+    return;
+  }
+  gpr_slice_buffer_move_into(&cd->client_read_buffer, &cd->server_write_buffer);
+  grpc_endpoint_write(exec_ctx, cd->server_endpoint, &cd->server_write_buffer,
+                      &cd->on_server_write_done);
+}
+
+static void on_server_read_done(grpc_exec_ctx* exec_ctx, void* arg,
+                                grpc_error* error) {
+  connection_data* cd = arg;
+  if (error != GRPC_ERROR_NONE) {
+    connection_data_failed(exec_ctx, cd, "HTTP proxy server read", error);
+    return;
+  }
+  gpr_slice_buffer_move_into(&cd->server_read_buffer, &cd->client_write_buffer);
+  grpc_endpoint_write(exec_ctx, cd->client_endpoint, &cd->client_write_buffer,
+                      &cd->on_client_write_done);
+}
+
+static void on_write_response_done(grpc_exec_ctx* exec_ctx, void* arg,
+                                   grpc_error* error) {
+  connection_data* cd = arg;
+  if (error != GRPC_ERROR_NONE) {
+    connection_data_failed(exec_ctx, cd, "HTTP proxy write response", error);
+    return;
+  }
+  // Set up proxying.
+  grpc_endpoint_read(exec_ctx, cd->client_endpoint, &cd->client_read_buffer,
+                     &cd->on_client_read_done);
+  grpc_endpoint_read(exec_ctx, cd->server_endpoint, &cd->server_read_buffer,
+                     &cd->on_server_read_done);
+}
+
+static void on_server_connect_done(grpc_exec_ctx* exec_ctx, void* arg,
+                                   grpc_error* error) {
+  connection_data* cd = arg;
+  if (error != GRPC_ERROR_NONE) {
+    connection_data_failed(exec_ctx, cd, "HTTP proxy server connect", error);
+    return;
+  }
+  // We've established a connection, so send back a 200 response code to
+  // the client.
+  gpr_slice slice = gpr_slice_from_copied_string("200 connected\r\n");
+  gpr_slice_buffer_reset_and_unref(&cd->client_write_buffer);
+  gpr_slice_buffer_add(&cd->client_write_buffer, slice);
+  grpc_endpoint_write(exec_ctx, cd->client_endpoint, &cd->client_write_buffer,
+                      &cd->on_write_response_done);
+}
+
+static void on_read_request_done(grpc_exec_ctx* exec_ctx, void* arg,
+                                 grpc_error* error) {
+  connection_data* cd = arg;
+  if (error != GRPC_ERROR_NONE) {
+    connection_data_failed(exec_ctx, cd, "HTTP proxy read request", error);
+    return;
+  }
+  // Read request and feed it to the parser.
+  for (size_t i = 0; i < cd->client_read_buffer.count; ++i) {
+    if (GPR_SLICE_LENGTH(cd->client_read_buffer.slices[i]) > 0) {
+      error = grpc_http_parser_parse(
+          &cd->http_parser, cd->client_read_buffer.slices[i]);
+      if (error != GRPC_ERROR_NONE) {
+        connection_data_failed(exec_ctx, cd, "HTTP proxy request parse",
+                               error);
+        return;
+      }
+    }
+  }
+  gpr_slice_buffer_reset_and_unref(&cd->client_read_buffer);
+  // If we're not done reading the request, read more data.
+  if (cd->http_parser.state != GRPC_HTTP_BODY) {
+    grpc_endpoint_read(exec_ctx, cd->client_endpoint, &cd->client_read_buffer,
+                       &cd->on_read_request_done);
+    return;
+  }
+  // Make sure we got a CONNECT request.
+  if (strcmp(cd->http_request.method, "CONNECT") != 0) {
+    char* msg;
+    gpr_asprintf(&msg, "HTTP proxy got request method %s",
+                 cd->http_request.method);
+    error = GRPC_ERROR_CREATE(msg);
+    gpr_free(msg);
+    connection_data_failed(exec_ctx, cd, "HTTP proxy read request", error);
+    return;
+  }
+  // Resolve address.
+  grpc_resolved_addresses* resolved_addresses = NULL;
+  error = grpc_blocking_resolve_address(cd->http_request.path, "80",
+                                        &resolved_addresses);
+  if (error != GRPC_ERROR_NONE) {
+    connection_data_failed(exec_ctx, cd, "HTTP proxy DNS lookup", error);
+    return;
+  }
+  GPR_ASSERT(resolved_addresses->naddrs >= 1);
+  // Connect to requested address.
+  const gpr_timespec deadline = gpr_time_add(
+      gpr_now(GPR_CLOCK_MONOTONIC), gpr_time_from_seconds(10, GPR_TIMESPAN));
+  grpc_tcp_client_connect(exec_ctx, &cd->on_server_connect_done,
+                          &cd->server_endpoint, cd->pollset_set,
+                          (struct sockaddr*)&resolved_addresses->addrs[0].addr,
+                          resolved_addresses->addrs[0].len, deadline);
+  grpc_resolved_addresses_destroy(resolved_addresses);
+}
+
+static void on_accept(grpc_exec_ctx* exec_ctx, void* arg,
+                      grpc_endpoint* ep, grpc_pollset* accepting_pollset,
+                      grpc_tcp_server_acceptor* acceptor) {
+// FIXME: remove
+gpr_log(GPR_ERROR, "==> on_accept()");
+  // Instantiate connection_data.
+  connection_data* cd = gpr_malloc(sizeof(*cd));
+  memset(cd, 0, sizeof(*cd));
+  cd->client_endpoint = ep;
+  cd->pollset_set = grpc_pollset_set_create();
+  grpc_closure_init(&cd->on_read_request_done, on_read_request_done, cd);
+  grpc_closure_init(&cd->on_server_connect_done, on_server_connect_done, cd);
+  grpc_closure_init(&cd->on_write_response_done, on_write_response_done, cd);
+  grpc_closure_init(&cd->on_client_read_done, on_client_read_done, cd);
+  grpc_closure_init(&cd->on_client_write_done, on_client_write_done, cd);
+  grpc_closure_init(&cd->on_server_read_done, on_server_read_done, cd);
+  grpc_closure_init(&cd->on_server_write_done, on_server_write_done, cd);
+  gpr_slice_buffer_init(&cd->client_read_buffer);
+  gpr_slice_buffer_init(&cd->client_write_buffer);
+  gpr_slice_buffer_init(&cd->server_read_buffer);
+  gpr_slice_buffer_init(&cd->server_write_buffer);
+  grpc_http_parser_init(&cd->http_parser, GRPC_HTTP_REQUEST,
+                        &cd->http_request);
+  grpc_endpoint_read(exec_ctx, cd->client_endpoint, &cd->client_read_buffer,
+                     &cd->on_read_request_done);
+}
+
+//
+// Proxy class
+//
+
+struct grpc_end2end_http_proxy {
+  char* proxy_name;
+//  gpr_thd_id thd;
+  grpc_tcp_server* server;
+  grpc_channel_args* channel_args;
+  gpr_mu* mu;
+  grpc_pollset* pollset;
+};
+
+#if 0
+static void thread_main(void *arg) {
+  //grpc_end2end_http_proxy *proxy = arg;
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+  while (true) {
+    grpc_exec_ctx_flush(&exec_ctx);
+  }
+}
+#endif
+
+grpc_end2end_http_proxy* grpc_end2end_http_proxy_create() {
+  grpc_end2end_http_proxy* proxy = gpr_malloc(sizeof(*proxy));
+  memset(proxy, 0, sizeof(*proxy));
+  // Construct proxy address.
+  const int proxy_port = grpc_pick_unused_port_or_die();
+  gpr_join_host_port(&proxy->proxy_name, "localhost", proxy_port);
+  gpr_log(GPR_INFO, "Proxy address: %s", proxy->proxy_name);
+// FIXME: remove
+gpr_log(GPR_ERROR, "Proxy address: %s", proxy->proxy_name);
+  // Create TCP server.
+  proxy->channel_args = grpc_channel_args_copy(NULL);
+  grpc_error* error = grpc_tcp_server_create(
+      NULL, proxy->channel_args, &proxy->server);
+  GPR_ASSERT(error == GRPC_ERROR_NONE);
+  // Bind to port.
+  struct sockaddr_in addr;
+  memset(&addr, 0, sizeof(addr));
+  addr.sin_family = AF_INET;
+  grpc_sockaddr_set_port((struct sockaddr*)&addr, proxy_port);
+  int port;
+  error = grpc_tcp_server_add_port(
+      proxy->server, (struct sockaddr*)&addr, sizeof(addr), &port);
+  GPR_ASSERT(error == GRPC_ERROR_NONE);
+  GPR_ASSERT(port == proxy_port);
+  // Start server.
+  proxy->pollset = gpr_malloc(grpc_pollset_size());
+  grpc_pollset_init(proxy->pollset, &proxy->mu);
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+  grpc_tcp_server_start(&exec_ctx, proxy->server, &proxy->pollset, 1,
+                        on_accept, NULL);
+  grpc_exec_ctx_finish(&exec_ctx);
+#if 0
+  // Start proxy thread.
+  gpr_thd_options opt = gpr_thd_options_default();
+  gpr_thd_options_set_joinable(&opt);
+  GPR_ASSERT(gpr_thd_new(&proxy->thd, thread_main, proxy, &opt));
+#endif
+  return proxy;
+}
+
+static void destroy_pollset(grpc_exec_ctx *exec_ctx, void *p,
+                            grpc_error *error) {
+  grpc_pollset_destroy(p);
+}
+
+void grpc_end2end_http_proxy_destroy(grpc_end2end_http_proxy* proxy) {
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+  grpc_tcp_server_shutdown_listeners(&exec_ctx, proxy->server);
+  grpc_tcp_server_unref(&exec_ctx, proxy->server);
+//  gpr_thd_join(proxy->thd);
+  gpr_free(proxy->proxy_name);
+  grpc_channel_args_destroy(proxy->channel_args);
+  grpc_closure destroyed;
+  grpc_closure_init(&destroyed, destroy_pollset, &proxy->pollset);
+  grpc_pollset_shutdown(&exec_ctx, proxy->pollset, &destroyed);
+  gpr_free(proxy);
+  grpc_exec_ctx_finish(&exec_ctx);
+}
+
+const char *grpc_end2end_http_proxy_get_proxy_name(
+    grpc_end2end_http_proxy *proxy) {
+  return proxy->proxy_name;
+}
diff --git a/test/core/end2end/fixtures/http_proxy.h b/test/core/end2end/fixtures/http_proxy.h
new file mode 100644
index 0000000..7af2ea9
--- /dev/null
+++ b/test/core/end2end/fixtures/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.
+ *
+ */
+
+typedef struct grpc_end2end_http_proxy grpc_end2end_http_proxy;
+
+grpc_end2end_http_proxy* grpc_end2end_http_proxy_create();
+
+void grpc_end2end_http_proxy_destroy(grpc_end2end_http_proxy* proxy);
+
+const char *grpc_end2end_http_proxy_get_proxy_name(
+    grpc_end2end_http_proxy *proxy);
diff --git a/tools/run_tests/sources_and_headers.json b/tools/run_tests/sources_and_headers.json
index d09aa41..0bc1ab7 100644
--- a/tools/run_tests/sources_and_headers.json
+++ b/tools/run_tests/sources_and_headers.json
@@ -6282,6 +6282,7 @@
     ], 
     "headers": [
       "test/core/end2end/cq_verifier.h", 
+      "test/core/end2end/fixtures/http_proxy.h", 
       "test/core/end2end/fixtures/proxy.h", 
       "test/core/iomgr/endpoint_tests.h", 
       "test/core/util/grpc_profiler.h", 
@@ -6298,6 +6299,8 @@
     "src": [
       "test/core/end2end/cq_verifier.c", 
       "test/core/end2end/cq_verifier.h", 
+      "test/core/end2end/fixtures/http_proxy.c", 
+      "test/core/end2end/fixtures/http_proxy.h", 
       "test/core/end2end/fixtures/proxy.c", 
       "test/core/end2end/fixtures/proxy.h", 
       "test/core/iomgr/endpoint_tests.c", 
diff --git a/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj b/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj
index f0a8f7b..6f1a3f3 100644
--- a/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj
+++ b/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj
@@ -150,6 +150,7 @@
     <ClInclude Include="$(SolutionDir)\..\test\core\end2end\data\ssl_test_data.h" />
     <ClInclude Include="$(SolutionDir)\..\test\core\security\oauth2_utils.h" />
     <ClInclude Include="$(SolutionDir)\..\test\core\end2end\cq_verifier.h" />
+    <ClInclude Include="$(SolutionDir)\..\test\core\end2end\fixtures\http_proxy.h" />
     <ClInclude Include="$(SolutionDir)\..\test\core\end2end\fixtures\proxy.h" />
     <ClInclude Include="$(SolutionDir)\..\test\core\iomgr\endpoint_tests.h" />
     <ClInclude Include="$(SolutionDir)\..\test\core\util\grpc_profiler.h" />
@@ -174,6 +175,8 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\core\end2end\cq_verifier.c">
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\test\core\end2end\fixtures\http_proxy.c">
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\core\end2end\fixtures\proxy.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\core\iomgr\endpoint_tests.c">
diff --git a/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj.filters b/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj.filters
index a1d31eb..45d7677 100644
--- a/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj.filters
@@ -19,6 +19,9 @@
     <ClCompile Include="$(SolutionDir)\..\test\core\end2end\cq_verifier.c">
       <Filter>test\core\end2end</Filter>
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\test\core\end2end\fixtures\http_proxy.c">
+      <Filter>test\core\end2end\fixtures</Filter>
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\core\end2end\fixtures\proxy.c">
       <Filter>test\core\end2end\fixtures</Filter>
     </ClCompile>
@@ -63,6 +66,9 @@
     <ClInclude Include="$(SolutionDir)\..\test\core\end2end\cq_verifier.h">
       <Filter>test\core\end2end</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\test\core\end2end\fixtures\http_proxy.h">
+      <Filter>test\core\end2end\fixtures</Filter>
+    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\test\core\end2end\fixtures\proxy.h">
       <Filter>test\core\end2end\fixtures</Filter>
     </ClInclude>
diff --git a/vsprojects/vcxproj/grpc_test_util_unsecure/grpc_test_util_unsecure.vcxproj b/vsprojects/vcxproj/grpc_test_util_unsecure/grpc_test_util_unsecure.vcxproj
index 33860c4..04d1e58 100644
--- a/vsprojects/vcxproj/grpc_test_util_unsecure/grpc_test_util_unsecure.vcxproj
+++ b/vsprojects/vcxproj/grpc_test_util_unsecure/grpc_test_util_unsecure.vcxproj
@@ -148,6 +148,7 @@
 
   <ItemGroup>
     <ClInclude Include="$(SolutionDir)\..\test\core\end2end\cq_verifier.h" />
+    <ClInclude Include="$(SolutionDir)\..\test\core\end2end\fixtures\http_proxy.h" />
     <ClInclude Include="$(SolutionDir)\..\test\core\end2end\fixtures\proxy.h" />
     <ClInclude Include="$(SolutionDir)\..\test\core\iomgr\endpoint_tests.h" />
     <ClInclude Include="$(SolutionDir)\..\test\core\util\grpc_profiler.h" />
@@ -162,6 +163,8 @@
   <ItemGroup>
     <ClCompile Include="$(SolutionDir)\..\test\core\end2end\cq_verifier.c">
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\test\core\end2end\fixtures\http_proxy.c">
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\core\end2end\fixtures\proxy.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\core\iomgr\endpoint_tests.c">
diff --git a/vsprojects/vcxproj/grpc_test_util_unsecure/grpc_test_util_unsecure.vcxproj.filters b/vsprojects/vcxproj/grpc_test_util_unsecure/grpc_test_util_unsecure.vcxproj.filters
index 372bb2a..0f7072a 100644
--- a/vsprojects/vcxproj/grpc_test_util_unsecure/grpc_test_util_unsecure.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc_test_util_unsecure/grpc_test_util_unsecure.vcxproj.filters
@@ -4,6 +4,9 @@
     <ClCompile Include="$(SolutionDir)\..\test\core\end2end\cq_verifier.c">
       <Filter>test\core\end2end</Filter>
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\test\core\end2end\fixtures\http_proxy.c">
+      <Filter>test\core\end2end\fixtures</Filter>
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\core\end2end\fixtures\proxy.c">
       <Filter>test\core\end2end\fixtures</Filter>
     </ClCompile>
@@ -42,6 +45,9 @@
     <ClInclude Include="$(SolutionDir)\..\test\core\end2end\cq_verifier.h">
       <Filter>test\core\end2end</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\test\core\end2end\fixtures\http_proxy.h">
+      <Filter>test\core\end2end\fixtures</Filter>
+    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\test\core\end2end\fixtures\proxy.h">
       <Filter>test\core\end2end\fixtures</Filter>
     </ClInclude>