Merge pull request #1311 from yang-g/codegen

Clarify some auth test definitions
diff --git a/BUILD b/BUILD
index 916f24e..8bebe1b 100644
--- a/BUILD
+++ b/BUILD
@@ -124,7 +124,7 @@
   srcs = [
     "src/core/httpcli/format_request.h",
     "src/core/httpcli/httpcli.h",
-    "src/core/httpcli/httpcli_security_context.h",
+    "src/core/httpcli/httpcli_security_connector.h",
     "src/core/httpcli/parser.h",
     "src/core/security/auth.h",
     "src/core/security/base64.h",
@@ -132,7 +132,7 @@
     "src/core/security/json_token.h",
     "src/core/security/secure_endpoint.h",
     "src/core/security/secure_transport_setup.h",
-    "src/core/security/security_context.h",
+    "src/core/security/security_connector.h",
     "src/core/tsi/fake_transport_security.h",
     "src/core/tsi/ssl_transport_security.h",
     "src/core/tsi/transport_security.h",
@@ -228,19 +228,18 @@
     "src/core/transport/transport_impl.h",
     "src/core/httpcli/format_request.c",
     "src/core/httpcli/httpcli.c",
-    "src/core/httpcli/httpcli_security_context.c",
+    "src/core/httpcli/httpcli_security_connector.c",
     "src/core/httpcli/parser.c",
     "src/core/security/auth.c",
     "src/core/security/base64.c",
     "src/core/security/credentials.c",
     "src/core/security/credentials_posix.c",
     "src/core/security/credentials_win32.c",
-    "src/core/security/factories.c",
     "src/core/security/google_default_credentials.c",
     "src/core/security/json_token.c",
     "src/core/security/secure_endpoint.c",
     "src/core/security/secure_transport_setup.c",
-    "src/core/security/security_context.c",
+    "src/core/security/security_connector.c",
     "src/core/security/server_secure_chttp2.c",
     "src/core/surface/init_secure.c",
     "src/core/surface/secure_channel_create.c",
diff --git a/Makefile b/Makefile
index e3204fc..4a8ab16 100644
--- a/Makefile
+++ b/Makefile
@@ -2591,19 +2591,18 @@
 LIBGRPC_SRC = \
     src/core/httpcli/format_request.c \
     src/core/httpcli/httpcli.c \
-    src/core/httpcli/httpcli_security_context.c \
+    src/core/httpcli/httpcli_security_connector.c \
     src/core/httpcli/parser.c \
     src/core/security/auth.c \
     src/core/security/base64.c \
     src/core/security/credentials.c \
     src/core/security/credentials_posix.c \
     src/core/security/credentials_win32.c \
-    src/core/security/factories.c \
     src/core/security/google_default_credentials.c \
     src/core/security/json_token.c \
     src/core/security/secure_endpoint.c \
     src/core/security/secure_transport_setup.c \
-    src/core/security/security_context.c \
+    src/core/security/security_connector.c \
     src/core/security/server_secure_chttp2.c \
     src/core/surface/init_secure.c \
     src/core/surface/secure_channel_create.c \
@@ -2740,19 +2739,18 @@
 # otherwise parallel compilation will fail if a source is compiled first.
 src/core/httpcli/format_request.c: $(OPENSSL_DEP)
 src/core/httpcli/httpcli.c: $(OPENSSL_DEP)
-src/core/httpcli/httpcli_security_context.c: $(OPENSSL_DEP)
+src/core/httpcli/httpcli_security_connector.c: $(OPENSSL_DEP)
 src/core/httpcli/parser.c: $(OPENSSL_DEP)
 src/core/security/auth.c: $(OPENSSL_DEP)
 src/core/security/base64.c: $(OPENSSL_DEP)
 src/core/security/credentials.c: $(OPENSSL_DEP)
 src/core/security/credentials_posix.c: $(OPENSSL_DEP)
 src/core/security/credentials_win32.c: $(OPENSSL_DEP)
-src/core/security/factories.c: $(OPENSSL_DEP)
 src/core/security/google_default_credentials.c: $(OPENSSL_DEP)
 src/core/security/json_token.c: $(OPENSSL_DEP)
 src/core/security/secure_endpoint.c: $(OPENSSL_DEP)
 src/core/security/secure_transport_setup.c: $(OPENSSL_DEP)
-src/core/security/security_context.c: $(OPENSSL_DEP)
+src/core/security/security_connector.c: $(OPENSSL_DEP)
 src/core/security/server_secure_chttp2.c: $(OPENSSL_DEP)
 src/core/surface/init_secure.c: $(OPENSSL_DEP)
 src/core/surface/secure_channel_create.c: $(OPENSSL_DEP)
@@ -2905,19 +2903,18 @@
 
 $(OBJDIR)/$(CONFIG)/src/core/httpcli/format_request.o: 
 $(OBJDIR)/$(CONFIG)/src/core/httpcli/httpcli.o: 
-$(OBJDIR)/$(CONFIG)/src/core/httpcli/httpcli_security_context.o: 
+$(OBJDIR)/$(CONFIG)/src/core/httpcli/httpcli_security_connector.o: 
 $(OBJDIR)/$(CONFIG)/src/core/httpcli/parser.o: 
 $(OBJDIR)/$(CONFIG)/src/core/security/auth.o: 
 $(OBJDIR)/$(CONFIG)/src/core/security/base64.o: 
 $(OBJDIR)/$(CONFIG)/src/core/security/credentials.o: 
 $(OBJDIR)/$(CONFIG)/src/core/security/credentials_posix.o: 
 $(OBJDIR)/$(CONFIG)/src/core/security/credentials_win32.o: 
-$(OBJDIR)/$(CONFIG)/src/core/security/factories.o: 
 $(OBJDIR)/$(CONFIG)/src/core/security/google_default_credentials.o: 
 $(OBJDIR)/$(CONFIG)/src/core/security/json_token.o: 
 $(OBJDIR)/$(CONFIG)/src/core/security/secure_endpoint.o: 
 $(OBJDIR)/$(CONFIG)/src/core/security/secure_transport_setup.o: 
-$(OBJDIR)/$(CONFIG)/src/core/security/security_context.o: 
+$(OBJDIR)/$(CONFIG)/src/core/security/security_connector.o: 
 $(OBJDIR)/$(CONFIG)/src/core/security/server_secure_chttp2.o: 
 $(OBJDIR)/$(CONFIG)/src/core/surface/init_secure.o: 
 $(OBJDIR)/$(CONFIG)/src/core/surface/secure_channel_create.o: 
diff --git a/build.json b/build.json
index 58837e2..67ab70a 100644
--- a/build.json
+++ b/build.json
@@ -386,7 +386,7 @@
       "headers": [
         "src/core/httpcli/format_request.h",
         "src/core/httpcli/httpcli.h",
-        "src/core/httpcli/httpcli_security_context.h",
+        "src/core/httpcli/httpcli_security_connector.h",
         "src/core/httpcli/parser.h",
         "src/core/security/auth.h",
         "src/core/security/base64.h",
@@ -394,7 +394,7 @@
         "src/core/security/json_token.h",
         "src/core/security/secure_endpoint.h",
         "src/core/security/secure_transport_setup.h",
-        "src/core/security/security_context.h",
+        "src/core/security/security_connector.h",
         "src/core/tsi/fake_transport_security.h",
         "src/core/tsi/ssl_transport_security.h",
         "src/core/tsi/transport_security.h",
@@ -403,19 +403,18 @@
       "src": [
         "src/core/httpcli/format_request.c",
         "src/core/httpcli/httpcli.c",
-        "src/core/httpcli/httpcli_security_context.c",
+        "src/core/httpcli/httpcli_security_connector.c",
         "src/core/httpcli/parser.c",
         "src/core/security/auth.c",
         "src/core/security/base64.c",
         "src/core/security/credentials.c",
         "src/core/security/credentials_posix.c",
         "src/core/security/credentials_win32.c",
-        "src/core/security/factories.c",
         "src/core/security/google_default_credentials.c",
         "src/core/security/json_token.c",
         "src/core/security/secure_endpoint.c",
         "src/core/security/secure_transport_setup.c",
-        "src/core/security/security_context.c",
+        "src/core/security/security_connector.c",
         "src/core/security/server_secure_chttp2.c",
         "src/core/surface/init_secure.c",
         "src/core/surface/secure_channel_create.c",
@@ -665,6 +664,9 @@
         "test/cpp/qps/server_async.cc",
         "test/cpp/qps/server_sync.cc",
         "test/cpp/qps/timer.cc"
+      ],
+      "deps": [
+        "grpc_test_util"
       ]
     },
     {
diff --git a/src/core/httpcli/httpcli.c b/src/core/httpcli/httpcli.c
index d2cf09a..fe7ea6a 100644
--- a/src/core/httpcli/httpcli.c
+++ b/src/core/httpcli/httpcli.c
@@ -40,9 +40,8 @@
 #include "src/core/iomgr/resolve_address.h"
 #include "src/core/iomgr/tcp_client.h"
 #include "src/core/httpcli/format_request.h"
-#include "src/core/httpcli/httpcli_security_context.h"
+#include "src/core/httpcli/httpcli_security_connector.h"
 #include "src/core/httpcli/parser.h"
-#include "src/core/security/security_context.h"
 #include "src/core/security/secure_transport_setup.h"
 #include "src/core/support/string.h"
 #include <grpc/support/alloc.h>
@@ -180,7 +179,7 @@
   }
   req->ep = tcp;
   if (req->use_ssl) {
-    grpc_channel_security_context *ctx = NULL;
+    grpc_channel_security_connector *sc = NULL;
     const unsigned char *pem_root_certs = NULL;
     size_t pem_root_certs_size = grpc_get_default_ssl_roots(&pem_root_certs);
     if (pem_root_certs == NULL || pem_root_certs_size == 0) {
@@ -188,12 +187,12 @@
       finish(req, 0);
       return;
     }
-    GPR_ASSERT(grpc_httpcli_ssl_channel_security_context_create(
-                   pem_root_certs, pem_root_certs_size, req->host, &ctx) ==
+    GPR_ASSERT(grpc_httpcli_ssl_channel_security_connector_create(
+                   pem_root_certs, pem_root_certs_size, req->host, &sc) ==
                GRPC_SECURITY_OK);
-    grpc_setup_secure_transport(&ctx->base, tcp, on_secure_transport_setup_done,
+    grpc_setup_secure_transport(&sc->base, tcp, on_secure_transport_setup_done,
                                 req);
-    grpc_security_context_unref(&ctx->base);
+    grpc_security_connector_unref(&sc->base);
   } else {
     start_write(req);
   }
diff --git a/src/core/httpcli/httpcli_security_context.c b/src/core/httpcli/httpcli_security_connector.c
similarity index 79%
rename from src/core/httpcli/httpcli_security_context.c
rename to src/core/httpcli/httpcli_security_connector.c
index e97752b..6eed5ea 100644
--- a/src/core/httpcli/httpcli_security_context.c
+++ b/src/core/httpcli/httpcli_security_connector.c
@@ -31,7 +31,7 @@
  *
  */
 
-#include "src/core/httpcli/httpcli_security_context.h"
+#include "src/core/httpcli/httpcli_security_connector.h"
 
 #include <string.h>
 
@@ -42,25 +42,25 @@
 #include "src/core/tsi/ssl_transport_security.h"
 
 typedef struct {
-  grpc_channel_security_context base;
+  grpc_channel_security_connector base;
   tsi_ssl_handshaker_factory *handshaker_factory;
   char *secure_peer_name;
-} grpc_httpcli_ssl_channel_security_context;
+} grpc_httpcli_ssl_channel_security_connector;
 
-static void httpcli_ssl_destroy(grpc_security_context *ctx) {
-  grpc_httpcli_ssl_channel_security_context *c =
-      (grpc_httpcli_ssl_channel_security_context *)ctx;
+static void httpcli_ssl_destroy(grpc_security_connector *sc) {
+  grpc_httpcli_ssl_channel_security_connector *c =
+      (grpc_httpcli_ssl_channel_security_connector *)sc;
   if (c->handshaker_factory != NULL) {
     tsi_ssl_handshaker_factory_destroy(c->handshaker_factory);
   }
   if (c->secure_peer_name != NULL) gpr_free(c->secure_peer_name);
-  gpr_free(ctx);
+  gpr_free(sc);
 }
 
 static grpc_security_status httpcli_ssl_create_handshaker(
-    grpc_security_context *ctx, tsi_handshaker **handshaker) {
-  grpc_httpcli_ssl_channel_security_context *c =
-      (grpc_httpcli_ssl_channel_security_context *)ctx;
+    grpc_security_connector *sc, tsi_handshaker **handshaker) {
+  grpc_httpcli_ssl_channel_security_connector *c =
+      (grpc_httpcli_ssl_channel_security_connector *)sc;
   tsi_result result = TSI_OK;
   if (c->handshaker_factory == NULL) return GRPC_SECURITY_ERROR;
   result = tsi_ssl_handshaker_factory_create_handshaker(
@@ -73,12 +73,12 @@
   return GRPC_SECURITY_OK;
 }
 
-static grpc_security_status httpcli_ssl_check_peer(grpc_security_context *ctx,
+static grpc_security_status httpcli_ssl_check_peer(grpc_security_connector *sc,
                                                    tsi_peer peer,
                                                    grpc_security_check_cb cb,
                                                    void *user_data) {
-  grpc_httpcli_ssl_channel_security_context *c =
-      (grpc_httpcli_ssl_channel_security_context *)ctx;
+  grpc_httpcli_ssl_channel_security_connector *c =
+      (grpc_httpcli_ssl_channel_security_connector *)sc;
   grpc_security_status status = GRPC_SECURITY_OK;
 
   /* Check the peer name. */
@@ -92,14 +92,14 @@
   return status;
 }
 
-static grpc_security_context_vtable httpcli_ssl_vtable = {
+static grpc_security_connector_vtable httpcli_ssl_vtable = {
     httpcli_ssl_destroy, httpcli_ssl_create_handshaker, httpcli_ssl_check_peer};
 
-grpc_security_status grpc_httpcli_ssl_channel_security_context_create(
+grpc_security_status grpc_httpcli_ssl_channel_security_connector_create(
     const unsigned char *pem_root_certs, size_t pem_root_certs_size,
-    const char *secure_peer_name, grpc_channel_security_context **ctx) {
+    const char *secure_peer_name, grpc_channel_security_connector **sc) {
   tsi_result result = TSI_OK;
-  grpc_httpcli_ssl_channel_security_context *c;
+  grpc_httpcli_ssl_channel_security_connector *c;
 
   if (secure_peer_name != NULL && pem_root_certs == NULL) {
     gpr_log(GPR_ERROR,
@@ -107,8 +107,8 @@
     return GRPC_SECURITY_ERROR;
   }
 
-  c = gpr_malloc(sizeof(grpc_httpcli_ssl_channel_security_context));
-  memset(c, 0, sizeof(grpc_httpcli_ssl_channel_security_context));
+  c = gpr_malloc(sizeof(grpc_httpcli_ssl_channel_security_connector));
+  memset(c, 0, sizeof(grpc_httpcli_ssl_channel_security_connector));
 
   gpr_ref_init(&c->base.base.refcount, 1);
   c->base.base.is_client_side = 1;
@@ -123,9 +123,9 @@
     gpr_log(GPR_ERROR, "Handshaker factory creation failed with %s.",
             tsi_result_to_string(result));
     httpcli_ssl_destroy(&c->base.base);
-    *ctx = NULL;
+    *sc = NULL;
     return GRPC_SECURITY_ERROR;
   }
-  *ctx = &c->base;
+  *sc = &c->base;
   return GRPC_SECURITY_OK;
 }
diff --git a/src/core/httpcli/httpcli_security_context.h b/src/core/httpcli/httpcli_security_connector.h
similarity index 80%
rename from src/core/httpcli/httpcli_security_context.h
rename to src/core/httpcli/httpcli_security_connector.h
index a776828..c50f259 100644
--- a/src/core/httpcli/httpcli_security_context.h
+++ b/src/core/httpcli/httpcli_security_connector.h
@@ -31,13 +31,13 @@
  *
  */
 
-#ifndef GRPC_INTERNAL_CORE_HTTPCLI_HTTPCLI_SECURITY_CONTEXT_H
-#define GRPC_INTERNAL_CORE_HTTPCLI_HTTPCLI_SECURITY_CONTEXT_H
+#ifndef GRPC_INTERNAL_CORE_HTTPCLI_HTTPCLI_SECURITY_CONNECTOR_H
+#define GRPC_INTERNAL_CORE_HTTPCLI_HTTPCLI_SECURITY_CONNECTOR_H
 
-#include "src/core/security/security_context.h"
+#include "src/core/security/security_connector.h"
 
-grpc_security_status grpc_httpcli_ssl_channel_security_context_create(
+grpc_security_status grpc_httpcli_ssl_channel_security_connector_create(
     const unsigned char *pem_root_certs, size_t pem_root_certs_size,
-    const char *secure_peer_name, grpc_channel_security_context **ctx);
+    const char *secure_peer_name, grpc_channel_security_connector **sc);
 
-#endif  /* GRPC_INTERNAL_CORE_HTTPCLI_HTTPCLI_SECURITY_CONTEXT_H */
+#endif  /* GRPC_INTERNAL_CORE_HTTPCLI_HTTPCLI_SECURITY_CONNECTOR_H */
diff --git a/src/core/security/auth.c b/src/core/security/auth.c
index 5fc6d27..130698c 100644
--- a/src/core/security/auth.c
+++ b/src/core/security/auth.c
@@ -40,7 +40,7 @@
 
 #include "src/core/support/string.h"
 #include "src/core/channel/channel_stack.h"
-#include "src/core/security/security_context.h"
+#include "src/core/security/security_connector.h"
 #include "src/core/security/credentials.h"
 #include "src/core/surface/call.h"
 
@@ -54,7 +54,7 @@
 
 /* We can have a per-channel credentials. */
 typedef struct {
-  grpc_channel_security_context *security_context;
+  grpc_channel_security_connector *security_connector;
   grpc_mdctx *md_ctx;
   grpc_mdstr *authority_string;
   grpc_mdstr *path_string;
@@ -126,7 +126,7 @@
   channel_data *channeld = elem->channel_data;
 
   grpc_credentials *channel_creds =
-      channeld->security_context->request_metadata_creds;
+      channeld->security_connector->request_metadata_creds;
   /* TODO(jboeuf):
      Decide on the policy in this case:
      - populate both channel and call?
@@ -138,7 +138,7 @@
   if (channel_creds != NULL &&
       grpc_credentials_has_request_metadata(channel_creds)) {
     char *service_url =
-        build_service_url(channeld->security_context->base.url_scheme, calld);
+        build_service_url(channeld->security_connector->base.url_scheme, calld);
     calld->op = *op; /* Copy op (originates from the caller's stack). */
     grpc_credentials_get_request_metadata(channel_creds, service_url,
                                           on_credentials_metadata, elem);
@@ -193,8 +193,8 @@
         grpc_security_status status;
         const char *call_host = grpc_mdstr_as_c_string(calld->host);
         calld->op = *op; /* Copy op (originates from the caller's stack). */
-        status = grpc_channel_security_context_check_call_host(
-            channeld->security_context, call_host, on_host_checked, elem);
+        status = grpc_channel_security_connector_check_call_host(
+            channeld->security_connector, call_host, on_host_checked, elem);
         if (status != GRPC_SECURITY_OK) {
           if (status == GRPC_SECURITY_ERROR) {
             char *error_msg;
@@ -255,7 +255,7 @@
                               const grpc_channel_args *args,
                               grpc_mdctx *metadata_context, int is_first,
                               int is_last) {
-  grpc_security_context *ctx = grpc_find_security_context_in_args(args);
+  grpc_security_connector *ctx = grpc_find_security_connector_in_args(args);
   /* grab pointers to our data from the channel element */
   channel_data *channeld = elem->channel_data;
 
@@ -268,23 +268,24 @@
 
   /* initialize members */
   GPR_ASSERT(ctx->is_client_side);
-  channeld->security_context =
-      (grpc_channel_security_context *)grpc_security_context_ref(ctx);
+  channeld->security_connector =
+      (grpc_channel_security_connector *)grpc_security_connector_ref(ctx);
   channeld->md_ctx = metadata_context;
   channeld->authority_string =
       grpc_mdstr_from_string(channeld->md_ctx, ":authority");
   channeld->path_string = grpc_mdstr_from_string(channeld->md_ctx, ":path");
   channeld->error_msg_key =
       grpc_mdstr_from_string(channeld->md_ctx, "grpc-message");
-  channeld->status_key = grpc_mdstr_from_string(channeld->md_ctx, "grpc-status");
+  channeld->status_key =
+      grpc_mdstr_from_string(channeld->md_ctx, "grpc-status");
 }
 
 /* Destructor for channel data */
 static void destroy_channel_elem(grpc_channel_element *elem) {
   /* grab pointers to our data from the channel element */
   channel_data *channeld = elem->channel_data;
-  grpc_channel_security_context *ctx = channeld->security_context;
-  if (ctx != NULL) grpc_security_context_unref(&ctx->base);
+  grpc_channel_security_connector *ctx = channeld->security_connector;
+  if (ctx != NULL) grpc_security_connector_unref(&ctx->base);
   if (channeld->authority_string != NULL) {
     grpc_mdstr_unref(channeld->authority_string);
   }
@@ -300,6 +301,5 @@
 }
 
 const grpc_channel_filter grpc_client_auth_filter = {
-    call_op,           channel_op,           sizeof(call_data),
-    init_call_elem,    destroy_call_elem,    sizeof(channel_data),
-    init_channel_elem, destroy_channel_elem, "auth"};
+    call_op, channel_op, sizeof(call_data), init_call_elem, destroy_call_elem,
+    sizeof(channel_data), init_channel_elem, destroy_channel_elem, "auth"};
diff --git a/src/core/security/credentials.c b/src/core/security/credentials.c
index e6d2e9e..f6366f0 100644
--- a/src/core/security/credentials.c
+++ b/src/core/security/credentials.c
@@ -36,11 +36,14 @@
 #include <string.h>
 #include <stdio.h>
 
+#include "src/core/channel/channel_args.h"
+#include "src/core/channel/http_client_filter.h"
 #include "src/core/json/json.h"
 #include "src/core/httpcli/httpcli.h"
 #include "src/core/iomgr/iomgr.h"
 #include "src/core/security/json_token.h"
 #include "src/core/support/string.h"
+
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/sync.h>
@@ -111,9 +114,33 @@
   creds->vtable->get_request_metadata(creds, service_url, cb, user_data);
 }
 
-grpc_mdctx *grpc_credentials_get_metadata_context(grpc_credentials *creds) {
-  if (creds == NULL) return NULL;
-  return creds->vtable->get_metadata_context(creds);
+grpc_mdctx *grpc_credentials_get_or_create_metadata_context(
+    grpc_credentials *creds) {
+  grpc_mdctx *mdctx = NULL;
+  if (creds != NULL && creds->vtable->get_metadata_context != NULL) {
+    mdctx = creds->vtable->get_metadata_context(creds);
+  }
+  if (mdctx == NULL) {
+    return grpc_mdctx_create();
+  } else {
+    grpc_mdctx_ref(mdctx);
+    return mdctx;
+  }
+}
+
+grpc_security_status grpc_credentials_create_security_connector(
+    grpc_credentials *creds, const char *target, const grpc_channel_args *args,
+    grpc_credentials *request_metadata_creds,
+    grpc_channel_security_connector **sc, grpc_channel_args **new_args) {
+  *new_args = NULL;
+  if (creds == NULL || creds->vtable->create_security_connector == NULL ||
+      grpc_credentials_has_request_metadata_only(creds)) {
+    gpr_log(GPR_ERROR,
+            "Invalid credentials for creating a security connector.");
+    return GRPC_SECURITY_ERROR;
+  }
+  return creds->vtable->create_security_connector(
+      creds, target, args, request_metadata_creds, sc, new_args);
 }
 
 void grpc_server_credentials_release(grpc_server_credentials *creds) {
@@ -121,6 +148,15 @@
   creds->vtable->destroy(creds);
 }
 
+grpc_security_status grpc_server_credentials_create_security_connector(
+    grpc_server_credentials *creds, grpc_security_connector **sc) {
+  if (creds == NULL || creds->vtable->create_security_connector == NULL) {
+    gpr_log(GPR_ERROR, "Server credentials cannot create security context.");
+    return GRPC_SECURITY_ERROR;
+  }
+  return creds->vtable->create_security_connector(creds, sc);
+}
+
 /* -- Ssl credentials. -- */
 
 typedef struct {
@@ -176,31 +212,48 @@
   return NULL;
 }
 
+static grpc_security_status ssl_create_security_connector(
+    grpc_credentials *creds, const char *target, const grpc_channel_args *args,
+    grpc_credentials *request_metadata_creds,
+    grpc_channel_security_connector **sc, grpc_channel_args **new_args) {
+  grpc_ssl_credentials *c = (grpc_ssl_credentials *)creds;
+  grpc_security_status status = GRPC_SECURITY_OK;
+  size_t i = 0;
+  const char *overridden_target_name = NULL;
+  grpc_arg arg;
+
+  for (i = 0; args && i < args->num_args; i++) {
+    grpc_arg *arg = &args->args[i];
+    if (strcmp(arg->key, GRPC_SSL_TARGET_NAME_OVERRIDE_ARG) == 0 &&
+        arg->type == GRPC_ARG_STRING) {
+      overridden_target_name = arg->value.string;
+      break;
+    }
+  }
+  status = grpc_ssl_channel_security_connector_create(
+      request_metadata_creds, &c->config, target, overridden_target_name, sc);
+  if (status != GRPC_SECURITY_OK) {
+    return status;
+  }
+  arg.type = GRPC_ARG_STRING;
+  arg.key = GRPC_ARG_HTTP2_SCHEME;
+  arg.value.string = "https";
+  *new_args = grpc_channel_args_copy_and_add(args, &arg);
+  return status;
+}
+
+static grpc_security_status ssl_server_create_security_connector(
+    grpc_server_credentials *creds, grpc_security_connector **sc) {
+  grpc_ssl_server_credentials *c = (grpc_ssl_server_credentials *)creds;
+  return grpc_ssl_server_security_connector_create(&c->config, sc);
+}
+
 static grpc_credentials_vtable ssl_vtable = {
     ssl_destroy, ssl_has_request_metadata, ssl_has_request_metadata_only,
-    ssl_get_metadata_context, NULL};
+    ssl_get_metadata_context, NULL, ssl_create_security_connector};
 
-static grpc_server_credentials_vtable ssl_server_vtable = {ssl_server_destroy};
-
-const grpc_ssl_config *grpc_ssl_credentials_get_config(
-    const grpc_credentials *creds) {
-  if (creds == NULL || strcmp(creds->type, GRPC_CREDENTIALS_TYPE_SSL)) {
-    return NULL;
-  } else {
-    grpc_ssl_credentials *c = (grpc_ssl_credentials *)creds;
-    return &c->config;
-  }
-}
-
-const grpc_ssl_server_config *grpc_ssl_server_credentials_get_config(
-    const grpc_server_credentials *creds) {
-  if (creds == NULL || strcmp(creds->type, GRPC_CREDENTIALS_TYPE_SSL)) {
-    return NULL;
-  } else {
-    grpc_ssl_server_credentials *c = (grpc_ssl_server_credentials *)creds;
-    return &c->config;
-  }
-}
+static grpc_server_credentials_vtable ssl_server_vtable = {
+    ssl_server_destroy, ssl_server_create_security_connector};
 
 static void ssl_copy_key_material(const char *input, unsigned char **output,
                                   size_t *output_size) {
@@ -388,7 +441,7 @@
 
 static grpc_credentials_vtable jwt_vtable = {
     jwt_destroy, jwt_has_request_metadata, jwt_has_request_metadata_only,
-    jwt_get_metadata_context, jwt_get_request_metadata};
+    jwt_get_metadata_context, jwt_get_request_metadata, NULL};
 
 grpc_credentials *grpc_jwt_credentials_create(const char *json_key,
                                               gpr_timespec token_lifetime) {
@@ -613,7 +666,7 @@
     oauth2_token_fetcher_destroy, oauth2_token_fetcher_has_request_metadata,
     oauth2_token_fetcher_has_request_metadata_only,
     oauth2_token_fetcher_get_metadata_context,
-    oauth2_token_fetcher_get_request_metadata};
+    oauth2_token_fetcher_get_request_metadata, NULL};
 
 static void compute_engine_fetch_oauth2(
     grpc_credentials_metadata_request *metadata_req,
@@ -657,7 +710,7 @@
     service_account_destroy, oauth2_token_fetcher_has_request_metadata,
     oauth2_token_fetcher_has_request_metadata_only,
     oauth2_token_fetcher_get_metadata_context,
-    oauth2_token_fetcher_get_request_metadata};
+    oauth2_token_fetcher_get_request_metadata, NULL};
 
 static void service_account_fetch_oauth2(
     grpc_credentials_metadata_request *metadata_req,
@@ -731,7 +784,7 @@
     refresh_token_destroy, oauth2_token_fetcher_has_request_metadata,
     oauth2_token_fetcher_has_request_metadata_only,
     oauth2_token_fetcher_get_metadata_context,
-    oauth2_token_fetcher_get_request_metadata};
+    oauth2_token_fetcher_get_request_metadata, NULL};
 
 static void refresh_token_fetch_oauth2(
     grpc_credentials_metadata_request *metadata_req,
@@ -834,7 +887,7 @@
 static grpc_credentials_vtable fake_oauth2_vtable = {
     fake_oauth2_destroy, fake_oauth2_has_request_metadata,
     fake_oauth2_has_request_metadata_only, fake_oauth2_get_metadata_context,
-    fake_oauth2_get_request_metadata};
+    fake_oauth2_get_request_metadata, NULL};
 
 grpc_credentials *grpc_fake_oauth2_credentials_create(
     const char *token_md_value, int is_async) {
@@ -878,15 +931,33 @@
   return NULL;
 }
 
+static grpc_security_status
+fake_transport_security_create_security_connector(
+    grpc_credentials *c, const char *target, const grpc_channel_args *args,
+    grpc_credentials *request_metadata_creds,
+    grpc_channel_security_connector **sc, grpc_channel_args **new_args) {
+  *sc = grpc_fake_channel_security_connector_create(request_metadata_creds, 1);
+  return GRPC_SECURITY_OK;
+}
+
+static grpc_security_status
+fake_transport_security_server_create_security_connector(
+    grpc_server_credentials *c, grpc_security_connector **sc) {
+  *sc = grpc_fake_server_security_connector_create();
+  return GRPC_SECURITY_OK;
+}
+
 static grpc_credentials_vtable fake_transport_security_credentials_vtable = {
     fake_transport_security_credentials_destroy,
     fake_transport_security_has_request_metadata,
     fake_transport_security_has_request_metadata_only,
-    fake_transport_security_get_metadata_context, NULL};
+    fake_transport_security_get_metadata_context, NULL,
+    fake_transport_security_create_security_connector};
 
 static grpc_server_credentials_vtable
     fake_transport_security_server_credentials_vtable = {
-        fake_transport_security_server_credentials_destroy};
+        fake_transport_security_server_credentials_destroy,
+        fake_transport_security_server_create_security_connector};
 
 grpc_credentials *grpc_fake_transport_security_credentials_create(void) {
   grpc_credentials *c = gpr_malloc(sizeof(grpc_credentials));
@@ -911,6 +982,7 @@
 typedef struct {
   grpc_credentials base;
   grpc_credentials_array inner;
+  grpc_credentials *connector_creds;
 } grpc_composite_credentials;
 
 typedef struct {
@@ -1038,7 +1110,10 @@
   size_t i;
   for (i = 0; i < c->inner.num_creds; i++) {
     grpc_credentials *inner_creds = c->inner.creds_array[i];
-    grpc_mdctx *inner_ctx = grpc_credentials_get_metadata_context(inner_creds);
+    grpc_mdctx *inner_ctx = NULL;
+    if (inner_creds->vtable->get_metadata_context != NULL) {
+      inner_ctx = inner_creds->vtable->get_metadata_context(inner_creds);
+    }
     if (inner_ctx) {
       GPR_ASSERT(ctx == NULL &&
                  "can only have one metadata context per composite credential");
@@ -1048,10 +1123,24 @@
   return ctx;
 }
 
+static grpc_security_status composite_create_security_connector(
+    grpc_credentials *creds, const char *target, const grpc_channel_args *args,
+    grpc_credentials *request_metadata_creds,
+    grpc_channel_security_connector **sc, grpc_channel_args **new_args) {
+  grpc_composite_credentials *c = (grpc_composite_credentials *)creds;
+  if (c->connector_creds == NULL) {
+    gpr_log(GPR_ERROR,
+            "Cannot create security connector, missing connector credentials.");
+    return GRPC_SECURITY_ERROR;
+  }
+  return grpc_credentials_create_security_connector(c->connector_creds, target,
+                                                    args, creds, sc, new_args);
+}
+
 static grpc_credentials_vtable composite_credentials_vtable = {
     composite_destroy, composite_has_request_metadata,
     composite_has_request_metadata_only, composite_get_metadata_context,
-    composite_get_request_metadata};
+    composite_get_request_metadata, composite_create_security_connector};
 
 static grpc_credentials_array get_creds_array(grpc_credentials **creds_addr) {
   grpc_credentials_array result;
@@ -1067,6 +1156,7 @@
 grpc_credentials *grpc_composite_credentials_create(grpc_credentials *creds1,
                                                     grpc_credentials *creds2) {
   size_t i;
+  size_t creds_array_byte_size;
   grpc_credentials_array creds1_array;
   grpc_credentials_array creds2_array;
   grpc_composite_credentials *c;
@@ -1080,16 +1170,39 @@
   creds1_array = get_creds_array(&creds1);
   creds2_array = get_creds_array(&creds2);
   c->inner.num_creds = creds1_array.num_creds + creds2_array.num_creds;
-  c->inner.creds_array =
-      gpr_malloc(c->inner.num_creds * sizeof(grpc_credentials *));
+  creds_array_byte_size = c->inner.num_creds * sizeof(grpc_credentials *);
+  c->inner.creds_array = gpr_malloc(creds_array_byte_size);
+  memset(c->inner.creds_array, 0, creds_array_byte_size);
   for (i = 0; i < creds1_array.num_creds; i++) {
-    c->inner.creds_array[i] = grpc_credentials_ref(creds1_array.creds_array[i]);
+    grpc_credentials *cur_creds = creds1_array.creds_array[i];
+    if (!grpc_credentials_has_request_metadata_only(cur_creds)) {
+      if (c->connector_creds == NULL) {
+        c->connector_creds = cur_creds;
+      } else {
+        gpr_log(GPR_ERROR, "Cannot compose multiple connector credentials.");
+        goto fail;
+      }
+    }
+    c->inner.creds_array[i] = grpc_credentials_ref(cur_creds);
   }
   for (i = 0; i < creds2_array.num_creds; i++) {
+    grpc_credentials *cur_creds = creds2_array.creds_array[i];
+    if (!grpc_credentials_has_request_metadata_only(cur_creds)) {
+      if (c->connector_creds == NULL) {
+        c->connector_creds = cur_creds;
+      } else {
+        gpr_log(GPR_ERROR, "Cannot compose multiple connector credentials.");
+        goto fail;
+      }
+    }
     c->inner.creds_array[i + creds1_array.num_creds] =
-        grpc_credentials_ref(creds2_array.creds_array[i]);
+        grpc_credentials_ref(cur_creds);
   }
   return &c->base;
+
+fail:
+  grpc_credentials_unref(&c->base);
+  return NULL;
 }
 
 const grpc_credentials_array *grpc_composite_credentials_get_credentials(
@@ -1163,7 +1276,7 @@
 
 static grpc_credentials_vtable iam_vtable = {
     iam_destroy, iam_has_request_metadata, iam_has_request_metadata_only,
-    iam_get_metadata_context, iam_get_request_metadata};
+    iam_get_metadata_context, iam_get_request_metadata, NULL};
 
 grpc_credentials *grpc_iam_credentials_create(const char *token,
                                               const char *authority_selector) {
diff --git a/src/core/security/credentials.h b/src/core/security/credentials.h
index 562b3fa..87c773e 100644
--- a/src/core/security/credentials.h
+++ b/src/core/security/credentials.h
@@ -39,6 +39,8 @@
 #include <grpc/grpc_security.h>
 #include <grpc/support/sync.h>
 
+#include "src/core/security/security_connector.h"
+
 struct grpc_httpcli_response;
 
 /* --- Constants. --- */
@@ -99,6 +101,11 @@
                                const char *service_url,
                                grpc_credentials_metadata_cb cb,
                                void *user_data);
+  grpc_security_status (*create_security_connector)(
+      grpc_credentials *c, const char *target, const grpc_channel_args *args,
+      grpc_credentials *request_metadata_creds,
+      grpc_channel_security_connector **sc, grpc_channel_args **new_args);
+
 } grpc_credentials_vtable;
 
 struct grpc_credentials {
@@ -115,19 +122,20 @@
                                            const char *service_url,
                                            grpc_credentials_metadata_cb cb,
                                            void *user_data);
-grpc_mdctx *grpc_credentials_get_metadata_context(grpc_credentials *creds);
 
-typedef struct {
-  unsigned char *pem_private_key;
-  size_t pem_private_key_size;
-  unsigned char *pem_cert_chain;
-  size_t pem_cert_chain_size;
-  unsigned char *pem_root_certs;
-  size_t pem_root_certs_size;
-} grpc_ssl_config;
+/* Gets the mdctx from the credentials and increase the refcount if it exists,
+   otherwise, create a new one. */
+grpc_mdctx *grpc_credentials_get_or_create_metadata_context(
+    grpc_credentials *creds);
 
-const grpc_ssl_config *grpc_ssl_credentials_get_config(
-    const grpc_credentials *ssl_creds);
+/* Creates a security connector for the channel. May also create new channel
+   args for the channel to be used in place of the passed in const args if
+   returned non NULL. In that case the caller is responsible for destroying
+   new_args after channel creation. */
+grpc_security_status grpc_credentials_create_security_connector(
+    grpc_credentials *creds, const char *target, const grpc_channel_args *args,
+    grpc_credentials *request_metadata_creds,
+    grpc_channel_security_connector **sc, grpc_channel_args **new_args);
 
 typedef struct {
   grpc_credentials **creds_array;
@@ -159,6 +167,8 @@
 
 typedef struct {
   void (*destroy)(grpc_server_credentials *c);
+  grpc_security_status (*create_security_connector)(
+      grpc_server_credentials *c, grpc_security_connector **sc);
 } grpc_server_credentials_vtable;
 
 struct grpc_server_credentials {
@@ -166,17 +176,7 @@
   const char *type;
 };
 
-typedef struct {
-  unsigned char **pem_private_keys;
-  size_t *pem_private_keys_sizes;
-  unsigned char **pem_cert_chains;
-  size_t *pem_cert_chains_sizes;
-  size_t num_key_cert_pairs;
-  unsigned char *pem_root_certs;
-  size_t pem_root_certs_size;
-} grpc_ssl_server_config;
-
-const grpc_ssl_server_config *grpc_ssl_server_credentials_get_config(
-    const grpc_server_credentials *ssl_creds);
+grpc_security_status grpc_server_credentials_create_security_connector(
+    grpc_server_credentials *creds, grpc_security_connector **sc);
 
 #endif  /* GRPC_INTERNAL_CORE_SECURITY_CREDENTIALS_H */
diff --git a/src/core/security/factories.c b/src/core/security/factories.c
deleted file mode 100644
index 3d9216a..0000000
--- a/src/core/security/factories.c
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- *
- * Copyright 2015, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include <string.h>
-
-#include <grpc/grpc.h>
-#include "src/core/security/credentials.h"
-#include "src/core/security/security_context.h"
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-#include <grpc/support/useful.h>
-
-grpc_channel *grpc_secure_channel_create(grpc_credentials *creds,
-                                         const char *target,
-                                         const grpc_channel_args *args) {
-  grpc_secure_channel_factory factories[] = {
-      {GRPC_CREDENTIALS_TYPE_SSL, grpc_ssl_channel_create},
-      {GRPC_CREDENTIALS_TYPE_FAKE_TRANSPORT_SECURITY,
-       grpc_fake_transport_security_channel_create}};
-  return grpc_secure_channel_create_with_factories(
-      factories, GPR_ARRAY_SIZE(factories), creds, target, args);
-}
-
-grpc_security_status grpc_server_security_context_create(
-    grpc_server_credentials *creds, grpc_security_context **ctx) {
-  grpc_security_status status = GRPC_SECURITY_ERROR;
-
-  *ctx = NULL;
-  if (strcmp(creds->type, GRPC_CREDENTIALS_TYPE_SSL) == 0) {
-    status = grpc_ssl_server_security_context_create(
-        grpc_ssl_server_credentials_get_config(creds), ctx);
-  } else if (strcmp(creds->type,
-                    GRPC_CREDENTIALS_TYPE_FAKE_TRANSPORT_SECURITY) == 0) {
-    *ctx = grpc_fake_server_security_context_create();
-    status = GRPC_SECURITY_OK;
-  }
-  return status;
-}
diff --git a/src/core/security/secure_transport_setup.c b/src/core/security/secure_transport_setup.c
index f57d221..3e1db9a 100644
--- a/src/core/security/secure_transport_setup.c
+++ b/src/core/security/secure_transport_setup.c
@@ -43,7 +43,7 @@
 #define GRPC_INITIAL_HANDSHAKE_BUFFER_SIZE 256
 
 typedef struct {
-  grpc_security_context *ctx;
+  grpc_security_connector *connector;
   tsi_handshaker *handshaker;
   unsigned char *handshake_buffer;
   size_t handshake_buffer_size;
@@ -74,7 +74,7 @@
   if (s->handshaker != NULL) tsi_handshaker_destroy(s->handshaker);
   if (s->handshake_buffer != NULL) gpr_free(s->handshake_buffer);
   gpr_slice_buffer_destroy(&s->left_overs);
-  grpc_security_context_unref(s->ctx);
+  grpc_security_connector_unref(s->connector);
   gpr_free(s);
 }
 
@@ -112,8 +112,8 @@
     secure_transport_setup_done(s, 0);
     return;
   }
-  peer_status =
-      grpc_security_context_check_peer(s->ctx, peer, on_peer_checked, s);
+  peer_status = grpc_security_connector_check_peer(s->connector, peer,
+                                                   on_peer_checked, s);
   if (peer_status == GRPC_SECURITY_ERROR) {
     gpr_log(GPR_ERROR, "Peer check failed.");
     secure_transport_setup_done(s, 0);
@@ -262,7 +262,7 @@
   }
 }
 
-void grpc_setup_secure_transport(grpc_security_context *ctx,
+void grpc_setup_secure_transport(grpc_security_connector *connector,
                                  grpc_endpoint *nonsecure_endpoint,
                                  grpc_secure_transport_setup_done_cb cb,
                                  void *user_data) {
@@ -270,12 +270,12 @@
   grpc_secure_transport_setup *s =
       gpr_malloc(sizeof(grpc_secure_transport_setup));
   memset(s, 0, sizeof(grpc_secure_transport_setup));
-  result = grpc_security_context_create_handshaker(ctx, &s->handshaker);
+  result = grpc_security_connector_create_handshaker(connector, &s->handshaker);
   if (result != GRPC_SECURITY_OK) {
     secure_transport_setup_done(s, 0);
     return;
   }
-  s->ctx = grpc_security_context_ref(ctx);
+  s->connector = grpc_security_connector_ref(connector);
   s->handshake_buffer_size = GRPC_INITIAL_HANDSHAKE_BUFFER_SIZE;
   s->handshake_buffer = gpr_malloc(s->handshake_buffer_size);
   s->endpoint = nonsecure_endpoint;
diff --git a/src/core/security/secure_transport_setup.h b/src/core/security/secure_transport_setup.h
index e1f8ed7..58701c4 100644
--- a/src/core/security/secure_transport_setup.h
+++ b/src/core/security/secure_transport_setup.h
@@ -35,7 +35,7 @@
 #define GRPC_INTERNAL_CORE_SECURITY_SECURE_TRANSPORT_SETUP_H
 
 #include "src/core/iomgr/endpoint.h"
-#include "src/core/security/security_context.h"
+#include "src/core/security/security_connector.h"
 
 /* --- Secure transport setup --- */
 
@@ -45,7 +45,7 @@
     grpc_endpoint *secure_endpoint);
 
 /* Calls the callback upon completion. */
-void grpc_setup_secure_transport(grpc_security_context *ctx,
+void grpc_setup_secure_transport(grpc_security_connector *connector,
                                  grpc_endpoint *nonsecure_endpoint,
                                  grpc_secure_transport_setup_done_cb cb,
                                  void *user_data);
diff --git a/src/core/security/security_context.c b/src/core/security/security_connector.c
similarity index 65%
rename from src/core/security/security_context.c
rename to src/core/security/security_connector.c
index dbfcf55..dbd79c5 100644
--- a/src/core/security/security_context.c
+++ b/src/core/security/security_connector.c
@@ -31,12 +31,10 @@
  *
  */
 
-#include "src/core/security/security_context.h"
+#include "src/core/security/security_connector.h"
 
 #include <string.h>
 
-#include "src/core/channel/channel_args.h"
-#include "src/core/channel/http_client_filter.h"
 #include "src/core/security/credentials.h"
 #include "src/core/security/secure_endpoint.h"
 #include "src/core/support/env.h"
@@ -56,7 +54,8 @@
 #ifndef INSTALL_PREFIX
 static const char *installed_roots_path = "/usr/share/grpc/roots.pem";
 #else
-static const char *installed_roots_path = INSTALL_PREFIX "/share/grpc/roots.pem";
+static const char *installed_roots_path =
+    INSTALL_PREFIX "/share/grpc/roots.pem";
 #endif
 
 /* -- Cipher suites. -- */
@@ -82,75 +81,77 @@
 
 /* -- Common methods. -- */
 
-grpc_security_status grpc_security_context_create_handshaker(
-    grpc_security_context *ctx, tsi_handshaker **handshaker) {
-  if (ctx == NULL || handshaker == NULL) return GRPC_SECURITY_ERROR;
-  return ctx->vtable->create_handshaker(ctx, handshaker);
+grpc_security_status grpc_security_connector_create_handshaker(
+    grpc_security_connector *sc, tsi_handshaker **handshaker) {
+  if (sc == NULL || handshaker == NULL) return GRPC_SECURITY_ERROR;
+  return sc->vtable->create_handshaker(sc, handshaker);
 }
 
-grpc_security_status grpc_security_context_check_peer(
-    grpc_security_context *ctx, tsi_peer peer, grpc_security_check_cb cb,
+grpc_security_status grpc_security_connector_check_peer(
+    grpc_security_connector *sc, tsi_peer peer, grpc_security_check_cb cb,
     void *user_data) {
-  if (ctx == NULL) {
+  if (sc == NULL) {
     tsi_peer_destruct(&peer);
     return GRPC_SECURITY_ERROR;
   }
-  return ctx->vtable->check_peer(ctx, peer, cb, user_data);
+  return sc->vtable->check_peer(sc, peer, cb, user_data);
 }
 
-grpc_security_status grpc_channel_security_context_check_call_host(
-    grpc_channel_security_context *ctx, const char *host,
+grpc_security_status grpc_channel_security_connector_check_call_host(
+    grpc_channel_security_connector *sc, const char *host,
     grpc_security_check_cb cb, void *user_data) {
-  if (ctx == NULL || ctx->check_call_host == NULL) return GRPC_SECURITY_ERROR;
-  return ctx->check_call_host(ctx, host, cb, user_data);
+  if (sc == NULL || sc->check_call_host == NULL) return GRPC_SECURITY_ERROR;
+  return sc->check_call_host(sc, host, cb, user_data);
 }
 
-void grpc_security_context_unref(grpc_security_context *ctx) {
-  if (ctx == NULL) return;
-  if (gpr_unref(&ctx->refcount)) ctx->vtable->destroy(ctx);
+void grpc_security_connector_unref(grpc_security_connector *sc) {
+  if (sc == NULL) return;
+  if (gpr_unref(&sc->refcount)) sc->vtable->destroy(sc);
 }
 
-grpc_security_context *grpc_security_context_ref(grpc_security_context *ctx) {
-  if (ctx == NULL) return NULL;
-  gpr_ref(&ctx->refcount);
-  return ctx;
+grpc_security_connector *grpc_security_connector_ref(
+    grpc_security_connector *sc) {
+  if (sc == NULL) return NULL;
+  gpr_ref(&sc->refcount);
+  return sc;
 }
 
-static void context_pointer_arg_destroy(void *p) {
-  grpc_security_context_unref(p);
+static void connector_pointer_arg_destroy(void *p) {
+  grpc_security_connector_unref(p);
 }
 
-static void *context_pointer_arg_copy(void *p) {
-  return grpc_security_context_ref(p);
+static void *connector_pointer_arg_copy(void *p) {
+  return grpc_security_connector_ref(p);
 }
 
-grpc_arg grpc_security_context_to_arg(grpc_security_context *ctx) {
+grpc_arg grpc_security_connector_to_arg(grpc_security_connector *sc) {
   grpc_arg result;
   result.type = GRPC_ARG_POINTER;
-  result.key = GRPC_SECURITY_CONTEXT_ARG;
-  result.value.pointer.destroy = context_pointer_arg_destroy;
-  result.value.pointer.copy = context_pointer_arg_copy;
-  result.value.pointer.p = ctx;
+  result.key = GRPC_SECURITY_CONNECTOR_ARG;
+  result.value.pointer.destroy = connector_pointer_arg_destroy;
+  result.value.pointer.copy = connector_pointer_arg_copy;
+  result.value.pointer.p = sc;
   return result;
 }
 
-grpc_security_context *grpc_security_context_from_arg(const grpc_arg *arg) {
-  if (strcmp(arg->key, GRPC_SECURITY_CONTEXT_ARG)) return NULL;
+grpc_security_connector *grpc_security_connector_from_arg(const grpc_arg *arg) {
+  if (strcmp(arg->key, GRPC_SECURITY_CONNECTOR_ARG)) return NULL;
   if (arg->type != GRPC_ARG_POINTER) {
     gpr_log(GPR_ERROR, "Invalid type %d for arg %s", arg->type,
-            GRPC_SECURITY_CONTEXT_ARG);
+            GRPC_SECURITY_CONNECTOR_ARG);
     return NULL;
   }
   return arg->value.pointer.p;
 }
 
-grpc_security_context *grpc_find_security_context_in_args(
+grpc_security_connector *grpc_find_security_connector_in_args(
     const grpc_channel_args *args) {
   size_t i;
   if (args == NULL) return NULL;
   for (i = 0; i < args->num_args; i++) {
-    grpc_security_context *ctx = grpc_security_context_from_arg(&args->args[i]);
-    if (ctx != NULL) return ctx;
+    grpc_security_connector *sc =
+        grpc_security_connector_from_arg(&args->args[i]);
+    if (sc != NULL) return sc;
   }
   return NULL;
 }
@@ -158,51 +159,41 @@
 static int check_request_metadata_creds(grpc_credentials *creds) {
   if (creds != NULL && !grpc_credentials_has_request_metadata(creds)) {
     gpr_log(GPR_ERROR,
-            "Incompatible credentials for channel security context: needs to "
+            "Incompatible credentials for channel security connector: needs to "
             "set request metadata.");
     return 0;
   }
   return 1;
 }
 
-static grpc_mdctx *get_or_create_mdctx(grpc_credentials *creds) {
-  grpc_mdctx *mdctx = grpc_credentials_get_metadata_context(creds);
-  if (mdctx == NULL) {
-    mdctx = grpc_mdctx_create();
-  } else {
-    grpc_mdctx_ref(mdctx);
-  }
-  return mdctx;
-}
-
 /* -- Fake implementation. -- */
 
 typedef struct {
-  grpc_channel_security_context base;
+  grpc_channel_security_connector base;
   int call_host_check_is_async;
-} grpc_fake_channel_security_context;
+} grpc_fake_channel_security_connector;
 
-static void fake_channel_destroy(grpc_security_context *ctx) {
-  grpc_channel_security_context *c = (grpc_channel_security_context *)ctx;
+static void fake_channel_destroy(grpc_security_connector *sc) {
+  grpc_channel_security_connector *c = (grpc_channel_security_connector *)sc;
   grpc_credentials_unref(c->request_metadata_creds);
-  gpr_free(ctx);
+  gpr_free(sc);
 }
 
-static void fake_server_destroy(grpc_security_context *ctx) { gpr_free(ctx); }
+static void fake_server_destroy(grpc_security_connector *sc) { gpr_free(sc); }
 
 static grpc_security_status fake_channel_create_handshaker(
-    grpc_security_context *ctx, tsi_handshaker **handshaker) {
+    grpc_security_connector *sc, tsi_handshaker **handshaker) {
   *handshaker = tsi_create_fake_handshaker(1);
   return GRPC_SECURITY_OK;
 }
 
 static grpc_security_status fake_server_create_handshaker(
-    grpc_security_context *ctx, tsi_handshaker **handshaker) {
+    grpc_security_connector *sc, tsi_handshaker **handshaker) {
   *handshaker = tsi_create_fake_handshaker(0);
   return GRPC_SECURITY_OK;
 }
 
-static grpc_security_status fake_check_peer(grpc_security_context *ctx,
+static grpc_security_status fake_check_peer(grpc_security_connector *sc,
                                             tsi_peer peer,
                                             grpc_security_check_cb cb,
                                             void *user_data) {
@@ -238,10 +229,10 @@
 }
 
 static grpc_security_status fake_channel_check_call_host(
-    grpc_channel_security_context *ctx, const char *host,
+    grpc_channel_security_connector *sc, const char *host,
     grpc_security_check_cb cb, void *user_data) {
-  grpc_fake_channel_security_context *c =
-      (grpc_fake_channel_security_context *)ctx;
+  grpc_fake_channel_security_connector *c =
+      (grpc_fake_channel_security_connector *)sc;
   if (c->call_host_check_is_async) {
     cb(user_data, GRPC_SECURITY_OK);
     return GRPC_SECURITY_PENDING;
@@ -250,16 +241,16 @@
   }
 }
 
-static grpc_security_context_vtable fake_channel_vtable = {
+static grpc_security_connector_vtable fake_channel_vtable = {
     fake_channel_destroy, fake_channel_create_handshaker, fake_check_peer};
 
-static grpc_security_context_vtable fake_server_vtable = {
+static grpc_security_connector_vtable fake_server_vtable = {
     fake_server_destroy, fake_server_create_handshaker, fake_check_peer};
 
-grpc_channel_security_context *grpc_fake_channel_security_context_create(
+grpc_channel_security_connector *grpc_fake_channel_security_connector_create(
     grpc_credentials *request_metadata_creds, int call_host_check_is_async) {
-  grpc_fake_channel_security_context *c =
-      gpr_malloc(sizeof(grpc_fake_channel_security_context));
+  grpc_fake_channel_security_connector *c =
+      gpr_malloc(sizeof(grpc_fake_channel_security_connector));
   gpr_ref_init(&c->base.base.refcount, 1);
   c->base.base.is_client_side = 1;
   c->base.base.url_scheme = GRPC_FAKE_SECURITY_URL_SCHEME;
@@ -271,8 +262,8 @@
   return &c->base;
 }
 
-grpc_security_context *grpc_fake_server_security_context_create(void) {
-  grpc_security_context *c = gpr_malloc(sizeof(grpc_security_context));
+grpc_security_connector *grpc_fake_server_security_connector_create(void) {
+  grpc_security_connector *c = gpr_malloc(sizeof(grpc_security_connector));
   gpr_ref_init(&c->refcount, 1);
   c->vtable = &fake_server_vtable;
   c->url_scheme = GRPC_FAKE_SECURITY_URL_SCHEME;
@@ -282,21 +273,21 @@
 /* --- Ssl implementation. --- */
 
 typedef struct {
-  grpc_channel_security_context base;
+  grpc_channel_security_connector base;
   tsi_ssl_handshaker_factory *handshaker_factory;
   char *target_name;
   char *overridden_target_name;
   tsi_peer peer;
-} grpc_ssl_channel_security_context;
+} grpc_ssl_channel_security_connector;
 
 typedef struct {
-  grpc_security_context base;
+  grpc_security_connector base;
   tsi_ssl_handshaker_factory *handshaker_factory;
-} grpc_ssl_server_security_context;
+} grpc_ssl_server_security_connector;
 
-static void ssl_channel_destroy(grpc_security_context *ctx) {
-  grpc_ssl_channel_security_context *c =
-      (grpc_ssl_channel_security_context *)ctx;
+static void ssl_channel_destroy(grpc_security_connector *sc) {
+  grpc_ssl_channel_security_connector *c =
+      (grpc_ssl_channel_security_connector *)sc;
   grpc_credentials_unref(c->base.request_metadata_creds);
   if (c->handshaker_factory != NULL) {
     tsi_ssl_handshaker_factory_destroy(c->handshaker_factory);
@@ -304,15 +295,16 @@
   if (c->target_name != NULL) gpr_free(c->target_name);
   if (c->overridden_target_name != NULL) gpr_free(c->overridden_target_name);
   tsi_peer_destruct(&c->peer);
-  gpr_free(ctx);
+  gpr_free(sc);
 }
 
-static void ssl_server_destroy(grpc_security_context *ctx) {
-  grpc_ssl_server_security_context *c = (grpc_ssl_server_security_context *)ctx;
+static void ssl_server_destroy(grpc_security_connector *sc) {
+  grpc_ssl_server_security_connector *c =
+      (grpc_ssl_server_security_connector *)sc;
   if (c->handshaker_factory != NULL) {
     tsi_ssl_handshaker_factory_destroy(c->handshaker_factory);
   }
-  gpr_free(ctx);
+  gpr_free(sc);
 }
 
 static grpc_security_status ssl_create_handshaker(
@@ -331,9 +323,9 @@
 }
 
 static grpc_security_status ssl_channel_create_handshaker(
-    grpc_security_context *ctx, tsi_handshaker **handshaker) {
-  grpc_ssl_channel_security_context *c =
-      (grpc_ssl_channel_security_context *)ctx;
+    grpc_security_connector *sc, tsi_handshaker **handshaker) {
+  grpc_ssl_channel_security_connector *c =
+      (grpc_ssl_channel_security_connector *)sc;
   return ssl_create_handshaker(c->handshaker_factory, 1,
                                c->overridden_target_name != NULL
                                    ? c->overridden_target_name
@@ -342,13 +334,13 @@
 }
 
 static grpc_security_status ssl_server_create_handshaker(
-    grpc_security_context *ctx, tsi_handshaker **handshaker) {
-  grpc_ssl_server_security_context *c = (grpc_ssl_server_security_context *)ctx;
+    grpc_security_connector *sc, tsi_handshaker **handshaker) {
+  grpc_ssl_server_security_connector *c =
+      (grpc_ssl_server_security_connector *)sc;
   return ssl_create_handshaker(c->handshaker_factory, 0, NULL, handshaker);
 }
 
-static int ssl_host_matches_name(const tsi_peer *peer,
-                                 const char *peer_name) {
+static int ssl_host_matches_name(const tsi_peer *peer, const char *peer_name) {
   char *allocated_name = NULL;
   int r;
 
@@ -384,8 +376,7 @@
   }
 
   /* Check the peer name if specified. */
-  if (peer_name != NULL &&
-      !ssl_host_matches_name(peer, peer_name)) {
+  if (peer_name != NULL && !ssl_host_matches_name(peer, peer_name)) {
     gpr_log(GPR_ERROR, "Peer name %s is not in peer certificate", peer_name);
     return GRPC_SECURITY_ERROR;
   }
@@ -393,12 +384,12 @@
   return GRPC_SECURITY_OK;
 }
 
-static grpc_security_status ssl_channel_check_peer(grpc_security_context *ctx,
+static grpc_security_status ssl_channel_check_peer(grpc_security_connector *sc,
                                                    tsi_peer peer,
                                                    grpc_security_check_cb cb,
                                                    void *user_data) {
-  grpc_ssl_channel_security_context *c =
-      (grpc_ssl_channel_security_context *)ctx;
+  grpc_ssl_channel_security_connector *c =
+      (grpc_ssl_channel_security_connector *)sc;
   grpc_security_status status;
   tsi_peer_destruct(&c->peer);
   c->peer = peer;
@@ -409,7 +400,7 @@
   return status;
 }
 
-static grpc_security_status ssl_server_check_peer(grpc_security_context *ctx,
+static grpc_security_status ssl_server_check_peer(grpc_security_connector *sc,
                                                   tsi_peer peer,
                                                   grpc_security_check_cb cb,
                                                   void *user_data) {
@@ -420,10 +411,10 @@
 }
 
 static grpc_security_status ssl_channel_check_call_host(
-    grpc_channel_security_context *ctx, const char *host,
+    grpc_channel_security_connector *sc, const char *host,
     grpc_security_check_cb cb, void *user_data) {
-  grpc_ssl_channel_security_context *c =
-      (grpc_ssl_channel_security_context *)ctx;
+  grpc_ssl_channel_security_connector *c =
+      (grpc_ssl_channel_security_connector *)sc;
 
   if (ssl_host_matches_name(&c->peer, host)) return GRPC_SECURITY_OK;
 
@@ -437,10 +428,10 @@
   }
 }
 
-static grpc_security_context_vtable ssl_channel_vtable = {
+static grpc_security_connector_vtable ssl_channel_vtable = {
     ssl_channel_destroy, ssl_channel_create_handshaker, ssl_channel_check_peer};
 
-static grpc_security_context_vtable ssl_server_vtable = {
+static grpc_security_connector_vtable ssl_server_vtable = {
     ssl_server_destroy, ssl_server_create_handshaker, ssl_server_check_peer};
 
 static gpr_slice default_pem_root_certs;
@@ -471,17 +462,17 @@
   return GPR_SLICE_LENGTH(default_pem_root_certs);
 }
 
-grpc_security_status grpc_ssl_channel_security_context_create(
+grpc_security_status grpc_ssl_channel_security_connector_create(
     grpc_credentials *request_metadata_creds, const grpc_ssl_config *config,
     const char *target_name, const char *overridden_target_name,
-    grpc_channel_security_context **ctx) {
+    grpc_channel_security_connector **sc) {
   size_t num_alpn_protocols = grpc_chttp2_num_alpn_versions();
   const unsigned char **alpn_protocol_strings =
       gpr_malloc(sizeof(const char *) * num_alpn_protocols);
   unsigned char *alpn_protocol_string_lengths =
       gpr_malloc(sizeof(unsigned char) * num_alpn_protocols);
   tsi_result result = TSI_OK;
-  grpc_ssl_channel_security_context *c;
+  grpc_ssl_channel_security_connector *c;
   size_t i;
   const unsigned char *pem_root_certs;
   size_t pem_root_certs_size;
@@ -502,8 +493,8 @@
     goto error;
   }
 
-  c = gpr_malloc(sizeof(grpc_ssl_channel_security_context));
-  memset(c, 0, sizeof(grpc_ssl_channel_security_context));
+  c = gpr_malloc(sizeof(grpc_ssl_channel_security_connector));
+  memset(c, 0, sizeof(grpc_ssl_channel_security_connector));
 
   gpr_ref_init(&c->base.base.refcount, 1);
   c->base.base.vtable = &ssl_channel_vtable;
@@ -535,10 +526,10 @@
     gpr_log(GPR_ERROR, "Handshaker factory creation failed with %s.",
             tsi_result_to_string(result));
     ssl_channel_destroy(&c->base.base);
-    *ctx = NULL;
+    *sc = NULL;
     goto error;
   }
-  *ctx = &c->base;
+  *sc = &c->base;
   gpr_free(alpn_protocol_strings);
   gpr_free(alpn_protocol_string_lengths);
   return GRPC_SECURITY_OK;
@@ -549,15 +540,15 @@
   return GRPC_SECURITY_ERROR;
 }
 
-grpc_security_status grpc_ssl_server_security_context_create(
-    const grpc_ssl_server_config *config, grpc_security_context **ctx) {
+grpc_security_status grpc_ssl_server_security_connector_create(
+    const grpc_ssl_server_config *config, grpc_security_connector **sc) {
   size_t num_alpn_protocols = grpc_chttp2_num_alpn_versions();
   const unsigned char **alpn_protocol_strings =
       gpr_malloc(sizeof(const char *) * num_alpn_protocols);
   unsigned char *alpn_protocol_string_lengths =
       gpr_malloc(sizeof(unsigned char) * num_alpn_protocols);
   tsi_result result = TSI_OK;
-  grpc_ssl_server_security_context *c;
+  grpc_ssl_server_security_connector *c;
   size_t i;
 
   for (i = 0; i < num_alpn_protocols; i++) {
@@ -571,8 +562,8 @@
     gpr_log(GPR_ERROR, "An SSL server needs a key and a cert.");
     goto error;
   }
-  c = gpr_malloc(sizeof(grpc_ssl_server_security_context));
-  memset(c, 0, sizeof(grpc_ssl_server_security_context));
+  c = gpr_malloc(sizeof(grpc_ssl_server_security_connector));
+  memset(c, 0, sizeof(grpc_ssl_server_security_connector));
 
   gpr_ref_init(&c->base.refcount, 1);
   c->base.url_scheme = GRPC_SSL_URL_SCHEME;
@@ -582,17 +573,17 @@
       config->pem_private_keys_sizes,
       (const unsigned char **)config->pem_cert_chains,
       config->pem_cert_chains_sizes, config->num_key_cert_pairs,
-      config->pem_root_certs, config->pem_root_certs_size,
-      ssl_cipher_suites(), alpn_protocol_strings,
-      alpn_protocol_string_lengths, num_alpn_protocols, &c->handshaker_factory);
+      config->pem_root_certs, config->pem_root_certs_size, ssl_cipher_suites(),
+      alpn_protocol_strings, alpn_protocol_string_lengths, num_alpn_protocols,
+      &c->handshaker_factory);
   if (result != TSI_OK) {
     gpr_log(GPR_ERROR, "Handshaker factory creation failed with %s.",
             tsi_result_to_string(result));
     ssl_server_destroy(&c->base);
-    *ctx = NULL;
+    *sc = NULL;
     goto error;
   }
-  *ctx = &c->base;
+  *sc = &c->base;
   gpr_free(alpn_protocol_strings);
   gpr_free(alpn_protocol_string_lengths);
   return GRPC_SECURITY_OK;
@@ -603,84 +594,3 @@
   return GRPC_SECURITY_ERROR;
 }
 
-/* -- High level objects. -- */
-
-grpc_channel *grpc_ssl_channel_create(grpc_credentials *ssl_creds,
-                                      grpc_credentials *request_metadata_creds,
-                                      const char *target,
-                                      const grpc_channel_args *args) {
-  grpc_channel_security_context *ctx = NULL;
-  grpc_channel *channel = NULL;
-  grpc_security_status status = GRPC_SECURITY_OK;
-  size_t i = 0;
-  const char *overridden_target_name = NULL;
-  grpc_arg arg;
-  grpc_channel_args *new_args;
-
-  for (i = 0; args && i < args->num_args; i++) {
-    grpc_arg *arg = &args->args[i];
-    if (strcmp(arg->key, GRPC_SSL_TARGET_NAME_OVERRIDE_ARG) == 0 &&
-        arg->type == GRPC_ARG_STRING) {
-      overridden_target_name = arg->value.string;
-      break;
-    }
-  }
-  status = grpc_ssl_channel_security_context_create(
-      request_metadata_creds, grpc_ssl_credentials_get_config(ssl_creds),
-      target, overridden_target_name, &ctx);
-  if (status != GRPC_SECURITY_OK) {
-    return grpc_lame_client_channel_create();
-  }
-  arg.type = GRPC_ARG_STRING;
-  arg.key = GRPC_ARG_HTTP2_SCHEME;
-  arg.value.string = "https";
-  new_args = grpc_channel_args_copy_and_add(args, &arg);
-  channel = grpc_secure_channel_create_internal(
-      target, new_args, ctx, get_or_create_mdctx(request_metadata_creds));
-  grpc_security_context_unref(&ctx->base);
-  grpc_channel_args_destroy(new_args);
-  return channel;
-}
-
-grpc_channel *grpc_fake_transport_security_channel_create(
-    grpc_credentials *fake_creds, grpc_credentials *request_metadata_creds,
-    const char *target, const grpc_channel_args *args) {
-  grpc_channel_security_context *ctx =
-      grpc_fake_channel_security_context_create(request_metadata_creds, 1);
-  grpc_channel *channel = grpc_secure_channel_create_internal(
-      target, args, ctx, get_or_create_mdctx(request_metadata_creds));
-  grpc_security_context_unref(&ctx->base);
-  return channel;
-}
-
-grpc_channel *grpc_secure_channel_create_with_factories(
-    const grpc_secure_channel_factory *factories, size_t num_factories,
-    grpc_credentials *creds, const char *target,
-    const grpc_channel_args *args) {
-  size_t i;
-  if (creds == NULL) {
-    gpr_log(GPR_ERROR, "No credentials to create a secure channel.");
-    return grpc_lame_client_channel_create();
-  }
-  if (grpc_credentials_has_request_metadata_only(creds)) {
-    gpr_log(GPR_ERROR,
-            "Credentials is insufficient to create a secure channel.");
-    return grpc_lame_client_channel_create();
-  }
-
-  for (i = 0; i < num_factories; i++) {
-    grpc_credentials *composite_creds = NULL;
-    grpc_credentials *transport_security_creds = NULL;
-    transport_security_creds = grpc_credentials_contains_type(
-        creds, factories[i].creds_type, &composite_creds);
-    if (transport_security_creds != NULL) {
-      return factories[i].factory(transport_security_creds, composite_creds,
-                                  target, args);
-    }
-  }
-
-  gpr_log(GPR_ERROR,
-          "Unknown credentials type %s for creating a secure channel.",
-          creds->type);
-  return grpc_lame_client_channel_create();
-}
diff --git a/src/core/security/security_connector.h b/src/core/security/security_connector.h
new file mode 100644
index 0000000..47abe05
--- /dev/null
+++ b/src/core/security/security_connector.h
@@ -0,0 +1,201 @@
+/*
+ *
+ * Copyright 2015, 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_INTERNAL_CORE_SECURITY_SECURITY_CONNECTOR_H
+#define GRPC_INTERNAL_CORE_SECURITY_SECURITY_CONNECTOR_H
+
+#include <grpc/grpc_security.h>
+#include "src/core/iomgr/endpoint.h"
+#include "src/core/tsi/transport_security_interface.h"
+
+/* --- status enum. --- */
+
+typedef enum {
+  GRPC_SECURITY_OK = 0,
+  GRPC_SECURITY_PENDING,
+  GRPC_SECURITY_ERROR
+} grpc_security_status;
+
+/* --- URL schemes. --- */
+
+#define GRPC_SSL_URL_SCHEME "https"
+#define GRPC_FAKE_SECURITY_URL_SCHEME "http+fake_security"
+
+/* --- security_connector object. ---
+
+    A security connector object represents away to configure the underlying
+    transport security mechanism and check the resulting trusted peer.  */
+
+typedef struct grpc_security_connector grpc_security_connector;
+
+#define GRPC_SECURITY_CONNECTOR_ARG "grpc.security_connector"
+
+typedef void (*grpc_security_check_cb)(void *user_data,
+                                       grpc_security_status status);
+
+typedef struct {
+  void (*destroy)(grpc_security_connector *sc);
+  grpc_security_status (*create_handshaker)(grpc_security_connector *sc,
+                                            tsi_handshaker **handshaker);
+  grpc_security_status (*check_peer)(grpc_security_connector *sc, tsi_peer peer,
+                                     grpc_security_check_cb cb,
+                                     void *user_data);
+} grpc_security_connector_vtable;
+
+struct grpc_security_connector {
+  const grpc_security_connector_vtable *vtable;
+  gpr_refcount refcount;
+  int is_client_side;
+  const char *url_scheme;
+};
+
+/* Increments the refcount. */
+grpc_security_connector *grpc_security_connector_ref(
+    grpc_security_connector *sc);
+
+/* Decrements the refcount and destroys the object if it reaches 0. */
+void grpc_security_connector_unref(grpc_security_connector *sc);
+
+/* Handshake creation. */
+grpc_security_status grpc_security_connector_create_handshaker(
+    grpc_security_connector *sc, tsi_handshaker **handshaker);
+
+/* Check the peer.
+   Implementations can choose to check the peer either synchronously or
+   asynchronously. In the first case, a successful call will return
+   GRPC_SECURITY_OK. In the asynchronous case, the call will return
+   GRPC_SECURITY_PENDING unless an error is detected early on.
+   Ownership of the peer is transfered.
+*/
+grpc_security_status grpc_security_connector_check_peer(
+    grpc_security_connector *sc, tsi_peer peer, grpc_security_check_cb cb,
+    void *user_data);
+
+/* Util to encapsulate the connector in a channel arg. */
+grpc_arg grpc_security_connector_to_arg(grpc_security_connector *sc);
+
+/* Util to get the connector from a channel arg. */
+grpc_security_connector *grpc_security_connector_from_arg(const grpc_arg *arg);
+
+/* Util to find the connector from channel args. */
+grpc_security_connector *grpc_find_security_connector_in_args(
+    const grpc_channel_args *args);
+
+/* --- channel_security_connector object. ---
+
+    A channel security connector object represents away to configure the
+    underlying transport security mechanism on the client side.  */
+
+typedef struct grpc_channel_security_connector grpc_channel_security_connector;
+
+struct grpc_channel_security_connector {
+  grpc_security_connector base; /* requires is_client_side to be non 0. */
+  grpc_credentials *request_metadata_creds;
+  grpc_security_status (*check_call_host)(grpc_channel_security_connector *sc,
+                                          const char *host,
+                                          grpc_security_check_cb cb,
+                                          void *user_data);
+};
+
+/* Checks that the host that will be set for a call is acceptable.
+   Implementations can choose do the check either synchronously or
+   asynchronously. In the first case, a successful call will return
+   GRPC_SECURITY_OK. In the asynchronous case, the call will return
+   GRPC_SECURITY_PENDING unless an error is detected early on. */
+grpc_security_status grpc_channel_security_connector_check_call_host(
+    grpc_channel_security_connector *sc, const char *host,
+    grpc_security_check_cb cb, void *user_data);
+
+/* --- Creation security connectors. --- */
+
+/* For TESTING ONLY!
+   Creates a fake connector that emulates real channel security.  */
+grpc_channel_security_connector *grpc_fake_channel_security_connector_create(
+    grpc_credentials *request_metadata_creds, int call_host_check_is_async);
+
+/* For TESTING ONLY!
+   Creates a fake connector that emulates real server security.  */
+grpc_security_connector *grpc_fake_server_security_connector_create(void);
+
+/* Config for ssl clients. */
+typedef struct {
+  unsigned char *pem_private_key;
+  size_t pem_private_key_size;
+  unsigned char *pem_cert_chain;
+  size_t pem_cert_chain_size;
+  unsigned char *pem_root_certs;
+  size_t pem_root_certs_size;
+} grpc_ssl_config;
+
+/* Creates an SSL channel_security_connector.
+   - request_metadata_creds is the credentials object which metadata
+     will be sent with each request. This parameter can be NULL.
+   - config is the SSL config to be used for the SSL channel establishment.
+   - is_client should be 0 for a server or a non-0 value for a client.
+   - secure_peer_name is the secure peer name that should be checked in
+     grpc_channel_security_connector_check_peer. This parameter may be NULL in
+     which case the peer name will not be checked. Note that if this parameter
+     is not NULL, then, pem_root_certs should not be NULL either.
+   - sc is a pointer on the connector to be created.
+  This function returns GRPC_SECURITY_OK in case of success or a
+  specific error code otherwise.
+*/
+grpc_security_status grpc_ssl_channel_security_connector_create(
+    grpc_credentials *request_metadata_creds,
+    const grpc_ssl_config *config, const char *target_name,
+    const char *overridden_target_name, grpc_channel_security_connector **sc);
+
+/* Gets the default ssl roots. */
+size_t grpc_get_default_ssl_roots(const unsigned char **pem_root_certs);
+
+/* Config for ssl servers. */
+typedef struct {
+  unsigned char **pem_private_keys;
+  size_t *pem_private_keys_sizes;
+  unsigned char **pem_cert_chains;
+  size_t *pem_cert_chains_sizes;
+  size_t num_key_cert_pairs;
+  unsigned char *pem_root_certs;
+  size_t pem_root_certs_size;
+} grpc_ssl_server_config;
+
+/* Creates an SSL server_security_connector.
+   - config is the SSL config to be used for the SSL channel establishment.
+   - sc is a pointer on the connector to be created.
+  This function returns GRPC_SECURITY_OK in case of success or a
+  specific error code otherwise.
+*/
+grpc_security_status grpc_ssl_server_security_connector_create(
+    const grpc_ssl_server_config *config, grpc_security_connector **sc);
+
+#endif /* GRPC_INTERNAL_CORE_SECURITY_SECURITY_CONNECTOR_H */
diff --git a/src/core/security/security_context.h b/src/core/security/security_context.h
deleted file mode 100644
index 8e7ba34..0000000
--- a/src/core/security/security_context.h
+++ /dev/null
@@ -1,214 +0,0 @@
-/*
- *
- * Copyright 2015, 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_INTERNAL_CORE_SECURITY_SECURITY_CONTEXT_H
-#define GRPC_INTERNAL_CORE_SECURITY_SECURITY_CONTEXT_H
-
-#include <grpc/grpc_security.h>
-#include "src/core/iomgr/endpoint.h"
-#include "src/core/security/credentials.h"
-#include "src/core/tsi/transport_security_interface.h"
-
-/* --- status enum. --- */
-
-typedef enum {
-  GRPC_SECURITY_OK = 0,
-  GRPC_SECURITY_PENDING,
-  GRPC_SECURITY_ERROR
-} grpc_security_status;
-
-/* --- URL schemes. --- */
-
-#define GRPC_SSL_URL_SCHEME "https"
-#define GRPC_FAKE_SECURITY_URL_SCHEME "http+fake_security"
-
-/* --- security_context object. ---
-
-    A security context object represents away to configure the underlying
-    transport security mechanism and check the resulting trusted peer.  */
-
-typedef struct grpc_security_context grpc_security_context;
-
-#define GRPC_SECURITY_CONTEXT_ARG "grpc.security_context"
-
-typedef void (*grpc_security_check_cb)(void *user_data,
-                                       grpc_security_status status);
-
-typedef struct {
-  void (*destroy)(grpc_security_context *ctx);
-  grpc_security_status (*create_handshaker)(grpc_security_context *ctx,
-                                            tsi_handshaker **handshaker);
-  grpc_security_status (*check_peer)(grpc_security_context *ctx, tsi_peer peer,
-                                     grpc_security_check_cb cb,
-                                     void *user_data);
-} grpc_security_context_vtable;
-
-struct grpc_security_context {
-  const grpc_security_context_vtable *vtable;
-  gpr_refcount refcount;
-  int is_client_side;
-  const char *url_scheme;
-};
-
-/* Increments the refcount. */
-grpc_security_context *grpc_security_context_ref(grpc_security_context *ctx);
-
-/* Decrements the refcount and destroys the object if it reaches 0. */
-void grpc_security_context_unref(grpc_security_context *ctx);
-
-/* Handshake creation. */
-grpc_security_status grpc_security_context_create_handshaker(
-    grpc_security_context *ctx, tsi_handshaker **handshaker);
-
-/* Check the peer.
-   Implementations can choose to check the peer either synchronously or
-   asynchronously. In the first case, a successful call will return
-   GRPC_SECURITY_OK. In the asynchronous case, the call will return
-   GRPC_SECURITY_PENDING unless an error is detected early on.
-   Ownership of the peer is transfered.
-*/
-grpc_security_status grpc_security_context_check_peer(
-    grpc_security_context *ctx, tsi_peer peer,
-    grpc_security_check_cb cb, void *user_data);
-
-/* Util to encapsulate the context in a channel arg. */
-grpc_arg grpc_security_context_to_arg(grpc_security_context *ctx);
-
-/* Util to get the context from a channel arg. */
-grpc_security_context *grpc_security_context_from_arg(const grpc_arg *arg);
-
-/* Util to find the context from channel args. */
-grpc_security_context *grpc_find_security_context_in_args(
-    const grpc_channel_args *args);
-
-/* --- channel_security_context object. ---
-
-    A channel security context object represents away to configure the
-    underlying transport security mechanism on the client side.  */
-
-typedef struct grpc_channel_security_context grpc_channel_security_context;
-
-struct grpc_channel_security_context {
-  grpc_security_context base; /* requires is_client_side to be non 0. */
-  grpc_credentials *request_metadata_creds;
-  grpc_security_status (*check_call_host)(
-      grpc_channel_security_context *ctx, const char *host,
-      grpc_security_check_cb cb, void *user_data);
-};
-
-/* Checks that the host that will be set for a call is acceptable.
-   Implementations can choose do the check either synchronously or
-   asynchronously. In the first case, a successful call will return
-   GRPC_SECURITY_OK. In the asynchronous case, the call will return
-   GRPC_SECURITY_PENDING unless an error is detected early on. */
-grpc_security_status grpc_channel_security_context_check_call_host(
-    grpc_channel_security_context *ctx, const char *host,
-    grpc_security_check_cb cb, void *user_data);
-
-/* --- Creation security contexts. --- */
-
-/* For TESTING ONLY!
-   Creates a fake context that emulates real channel security.  */
-grpc_channel_security_context *grpc_fake_channel_security_context_create(
-    grpc_credentials *request_metadata_creds, int call_host_check_is_async);
-
-/* For TESTING ONLY!
-   Creates a fake context that emulates real server security.  */
-grpc_security_context *grpc_fake_server_security_context_create(void);
-
-/* Creates an SSL channel_security_context.
-   - request_metadata_creds is the credentials object which metadata
-     will be sent with each request. This parameter can be NULL.
-   - config is the SSL config to be used for the SSL channel establishment.
-   - is_client should be 0 for a server or a non-0 value for a client.
-   - secure_peer_name is the secure peer name that should be checked in
-     grpc_channel_security_context_check_peer. This parameter may be NULL in
-     which case the peer name will not be checked. Note that if this parameter
-     is not NULL, then, pem_root_certs should not be NULL either.
-   - ctx is a pointer on the context to be created.
-  This function returns GRPC_SECURITY_OK in case of success or a
-  specific error code otherwise.
-*/
-grpc_security_status grpc_ssl_channel_security_context_create(
-    grpc_credentials *request_metadata_creds, const grpc_ssl_config *config,
-    const char *target_name, const char *overridden_target_name,
-    grpc_channel_security_context **ctx);
-
-/* Creates an SSL server_security_context.
-   - config is the SSL config to be used for the SSL channel establishment.
-   - ctx is a pointer on the context to be created.
-  This function returns GRPC_SECURITY_OK in case of success or a
-  specific error code otherwise.
-*/
-grpc_security_status grpc_ssl_server_security_context_create(
-    const grpc_ssl_server_config *config, grpc_security_context **ctx);
-
-/* --- Creation of high level objects. --- */
-
-/* Secure client channel creation. */
-
-size_t grpc_get_default_ssl_roots(const unsigned char **pem_root_certs);
-
-grpc_channel *grpc_ssl_channel_create(grpc_credentials *ssl_creds,
-                                      grpc_credentials *request_metadata_creds,
-                                      const char *target,
-                                      const grpc_channel_args *args);
-
-grpc_channel *grpc_fake_transport_security_channel_create(
-    grpc_credentials *fake_creds, grpc_credentials *request_metadata_creds,
-    const char *target, const grpc_channel_args *args);
-
-grpc_channel *grpc_secure_channel_create_internal(
-    const char *target, const grpc_channel_args *args,
-    grpc_channel_security_context *ctx, grpc_mdctx *mdctx);
-
-typedef grpc_channel *(*grpc_secure_channel_factory_func)(
-    grpc_credentials *transport_security_creds,
-    grpc_credentials *request_metadata_creds, const char *target,
-    const grpc_channel_args *args);
-
-typedef struct {
-  const char *creds_type;
-  grpc_secure_channel_factory_func factory;
-} grpc_secure_channel_factory;
-
-grpc_channel *grpc_secure_channel_create_with_factories(
-    const grpc_secure_channel_factory *factories, size_t num_factories,
-    grpc_credentials *creds, const char *target, const grpc_channel_args *args);
-
-/* Secure server context creation. */
-
-grpc_security_status grpc_server_security_context_create(
-    grpc_server_credentials *creds, grpc_security_context **ctx);
-
-#endif  /* GRPC_INTERNAL_CORE_SECURITY_SECURITY_CONTEXT_H */
diff --git a/src/core/security/server_secure_chttp2.c b/src/core/security/server_secure_chttp2.c
index 165ed54..5b7d99c 100644
--- a/src/core/security/server_secure_chttp2.c
+++ b/src/core/security/server_secure_chttp2.c
@@ -40,7 +40,8 @@
 #include "src/core/iomgr/endpoint.h"
 #include "src/core/iomgr/resolve_address.h"
 #include "src/core/iomgr/tcp_server.h"
-#include "src/core/security/security_context.h"
+#include "src/core/security/credentials.h"
+#include "src/core/security/security_connector.h"
 #include "src/core/security/secure_transport_setup.h"
 #include "src/core/surface/server.h"
 #include "src/core/transport/chttp2_transport.h"
@@ -52,7 +53,7 @@
 typedef struct grpc_server_secure_state {
   grpc_server *server;
   grpc_tcp_server *tcp;
-  grpc_security_context *ctx;
+  grpc_security_connector *sc;
   int is_shutdown;
   gpr_mu mu;
   gpr_refcount refcount;
@@ -64,7 +65,7 @@
 
 static void state_unref(grpc_server_secure_state *state) {
   if (gpr_unref(&state->refcount)) {
-    grpc_security_context_unref(state->ctx);
+    grpc_security_connector_unref(state->sc);
     gpr_free(state);
   }
 }
@@ -104,7 +105,7 @@
 static void on_accept(void *statep, grpc_endpoint *tcp) {
   grpc_server_secure_state *state = statep;
   state_ref(state);
-  grpc_setup_secure_transport(state->ctx, tcp, on_secure_transport_setup_done,
+  grpc_setup_secure_transport(state->sc, tcp, on_secure_transport_setup_done,
                               state);
 }
 
@@ -137,11 +138,11 @@
   int port_num = -1;
   int port_temp;
   grpc_security_status status = GRPC_SECURITY_ERROR;
-  grpc_security_context *ctx = NULL;
+  grpc_security_connector *sc = NULL;
 
   /* create security context */
   if (creds == NULL) goto error;
-  status = grpc_server_security_context_create(creds, &ctx);
+  status = grpc_server_credentials_create_security_connector(creds, &sc);
   if (status != GRPC_SECURITY_OK) {
     gpr_log(GPR_ERROR,
             "Unable to create secure server with credentials of type %s.",
@@ -188,7 +189,7 @@
   state = gpr_malloc(sizeof(*state));
   state->server = server;
   state->tcp = tcp;
-  state->ctx = ctx;
+  state->sc = sc;
   state->is_shutdown = 0;
   gpr_mu_init(&state->mu);
   gpr_ref_init(&state->refcount, 1);
@@ -200,8 +201,8 @@
 
 /* Error path: cleanup and return */
 error:
-  if (ctx) {
-    grpc_security_context_unref(ctx);
+  if (sc) {
+    grpc_security_connector_unref(sc);
   }
   if (resolved) {
     grpc_resolved_addresses_destroy(resolved);
diff --git a/src/core/surface/secure_channel_create.c b/src/core/surface/secure_channel_create.c
index 96b2fe0..e7d223b 100644
--- a/src/core/surface/secure_channel_create.c
+++ b/src/core/surface/secure_channel_create.c
@@ -48,7 +48,7 @@
 #include "src/core/iomgr/resolve_address.h"
 #include "src/core/iomgr/tcp_client.h"
 #include "src/core/security/auth.h"
-#include "src/core/security/security_context.h"
+#include "src/core/security/credentials.h"
 #include "src/core/security/secure_transport_setup.h"
 #include "src/core/support/string.h"
 #include "src/core/surface/channel.h"
@@ -74,7 +74,7 @@
 } request;
 
 struct setup {
-  grpc_channel_security_context *security_context;
+  grpc_channel_security_connector *security_connector;
   const char *target;
   grpc_transport_setup_callback setup_callback;
   void *setup_user_data;
@@ -130,7 +130,7 @@
       return;
     }
   } else {
-    grpc_setup_secure_transport(&r->setup->security_context->base, tcp,
+    grpc_setup_secure_transport(&r->setup->security_connector->base, tcp,
                                 on_secure_transport_setup_done, r);
   }
 }
@@ -185,7 +185,7 @@
 static void done_setup(void *sp) {
   setup *s = sp;
   gpr_free((void *)s->target);
-  grpc_security_context_unref(&s->security_context->base);
+  grpc_security_connector_unref(&s->security_connector->base);
   gpr_free(s);
 }
 
@@ -203,23 +203,37 @@
    Asynchronously: - resolve target
                    - connect to it (trying alternatives as presented)
                    - perform handshakes */
-grpc_channel *grpc_secure_channel_create_internal(
-    const char *target, const grpc_channel_args *args,
-    grpc_channel_security_context *context, grpc_mdctx *mdctx) {
+grpc_channel *grpc_secure_channel_create(grpc_credentials *creds,
+                                         const char *target,
+                                         const grpc_channel_args *args) {
   setup *s;
   grpc_channel *channel;
-  grpc_arg context_arg;
+  grpc_arg connector_arg;
   grpc_channel_args *args_copy;
+  grpc_channel_args *new_args_from_connector;
+  grpc_channel_security_connector* connector;
+  grpc_mdctx *mdctx;
 #define MAX_FILTERS 3
   const grpc_channel_filter *filters[MAX_FILTERS];
   int n = 0;
-  if (grpc_find_security_context_in_args(args) != NULL) {
+
+  if (grpc_find_security_connector_in_args(args) != NULL) {
     gpr_log(GPR_ERROR, "Cannot set security context in channel args.");
+    return grpc_lame_client_channel_create();
   }
 
+  if (grpc_credentials_create_security_connector(
+          creds, target, args, NULL, &connector, &new_args_from_connector) !=
+      GRPC_SECURITY_OK) {
+    return grpc_lame_client_channel_create();
+  }
+  mdctx = grpc_credentials_get_or_create_metadata_context(creds);
+
   s = gpr_malloc(sizeof(setup));
-  context_arg = grpc_security_context_to_arg(&context->base);
-  args_copy = grpc_channel_args_copy_and_add(args, &context_arg);
+  connector_arg = grpc_security_connector_to_arg(&connector->base);
+  args_copy = grpc_channel_args_copy_and_add(
+      new_args_from_connector != NULL ? new_args_from_connector : args,
+      &connector_arg);
   filters[n++] = &grpc_client_surface_filter;
   if (grpc_channel_args_is_census_enabled(args)) {
     filters[n++] = &grpc_client_census_filter;
@@ -228,13 +242,14 @@
   GPR_ASSERT(n <= MAX_FILTERS);
   channel = grpc_channel_create_from_filters(filters, n, args_copy, mdctx, 1);
   grpc_channel_args_destroy(args_copy);
+  if (new_args_from_connector != NULL) {
+    grpc_channel_args_destroy(new_args_from_connector);
+  }
 
   s->target = gpr_strdup(target);
   s->setup_callback = complete_setup;
   s->setup_user_data = grpc_channel_get_channel_stack(channel);
-  s->security_context =
-      (grpc_channel_security_context *)grpc_security_context_ref(
-          &context->base);
+  s->security_connector = connector;
   grpc_client_setup_create_and_attach(grpc_channel_get_channel_stack(channel),
                                       args, mdctx, initiate_setup, done_setup,
                                       s);
diff --git a/src/core/transport/chttp2/frame.h b/src/core/transport/chttp2/frame.h
index fbb9419..ac76c4c 100644
--- a/src/core/transport/chttp2/frame.h
+++ b/src/core/transport/chttp2/frame.h
@@ -54,6 +54,7 @@
   gpr_uint8 process_ping_reply;
   gpr_uint8 goaway;
 
+  gpr_int64 initial_window_update;
   gpr_uint32 window_update;
   gpr_uint32 goaway_last_stream_index;
   gpr_uint32 goaway_error;
diff --git a/src/core/transport/chttp2/frame_settings.c b/src/core/transport/chttp2/frame_settings.c
index 8d3250c..2ffce73 100644
--- a/src/core/transport/chttp2/frame_settings.c
+++ b/src/core/transport/chttp2/frame_settings.c
@@ -218,6 +218,14 @@
                 return GRPC_CHTTP2_CONNECTION_ERROR;
             }
           }
+          if (parser->id == GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE &&
+              parser->incoming_settings[parser->id] != parser->value) {
+            state->initial_window_update =
+                (gpr_int64)parser->value -
+                parser->incoming_settings[parser->id];
+            gpr_log(GPR_DEBUG, "adding %d for initial_window change",
+                    (int)state->initial_window_update);
+          }
           parser->incoming_settings[parser->id] = parser->value;
           if (grpc_http_trace) {
             gpr_log(GPR_DEBUG, "CHTTP2: got setting %d = %d", parser->id,
diff --git a/src/core/transport/chttp2_transport.c b/src/core/transport/chttp2_transport.c
index 110a4b5..995d640 100644
--- a/src/core/transport/chttp2_transport.c
+++ b/src/core/transport/chttp2_transport.c
@@ -276,8 +276,8 @@
 struct stream {
   gpr_uint32 id;
 
-  gpr_uint32 outgoing_window;
   gpr_uint32 incoming_window;
+  gpr_int64 outgoing_window;
   /* when the application requests writes be closed, the write_closed is
      'queued'; when the close is flow controlled into the send path, we are
      'sending' it; when the write has been performed it is 'sent' */
@@ -852,7 +852,8 @@
 
   /* for each stream that's become writable, frame it's data (according to
      available window sizes) and add to the output buffer */
-  while (t->outgoing_window && (s = stream_list_remove_head(t, WRITABLE))) {
+  while (t->outgoing_window && (s = stream_list_remove_head(t, WRITABLE)) &&
+         s->outgoing_window > 0) {
     window_delta = grpc_chttp2_preencode(
         s->outgoing_sopb.ops, &s->outgoing_sopb.nops,
         GPR_MIN(t->outgoing_window, s->outgoing_window), &s->writing_sopb);
@@ -867,7 +868,7 @@
 
     /* if there are still writes to do and the stream still has window
        available, then schedule a further write */
-    if (s->outgoing_sopb.nops && s->outgoing_window) {
+    if (s->outgoing_sopb.nops > 0 && s->outgoing_window > 0) {
       GPR_ASSERT(!t->outgoing_window);
       stream_list_add_tail(t, s, WRITABLE);
     }
@@ -1430,8 +1431,8 @@
   }
 }
 
-static int is_window_update_legal(gpr_uint32 window_update, gpr_uint32 window) {
-  return window_update < MAX_WINDOW - window;
+static int is_window_update_legal(gpr_int64 window_update, gpr_int64 window) {
+  return window + window_update < MAX_WINDOW;
 }
 
 static int parse_frame_slice(transport *t, gpr_slice slice, int is_last) {
@@ -1485,12 +1486,23 @@
           }
         }
       }
+      if (st.initial_window_update) {
+        for (i = 0; i < t->stream_map.count; i++) {
+          stream *s = (stream*)(t->stream_map.values[i]);
+          int was_window_empty = s->outgoing_window <= 0;
+          s->outgoing_window += st.initial_window_update;
+          if (was_window_empty && s->outgoing_window > 0 &&
+              s->outgoing_sopb.nops > 0) {
+            stream_list_join(t, s, WRITABLE);
+          }
+        }
+      }
       if (st.window_update) {
         if (t->incoming_stream_id) {
           /* if there was a stream id, this is for some stream */
           stream *s = lookup_stream(t, t->incoming_stream_id);
           if (s) {
-            int was_window_empty = s->outgoing_window == 0;
+            int was_window_empty = s->outgoing_window <= 0;
             if (!is_window_update_legal(st.window_update, s->outgoing_window)) {
               cancel_stream(t, s, grpc_chttp2_http2_error_to_grpc_status(
                                       GRPC_CHTTP2_FLOW_CONTROL_ERROR),
diff --git a/src/ruby/.rspec b/src/ruby/.rspec
index 60a4aad..dd579f7 100755
--- a/src/ruby/.rspec
+++ b/src/ruby/.rspec
@@ -1 +1,2 @@
 -I.
+--require spec_helper
diff --git a/src/ruby/.rubocop_todo.yml b/src/ruby/.rubocop_todo.yml
index 02136a8..ed4a443 100644
--- a/src/ruby/.rubocop_todo.yml
+++ b/src/ruby/.rubocop_todo.yml
@@ -1,18 +1,18 @@
 # This configuration was generated by `rubocop --auto-gen-config`
-# on 2015-04-16 12:30:09 -0700 using RuboCop version 0.30.0.
+# on 2015-04-17 14:43:27 -0700 using RuboCop version 0.30.0.
 # The point is for the user to remove these configuration records
 # one by one as the offenses are removed from the code base.
 # Note that changes in the inspected code, or installation of new
 # versions of RuboCop, may require this file to be generated again.
 
-# Offense count: 34
+# Offense count: 30
 Metrics/AbcSize:
-  Max: 36
+  Max: 40
 
 # Offense count: 3
 # Configuration parameters: CountComments.
 Metrics/ClassLength:
-  Max: 185
+  Max: 184
 
 # Offense count: 35
 # Configuration parameters: CountComments.
diff --git a/src/ruby/Rakefile b/src/ruby/Rakefile
index afb354e..02af9a8 100755
--- a/src/ruby/Rakefile
+++ b/src/ruby/Rakefile
@@ -26,6 +26,7 @@
   SPEC_SUITES.each do |suite|
     desc "Run all specs in the #{suite[:title]} spec suite"
     RSpec::Core::RakeTask.new(suite[:id]) do |t|
+      ENV['COVERAGE_NAME'] = suite[:id].to_s
       spec_files = []
       suite[:files].each { |f| spec_files += Dir[f] } if suite[:files]
 
diff --git a/src/ruby/grpc.gemspec b/src/ruby/grpc.gemspec
index 12d4ab1..c633579 100755
--- a/src/ruby/grpc.gemspec
+++ b/src/ruby/grpc.gemspec
@@ -13,6 +13,9 @@
   s.description   = 'Send RPCs from Ruby using GRPC'
   s.license       = 'BSD-3-Clause'
 
+  s.required_ruby_version = '>= 2.0.0'
+  s.requirements << 'libgrpc ~> 0.6.0 needs to be installed'
+
   s.files         = `git ls-files`.split("\n")
   s.test_files    = `git ls-files -- spec/*`.split("\n")
   s.executables   = `git ls-files -- bin/*.rb`.split("\n").map do |f|
@@ -25,13 +28,13 @@
   s.add_dependency 'googleauth', '~> 0.4'  # reqd for interop tests
   s.add_dependency 'logging', '~> 1.8'
   s.add_dependency 'minitest', '~> 5.4'  # reqd for interop tests
-  s.add_dependency 'xray', '~> 1.1'
 
+  s.add_development_dependency 'simplecov', '~> 0.9'
   s.add_development_dependency 'bundler', '~> 1.9'
   s.add_development_dependency 'rake', '~> 10.4'
   s.add_development_dependency 'rake-compiler', '~> 0.9'
-  s.add_development_dependency 'rubocop', '~> 0.30'
   s.add_development_dependency 'rspec', '~> 3.2'
+  s.add_development_dependency 'rubocop', '~> 0.30'
 
   s.extensions = %w(ext/grpc/extconf.rb)
 end
diff --git a/src/ruby/lib/grpc/errors.rb b/src/ruby/lib/grpc/errors.rb
index 35e9c02..f1201c1 100644
--- a/src/ruby/lib/grpc/errors.rb
+++ b/src/ruby/lib/grpc/errors.rb
@@ -36,14 +36,15 @@
   # error should be returned to the other end of a GRPC connection; when
   # caught it means that this end received a status error.
   class BadStatus < StandardError
-    attr_reader :code, :details
+    attr_reader :code, :details, :metadata
 
     # @param code [Numeric] the status code
     # @param details [String] the details of the exception
-    def initialize(code, details = 'unknown cause')
+    def initialize(code, details = 'unknown cause', **kw)
       super("#{code}:#{details}")
       @code = code
       @details = details
+      @metadata = kw
     end
 
     # Converts the exception to a GRPC::Status for use in the networking
@@ -51,7 +52,7 @@
     #
     # @return [Status] with the same code and details
     def to_status
-      Status.new(code, details)
+      Struct::Status.new(code, details, @metadata)
     end
   end
 
diff --git a/src/ruby/lib/grpc/generic/active_call.rb b/src/ruby/lib/grpc/generic/active_call.rb
index 8d63de4..43ba549 100644
--- a/src/ruby/lib/grpc/generic/active_call.rb
+++ b/src/ruby/lib/grpc/generic/active_call.rb
@@ -39,7 +39,10 @@
       return nil if status.nil?
       fail GRPC::Cancelled if status.code == GRPC::Core::StatusCodes::CANCELLED
       if status.code != GRPC::Core::StatusCodes::OK
-        fail GRPC::BadStatus.new(status.code, status.details)
+        # raise BadStatus, propagating the metadata if present.
+        md = status.metadata
+        with_sym_keys = Hash[md.each_pair.collect { |x, y| [x.to_sym, y] }]
+        fail GRPC::BadStatus.new(status.code, status.details, **with_sym_keys)
       end
       status
     end
@@ -119,6 +122,12 @@
       @metadata_tag = metadata_tag
     end
 
+    # output_metadata are provides access to hash that can be used to
+    # save metadata to be sent as trailer
+    def output_metadata
+      @output_metadata ||= {}
+    end
+
     # multi_req_view provides a restricted view of this ActiveCall for use
     # in a server client-streaming handler.
     def multi_req_view
@@ -161,10 +170,12 @@
     def finished
       batch_result = @call.run_batch(@cq, self, INFINITE_FUTURE,
                                      RECV_STATUS_ON_CLIENT => nil)
-      if @call.metadata.nil?
-        @call.metadata = batch_result.metadata
-      elsif !batch_result.metadata.nil?
-        @call.metadata.merge!(batch_result.metadata)
+      unless batch_result.status.nil?
+        if @call.metadata.nil?
+          @call.metadata = batch_result.status.metadata
+        else
+          @call.metadata.merge!(batch_result.status.metadata)
+        end
       end
       batch_result.check_status
     end
@@ -192,9 +203,13 @@
     # @param details [String] details
     # @param assert_finished [true, false] when true(default), waits for
     # FINISHED.
-    def send_status(code = OK, details = '', assert_finished = false)
+    #
+    # == Keyword Arguments ==
+    # any keyword arguments are treated as metadata to be sent to the server
+    # if a keyword value is a list, multiple metadata for it's key are sent
+    def send_status(code = OK, details = '', assert_finished = false, **kw)
       ops = {
-        SEND_STATUS_FROM_SERVER => Struct::Status.new(code, details)
+        SEND_STATUS_FROM_SERVER => Struct::Status.new(code, details, kw)
       }
       ops[RECV_CLOSE_ON_SERVER] = nil if assert_finished
       @call.run_batch(@cq, self, INFINITE_FUTURE, ops)
@@ -438,12 +453,13 @@
 
     # SingleReqView limits access to an ActiveCall's methods for use in server
     # handlers that receive just one request.
-    SingleReqView = view_class(:cancelled, :deadline, :metadata)
+    SingleReqView = view_class(:cancelled, :deadline, :metadata,
+                               :output_metadata)
 
     # MultiReqView limits access to an ActiveCall's methods for use in
     # server client_streamer handlers.
     MultiReqView = view_class(:cancelled, :deadline, :each_queued_msg,
-                              :each_remote_read, :metadata)
+                              :each_remote_read, :metadata, :output_metadata)
 
     # Operation limits access to an ActiveCall's methods for use as
     # a Operation on the client.
diff --git a/src/ruby/lib/grpc/generic/client_stub.rb b/src/ruby/lib/grpc/generic/client_stub.rb
index dc7672d..7b2c04a 100644
--- a/src/ruby/lib/grpc/generic/client_stub.rb
+++ b/src/ruby/lib/grpc/generic/client_stub.rb
@@ -28,7 +28,6 @@
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 require 'grpc/generic/active_call'
-require 'xray/thread_dump_signal_handler'
 
 # GRPC contains the General RPC module.
 module GRPC
diff --git a/src/ruby/lib/grpc/generic/rpc_desc.rb b/src/ruby/lib/grpc/generic/rpc_desc.rb
index 3e48b8e..10211ae 100644
--- a/src/ruby/lib/grpc/generic/rpc_desc.rb
+++ b/src/ruby/lib/grpc/generic/rpc_desc.rb
@@ -80,12 +80,12 @@
       else  # is a bidi_stream
         active_call.run_server_bidi(mth)
       end
-      send_status(active_call, OK, 'OK')
+      send_status(active_call, OK, 'OK', **active_call.output_metadata)
     rescue BadStatus => e
-      # this is raised by handlers that want GRPC to send an application
-      # error code and detail message.
+      # this is raised by handlers that want GRPC to send an application error
+      # code and detail message and some additional app-specific metadata.
       logger.debug("app err: #{active_call}, status:#{e.code}:#{e.details}")
-      send_status(active_call, e.code, e.details)
+      send_status(active_call, e.code, e.details, **e.metadata)
     rescue Core::CallError => e
       # This is raised by GRPC internals but should rarely, if ever happen.
       # Log it, but don't notify the other endpoint..
@@ -135,9 +135,9 @@
       "##{mth.name}: bad arg count; got:#{mth.arity}, want:#{want}, #{msg}"
     end
 
-    def send_status(active_client, code, details)
+    def send_status(active_client, code, details, **kw)
       details = 'Not sure why' if details.nil?
-      active_client.send_status(code, details, code == OK)
+      active_client.send_status(code, details, code == OK, **kw)
     rescue StandardError => e
       logger.warn("Could not send status #{code}:#{details}")
       logger.warn(e)
diff --git a/src/ruby/lib/grpc/generic/rpc_server.rb b/src/ruby/lib/grpc/generic/rpc_server.rb
index bc2211e..88c24aa 100644
--- a/src/ruby/lib/grpc/generic/rpc_server.rb
+++ b/src/ruby/lib/grpc/generic/rpc_server.rb
@@ -31,13 +31,126 @@
 require 'grpc/generic/active_call'
 require 'grpc/generic/service'
 require 'thread'
-require 'xray/thread_dump_signal_handler'
 
 # A global that contains signals the gRPC servers should respond to.
 $grpc_signals = []
 
 # GRPC contains the General RPC module.
 module GRPC
+  # Handles the signals in $grpc_signals.
+  #
+  # @return false if the server should exit, true if not.
+  def handle_signals
+    loop do
+      sig = $grpc_signals.shift
+      case sig
+      when 'INT'
+        return false
+      when 'TERM'
+        return false
+      end
+    end
+    true
+  end
+  module_function :handle_signals
+
+  # Pool is a simple thread pool.
+  class Pool
+    # Default keep alive period is 1s
+    DEFAULT_KEEP_ALIVE = 1
+
+    def initialize(size, keep_alive: DEFAULT_KEEP_ALIVE)
+      fail 'pool size must be positive' unless size > 0
+      @jobs = Queue.new
+      @size = size
+      @stopped = false
+      @stop_mutex = Mutex.new
+      @stop_cond = ConditionVariable.new
+      @workers = []
+      @keep_alive = keep_alive
+    end
+
+    # Returns the number of jobs waiting
+    def jobs_waiting
+      @jobs.size
+    end
+
+    # Runs the given block on the queue with the provided args.
+    #
+    # @param args the args passed blk when it is called
+    # @param blk the block to call
+    def schedule(*args, &blk)
+      fail 'already stopped' if @stopped
+      return if blk.nil?
+      logger.info('schedule another job')
+      @jobs << [blk, args]
+    end
+
+    # Starts running the jobs in the thread pool.
+    def start
+      fail 'already stopped' if @stopped
+      until @workers.size == @size.to_i
+        next_thread = Thread.new do
+          catch(:exit) do  # allows { throw :exit } to kill a thread
+            loop_execute_jobs
+          end
+          remove_current_thread
+        end
+        @workers << next_thread
+      end
+    end
+
+    # Stops the jobs in the pool
+    def stop
+      logger.info('stopping, will wait for all the workers to exit')
+      @workers.size.times { schedule { throw :exit } }
+      @stopped = true
+      @stop_mutex.synchronize do  # wait @keep_alive for works to stop
+        @stop_cond.wait(@stop_mutex, @keep_alive) if @workers.size > 0
+      end
+      forcibly_stop_workers
+      logger.info('stopped, all workers are shutdown')
+    end
+
+    protected
+
+    # Forcibly shutdown any threads that are still alive.
+    def forcibly_stop_workers
+      return unless @workers.size > 0
+      logger.info("forcibly terminating #{@workers.size} worker(s)")
+      @workers.each do |t|
+        next unless t.alive?
+        begin
+          t.exit
+        rescue StandardError => e
+          logger.warn('error while terminating a worker')
+          logger.warn(e)
+        end
+      end
+    end
+
+    # removes the threads from workers, and signal when all the
+    # threads are complete.
+    def remove_current_thread
+      @stop_mutex.synchronize do
+        @workers.delete(Thread.current)
+        @stop_cond.signal if @workers.size == 0
+      end
+    end
+
+    def loop_execute_jobs
+      loop do
+        begin
+          blk, args = @jobs.pop
+          blk.call(*args)
+        rescue StandardError => e
+          logger.warn('Error in worker thread')
+          logger.warn(e)
+        end
+      end
+    end
+  end
+
   # RpcServer hosts a number of services and makes them available on the
   # network.
   class RpcServer
@@ -70,6 +183,32 @@
       %w(INT TERM).each { |sig| trap(sig) { $grpc_signals << sig } }
     end
 
+    # setup_cq is used by #initialize to constuct a Core::CompletionQueue from
+    # its arguments.
+    def self.setup_cq(alt_cq)
+      return Core::CompletionQueue.new if alt_cq.nil?
+      unless alt_cq.is_a? Core::CompletionQueue
+        fail(TypeError, '!CompletionQueue')
+      end
+      alt_cq
+    end
+
+    # setup_srv is used by #initialize to constuct a Core::Server from its
+    # arguments.
+    def self.setup_srv(alt_srv, cq, **kw)
+      return Core::Server.new(cq, kw) if alt_srv.nil?
+      fail(TypeError, '!Server') unless alt_srv.is_a? Core::Server
+      alt_srv
+    end
+
+    # setup_connect_md_proc is used by #initialize to validate the
+    # connect_md_proc.
+    def self.setup_connect_md_proc(a_proc)
+      return nil if a_proc.nil?
+      fail(TypeError, '!Proc') unless a_proc.is_a? Proc
+      a_proc
+    end
+
     # Creates a new RpcServer.
     #
     # The RPC server is configured using keyword arguments.
@@ -97,30 +236,21 @@
     # * max_waiting_requests: the maximum number of requests that are not
     # being handled to allow. When this limit is exceeded, the server responds
     # with not available to new requests
+    #
+    # * connect_md_proc:
+    # when non-nil is a proc for determining metadata to to send back the client
+    # on receiving an invocation req.  The proc signature is:
+    # {key: val, ..} func(method_name, {key: val, ...})
     def initialize(pool_size:DEFAULT_POOL_SIZE,
                    max_waiting_requests:DEFAULT_MAX_WAITING_REQUESTS,
                    poll_period:DEFAULT_POLL_PERIOD,
                    completion_queue_override:nil,
                    server_override:nil,
+                   connect_md_proc:nil,
                    **kw)
-      if completion_queue_override.nil?
-        cq = Core::CompletionQueue.new
-      else
-        cq = completion_queue_override
-        unless cq.is_a? Core::CompletionQueue
-          fail(ArgumentError, 'not a CompletionQueue')
-        end
-      end
-      @cq = cq
-
-      if server_override.nil?
-        srv = Core::Server.new(@cq, kw)
-      else
-        srv = server_override
-        fail(ArgumentError, 'not a Server') unless srv.is_a? Core::Server
-      end
-      @server = srv
-
+      @cq = RpcServer.setup_cq(completion_queue_override)
+      @server = RpcServer.setup_srv(server_override, @cq, **kw)
+      @connect_md_proc = RpcServer.setup_connect_md_proc(connect_md_proc)
       @pool_size = pool_size
       @max_waiting_requests = max_waiting_requests
       @poll_period = poll_period
@@ -180,22 +310,6 @@
       t.join
     end
 
-    # Handles the signals in $grpc_signals.
-    #
-    # @return false if the server should exit, true if not.
-    def handle_signals
-      loop do
-        sig = $grpc_signals.shift
-        case sig
-        when 'INT'
-          return false
-        when 'TERM'
-          return false
-        end
-      end
-      true
-    end
-
     # Determines if the server is currently stopped
     def stopped?
       @stopped ||= false
@@ -259,19 +373,7 @@
       end
       @pool.start
       @server.start
-      request_call_tag = Object.new
-      until stopped?
-        deadline = from_relative_time(@poll_period)
-        an_rpc = @server.request_call(@cq, request_call_tag, deadline)
-        next if an_rpc.nil?
-        c = new_active_server_call(an_rpc)
-        unless c.nil?
-          mth = an_rpc.method.to_sym
-          @pool.schedule(c) do |call|
-            rpc_descs[mth].run_server_method(call, rpc_handlers[mth])
-          end
-        end
-      end
+      loop_handle_server_calls
       @running = false
     end
 
@@ -298,17 +400,35 @@
       nil
     end
 
+    # handles calls to the server
+    def loop_handle_server_calls
+      fail 'not running' unless @running
+      request_call_tag = Object.new
+      until stopped?
+        deadline = from_relative_time(@poll_period)
+        an_rpc = @server.request_call(@cq, request_call_tag, deadline)
+        c = new_active_server_call(an_rpc)
+        unless c.nil?
+          mth = an_rpc.method.to_sym
+          @pool.schedule(c) do |call|
+            rpc_descs[mth].run_server_method(call, rpc_handlers[mth])
+          end
+        end
+      end
+    end
+
     def new_active_server_call(an_rpc)
-      # Accept the call.  This is necessary even if a status is to be sent
-      # back immediately
       return nil if an_rpc.nil? || an_rpc.call.nil?
 
       # allow the metadata to be accessed from the call
       handle_call_tag = Object.new
-      an_rpc.call.metadata = an_rpc.metadata
-      # TODO: add a hook to send md
+      an_rpc.call.metadata = an_rpc.metadata  # attaches md to call for handlers
+      connect_md = nil
+      unless @connect_md_proc.nil?
+        connect_md = @connect_md_proc.call(an_rpc.method, an_rpc.metadata)
+      end
       an_rpc.call.run_batch(@cq, handle_call_tag, INFINITE_FUTURE,
-                            SEND_INITIAL_METADATA => nil)
+                            SEND_INITIAL_METADATA => connect_md)
       return nil unless available?(an_rpc)
       return nil unless found?(an_rpc)
 
@@ -320,93 +440,6 @@
                      an_rpc.deadline)
     end
 
-    # Pool is a simple thread pool for running server requests.
-    class Pool
-      # Default keep alive period is 1s
-      DEFAULT_KEEP_ALIVE = 1
-
-      def initialize(size, keep_alive: DEFAULT_KEEP_ALIVE)
-        fail 'pool size must be positive' unless size > 0
-        @jobs = Queue.new
-        @size = size
-        @stopped = false
-        @stop_mutex = Mutex.new
-        @stop_cond = ConditionVariable.new
-        @workers = []
-        @keep_alive = keep_alive
-      end
-
-      # Returns the number of jobs waiting
-      def jobs_waiting
-        @jobs.size
-      end
-
-      # Runs the given block on the queue with the provided args.
-      #
-      # @param args the args passed blk when it is called
-      # @param blk the block to call
-      def schedule(*args, &blk)
-        fail 'already stopped' if @stopped
-        return if blk.nil?
-        logger.info('schedule another job')
-        @jobs << [blk, args]
-      end
-
-      # Starts running the jobs in the thread pool.
-      def start
-        fail 'already stopped' if @stopped
-        until @workers.size == @size.to_i
-          next_thread = Thread.new do
-            catch(:exit) do  # allows { throw :exit } to kill a thread
-              loop do
-                begin
-                  blk, args = @jobs.pop
-                  blk.call(*args)
-                rescue StandardError => e
-                  logger.warn('Error in worker thread')
-                  logger.warn(e)
-                end
-              end
-            end
-
-            # removes the threads from workers, and signal when all the
-            # threads are complete.
-            @stop_mutex.synchronize do
-              @workers.delete(Thread.current)
-              @stop_cond.signal if @workers.size == 0
-            end
-          end
-          @workers << next_thread
-        end
-      end
-
-      # Stops the jobs in the pool
-      def stop
-        logger.info('stopping, will wait for all the workers to exit')
-        @workers.size.times { schedule { throw :exit } }
-        @stopped = true
-
-        @stop_mutex.synchronize do
-          @stop_cond.wait(@stop_mutex, @keep_alive) if @workers.size > 0
-        end
-
-        # Forcibly shutdown any threads that are still alive.
-        if @workers.size > 0
-          logger.info("forcibly terminating #{@workers.size} worker(s)")
-          @workers.each do |t|
-            next unless t.alive?
-            begin
-              t.exit
-            rescue StandardError => e
-              logger.warn('error while terminating a worker')
-              logger.warn(e)
-            end
-          end
-        end
-        logger.info('stopped, all workers are shutdown')
-      end
-    end
-
     protected
 
     def rpc_descs
@@ -417,11 +450,9 @@
       @rpc_handlers ||= {}
     end
 
-    private
-
     def assert_valid_service_class(cls)
       unless cls.include?(GenericService)
-        fail "#{cls} should 'include GenericService'"
+        fail "#{cls} must 'include GenericService'"
       end
       if cls.rpc_descs.size == 0
         fail "#{cls} should specify some rpc descriptions"
@@ -431,21 +462,17 @@
 
     def add_rpc_descs_for(service)
       cls = service.is_a?(Class) ? service : service.class
-      specs = rpc_descs
-      handlers = rpc_handlers
+      specs, handlers = rpc_descs, rpc_handlers
       cls.rpc_descs.each_pair do |name, spec|
         route = "/#{cls.service_name}/#{name}".to_sym
-        if specs.key? route
-          fail "Cannot add rpc #{route} from #{spec}, already registered"
+        fail "already registered: rpc #{route} from #{spec}" if specs.key? route
+        specs[route] = spec
+        if service.is_a?(Class)
+          handlers[route] = cls.new.method(name.to_s.underscore.to_sym)
         else
-          specs[route] = spec
-          if service.is_a?(Class)
-            handlers[route] = cls.new.method(name.to_s.underscore.to_sym)
-          else
-            handlers[route] = service.method(name.to_s.underscore.to_sym)
-          end
-          logger.info("handling #{route} with #{handlers[route]}")
+          handlers[route] = service.method(name.to_s.underscore.to_sym)
         end
+        logger.info("handling #{route} with #{handlers[route]}")
       end
     end
   end
diff --git a/src/ruby/spec/credentials_spec.rb b/src/ruby/spec/credentials_spec.rb
index fc97d11..8e72e85 100644
--- a/src/ruby/spec/credentials_spec.rb
+++ b/src/ruby/spec/credentials_spec.rb
@@ -61,11 +61,11 @@
   end
 
   describe '#compose' do
-    it 'can be completed OK' do
+    it 'cannot be completed OK with 2 SSL creds' do
       certs = load_test_certs
       cred1 = Credentials.new(*certs)
       cred2 = Credentials.new(*certs)
-      expect { cred1.compose(cred2) }.to_not raise_error
+      expect { cred1.compose(cred2) }.to raise_error
     end
   end
 end
diff --git a/src/ruby/spec/generic/client_stub_spec.rb b/src/ruby/spec/generic/client_stub_spec.rb
index 193c5f2..88c6b44 100644
--- a/src/ruby/spec/generic/client_stub_spec.rb
+++ b/src/ruby/spec/generic/client_stub_spec.rb
@@ -28,7 +28,6 @@
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 require 'grpc'
-require 'xray/thread_dump_signal_handler'
 
 # Notifier is useful high-level synchronization primitive.
 class Notifier
diff --git a/src/ruby/spec/generic/rpc_desc_spec.rb b/src/ruby/spec/generic/rpc_desc_spec.rb
index a682994..083632a 100644
--- a/src/ruby/spec/generic/rpc_desc_spec.rb
+++ b/src/ruby/spec/generic/rpc_desc_spec.rb
@@ -52,41 +52,49 @@
     @ok_response = Object.new
   end
 
+  shared_examples 'it handles errors' do
+    it 'sends the specified status if BadStatus is raised' do
+      expect(@call).to receive(:remote_read).once.and_return(Object.new)
+      expect(@call).to receive(:send_status).once.with(@bs_code, 'NOK', false,
+                                                       {})
+      this_desc.run_server_method(@call, method(:bad_status))
+    end
+
+    it 'sends status UNKNOWN if other StandardErrors are raised' do
+      expect(@call).to receive(:remote_read).once.and_return(Object.new)
+      expect(@call).to receive(:send_status) .once.with(UNKNOWN, @no_reason,
+                                                        false, {})
+      this_desc.run_server_method(@call, method(:other_error))
+    end
+
+    it 'absorbs CallError with no further action' do
+      expect(@call).to receive(:remote_read).once.and_raise(CallError)
+      blk = proc do
+        this_desc.run_server_method(@call, method(:fake_reqresp))
+      end
+      expect(&blk).to_not raise_error
+    end
+  end
+
   describe '#run_server_method' do
+    let(:fake_md) { { k1: 'v1', k2: 'v2' } }
     describe 'for request responses' do
+      let(:this_desc) { @request_response }
       before(:each) do
         @call = double('active_call')
         allow(@call).to receive(:single_req_view).and_return(@call)
-        allow(@call).to receive(:gc)
       end
 
-      it 'sends the specified status if BadStatus is raised' do
-        expect(@call).to receive(:remote_read).once.and_return(Object.new)
-        expect(@call).to receive(:send_status).once.with(@bs_code, 'NOK', false)
-        @request_response.run_server_method(@call, method(:bad_status))
-      end
-
-      it 'sends status UNKNOWN if other StandardErrors are raised' do
-        expect(@call).to receive(:remote_read).once.and_return(Object.new)
-        expect(@call).to receive(:send_status) .once.with(UNKNOWN, @no_reason,
-                                                          false)
-        @request_response.run_server_method(@call, method(:other_error))
-      end
-
-      it 'absorbs CallError with no further action' do
-        expect(@call).to receive(:remote_read).once.and_raise(CallError)
-        blk = proc do
-          @request_response.run_server_method(@call, method(:fake_reqresp))
-        end
-        expect(&blk).to_not raise_error
-      end
+      it_behaves_like 'it handles errors'
 
       it 'sends a response and closes the stream if there no errors' do
         req = Object.new
         expect(@call).to receive(:remote_read).once.and_return(req)
         expect(@call).to receive(:remote_send).once.with(@ok_response)
-        expect(@call).to receive(:send_status).once.with(OK, 'OK', true)
-        @request_response.run_server_method(@call, method(:fake_reqresp))
+        expect(@call).to receive(:output_metadata).and_return(fake_md)
+        expect(@call).to receive(:send_status).once.with(OK, 'OK', true,
+                                                         **fake_md)
+        this_desc.run_server_method(@call, method(:fake_reqresp))
       end
     end
 
@@ -94,17 +102,17 @@
       before(:each) do
         @call = double('active_call')
         allow(@call).to receive(:multi_req_view).and_return(@call)
-        allow(@call).to receive(:gc)
       end
 
       it 'sends the specified status if BadStatus is raised' do
-        expect(@call).to receive(:send_status).once.with(@bs_code, 'NOK', false)
+        expect(@call).to receive(:send_status).once.with(@bs_code, 'NOK', false,
+                                                         {})
         @client_streamer.run_server_method(@call, method(:bad_status_alt))
       end
 
       it 'sends status UNKNOWN if other StandardErrors are raised' do
         expect(@call).to receive(:send_status) .once.with(UNKNOWN, @no_reason,
-                                                          false)
+                                                          false, {})
         @client_streamer.run_server_method(@call, method(:other_error_alt))
       end
 
@@ -118,44 +126,29 @@
 
       it 'sends a response and closes the stream if there no errors' do
         expect(@call).to receive(:remote_send).once.with(@ok_response)
-        expect(@call).to receive(:send_status).once.with(OK, 'OK', true)
+        expect(@call).to receive(:output_metadata).and_return(fake_md)
+        expect(@call).to receive(:send_status).once.with(OK, 'OK', true,
+                                                         **fake_md)
         @client_streamer.run_server_method(@call, method(:fake_clstream))
       end
     end
 
     describe 'for server streaming' do
+      let(:this_desc) { @request_response }
       before(:each) do
         @call = double('active_call')
         allow(@call).to receive(:single_req_view).and_return(@call)
-        allow(@call).to receive(:gc)
       end
 
-      it 'sends the specified status if BadStatus is raised' do
-        expect(@call).to receive(:remote_read).once.and_return(Object.new)
-        expect(@call).to receive(:send_status).once.with(@bs_code, 'NOK', false)
-        @server_streamer.run_server_method(@call, method(:bad_status))
-      end
-
-      it 'sends status UNKNOWN if other StandardErrors are raised' do
-        expect(@call).to receive(:remote_read).once.and_return(Object.new)
-        expect(@call).to receive(:send_status) .once.with(UNKNOWN, @no_reason,
-                                                          false)
-        @server_streamer.run_server_method(@call, method(:other_error))
-      end
-
-      it 'absorbs CallError with no further action' do
-        expect(@call).to receive(:remote_read).once.and_raise(CallError)
-        blk = proc do
-          @server_streamer.run_server_method(@call, method(:fake_svstream))
-        end
-        expect(&blk).to_not raise_error
-      end
+      it_behaves_like 'it handles errors'
 
       it 'sends a response and closes the stream if there no errors' do
         req = Object.new
         expect(@call).to receive(:remote_read).once.and_return(req)
         expect(@call).to receive(:remote_send).twice.with(@ok_response)
-        expect(@call).to receive(:send_status).once.with(OK, 'OK', true)
+        expect(@call).to receive(:output_metadata).and_return(fake_md)
+        expect(@call).to receive(:send_status).once.with(OK, 'OK', true,
+                                                         **fake_md)
         @server_streamer.run_server_method(@call, method(:fake_svstream))
       end
     end
@@ -166,26 +159,28 @@
         enq_th, rwl_th = double('enqueue_th'), ('read_write_loop_th')
         allow(enq_th).to receive(:join)
         allow(rwl_th).to receive(:join)
-        allow(@call).to receive(:gc)
       end
 
       it 'sends the specified status if BadStatus is raised' do
         e = GRPC::BadStatus.new(@bs_code, 'NOK')
         expect(@call).to receive(:run_server_bidi).and_raise(e)
-        expect(@call).to receive(:send_status).once.with(@bs_code, 'NOK', false)
+        expect(@call).to receive(:send_status).once.with(@bs_code, 'NOK', false,
+                                                         {})
         @bidi_streamer.run_server_method(@call, method(:bad_status_alt))
       end
 
       it 'sends status UNKNOWN if other StandardErrors are raised' do
         expect(@call).to receive(:run_server_bidi).and_raise(StandardError)
         expect(@call).to receive(:send_status).once.with(UNKNOWN, @no_reason,
-                                                         false)
+                                                         false, {})
         @bidi_streamer.run_server_method(@call, method(:other_error_alt))
       end
 
       it 'closes the stream if there no errors' do
         expect(@call).to receive(:run_server_bidi)
-        expect(@call).to receive(:send_status).once.with(OK, 'OK', true)
+        expect(@call).to receive(:output_metadata).and_return(fake_md)
+        expect(@call).to receive(:send_status).once.with(OK, 'OK', true,
+                                                         **fake_md)
         @bidi_streamer.run_server_method(@call, method(:fake_bidistream))
       end
     end
diff --git a/src/ruby/spec/generic/rpc_server_pool_spec.rb b/src/ruby/spec/generic/rpc_server_pool_spec.rb
index 8383dc1..aae3a7d 100644
--- a/src/ruby/spec/generic/rpc_server_pool_spec.rb
+++ b/src/ruby/spec/generic/rpc_server_pool_spec.rb
@@ -28,11 +28,10 @@
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 require 'grpc'
-require 'xray/thread_dump_signal_handler'
 
-Pool = GRPC::RpcServer::Pool
+describe GRPC::Pool do
+  Pool = GRPC::Pool
 
-describe Pool do
   describe '#new' do
     it 'raises if a non-positive size is used' do
       expect { Pool.new(0) }.to raise_error
diff --git a/src/ruby/spec/generic/rpc_server_spec.rb b/src/ruby/spec/generic/rpc_server_spec.rb
index 1323bac..2cd21a1 100644
--- a/src/ruby/spec/generic/rpc_server_spec.rb
+++ b/src/ruby/spec/generic/rpc_server_spec.rb
@@ -28,7 +28,6 @@
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 require 'grpc'
-require 'xray/thread_dump_signal_handler'
 
 def load_test_certs
   test_root = File.join(File.dirname(File.dirname(__FILE__)), 'testdata')
@@ -58,18 +57,20 @@
   rpc :an_rpc, EchoMsg, EchoMsg
 end
 
-# A test service with an implementation.
+# A test service with an echo implementation.
 class EchoService
   include GRPC::GenericService
   rpc :an_rpc, EchoMsg, EchoMsg
   attr_reader :received_md
 
-  def initialize(_default_var = 'ignored')
+  def initialize(**kw)
+    @trailing_metadata = kw
     @received_md = []
   end
 
   def an_rpc(req, call)
     logger.info('echo service received a request')
+    call.output_metadata.update(@trailing_metadata)
     @received_md << call.metadata unless call.metadata.nil?
     req
   end
@@ -77,6 +78,25 @@
 
 EchoStub = EchoService.rpc_stub_class
 
+# A test service with an implementation that fails with BadStatus
+class FailingService
+  include GRPC::GenericService
+  rpc :an_rpc, EchoMsg, EchoMsg
+  attr_reader :details, :code, :md
+
+  def initialize(_default_var = 'ignored')
+    @details = 'app error'
+    @code = 101
+    @md = { failed_method: 'an_rpc' }
+  end
+
+  def an_rpc(_req, _call)
+    fail GRPC::BadStatus.new(@code, @details, **@md)
+  end
+end
+
+FailingStub = FailingService.rpc_stub_class
+
 # A slow test service.
 class SlowService
   include GRPC::GenericService
@@ -301,21 +321,20 @@
   end
 
   describe '#run' do
-    before(:each) do
-      @client_opts = {
-        channel_override: @ch
-      }
-      @marshal = EchoService.rpc_descs[:an_rpc].marshal_proc
-      @unmarshal = EchoService.rpc_descs[:an_rpc].unmarshal_proc(:output)
-      server_opts = {
-        server_override: @server,
-        completion_queue_override: @server_queue,
-        poll_period: 1
-      }
-      @srv = RpcServer.new(**server_opts)
-    end
+    let(:client_opts) { { channel_override: @ch } }
+    let(:marshal) { EchoService.rpc_descs[:an_rpc].marshal_proc }
+    let(:unmarshal) { EchoService.rpc_descs[:an_rpc].unmarshal_proc(:output) }
 
-    describe 'when running' do
+    context 'with no connect_metadata' do
+      before(:each) do
+        server_opts = {
+          server_override: @server,
+          completion_queue_override: @server_queue,
+          poll_period: 1
+        }
+        @srv = RpcServer.new(**server_opts)
+      end
+
       it 'should return NOT_FOUND status on unknown methods', server: true do
         @srv.handle(EchoService)
         t = Thread.new { @srv.run }
@@ -323,8 +342,8 @@
         req = EchoMsg.new
         blk = proc do
           cq = GRPC::Core::CompletionQueue.new
-          stub = GRPC::ClientStub.new(@host, cq, **@client_opts)
-          stub.request_response('/unknown', req, @marshal, @unmarshal)
+          stub = GRPC::ClientStub.new(@host, cq, **client_opts)
+          stub.request_response('/unknown', req, marshal, unmarshal)
         end
         expect(&blk).to raise_error GRPC::BadStatus
         @srv.stop
@@ -337,7 +356,7 @@
         @srv.wait_till_running
         req = EchoMsg.new
         n = 5  # arbitrary
-        stub = EchoStub.new(@host, **@client_opts)
+        stub = EchoStub.new(@host, **client_opts)
         n.times { expect(stub.an_rpc(req)).to be_a(EchoMsg) }
         @srv.stop
         t.join
@@ -349,7 +368,7 @@
         t = Thread.new { @srv.run }
         @srv.wait_till_running
         req = EchoMsg.new
-        stub = EchoStub.new(@host, **@client_opts)
+        stub = EchoStub.new(@host, **client_opts)
         expect(stub.an_rpc(req, k1: 'v1', k2: 'v2')).to be_a(EchoMsg)
         wanted_md = [{ 'k1' => 'v1', 'k2' => 'v2' }]
         expect(service.received_md).to eq(wanted_md)
@@ -363,7 +382,7 @@
         t = Thread.new { @srv.run }
         @srv.wait_till_running
         req = EchoMsg.new
-        stub = SlowStub.new(@host, **@client_opts)
+        stub = SlowStub.new(@host, **client_opts)
         deadline = service.delay + 1.0 # wait for long enough
         expect(stub.an_rpc(req, deadline, k1: 'v1', k2: 'v2')).to be_a(EchoMsg)
         wanted_md = [{ 'k1' => 'v1', 'k2' => 'v2' }]
@@ -378,7 +397,7 @@
         t = Thread.new { @srv.run }
         @srv.wait_till_running
         req = EchoMsg.new
-        stub = SlowStub.new(@host, **@client_opts)
+        stub = SlowStub.new(@host, **client_opts)
         deadline = 0.1  # too short for SlowService to respond
         blk = proc { stub.an_rpc(req, deadline, k1: 'v1', k2: 'v2') }
         expect(&blk).to raise_error GRPC::BadStatus
@@ -394,7 +413,7 @@
         t = Thread.new { @srv.run }
         @srv.wait_till_running
         req = EchoMsg.new
-        stub = SlowStub.new(@host, **@client_opts)
+        stub = SlowStub.new(@host, **client_opts)
         op = stub.an_rpc(req, k1: 'v1', k2: 'v2', return_op: true)
         Thread.new do  # cancel the call
           sleep 0.1
@@ -411,11 +430,11 @@
         t = Thread.new { @srv.run }
         @srv.wait_till_running
         req = EchoMsg.new
-        @client_opts[:update_metadata] = proc do |md|
+        client_opts[:update_metadata] = proc do |md|
           md[:k1] = 'updated-v1'
           md
         end
-        stub = EchoStub.new(@host, **@client_opts)
+        stub = EchoStub.new(@host, **client_opts)
         expect(stub.an_rpc(req, k1: 'v1', k2: 'v2')).to be_a(EchoMsg)
         wanted_md = [{ 'k1' => 'updated-v1', 'k2' => 'v2',
                        'jwt_aud_uri' => "https://#{@host}/EchoService" }]
@@ -433,7 +452,7 @@
         threads = []
         n.times do
           threads << Thread.new do
-            stub = EchoStub.new(@host, **@client_opts)
+            stub = EchoStub.new(@host, **client_opts)
             q << stub.an_rpc(req)
           end
         end
@@ -461,7 +480,7 @@
         one_failed_as_unavailable = false
         n.times do
           threads << Thread.new do
-            stub = SlowStub.new(@host, **@client_opts)
+            stub = SlowStub.new(@host, **client_opts)
             begin
               stub.an_rpc(req)
             rescue GRPC::BadStatus => e
@@ -474,5 +493,97 @@
         expect(one_failed_as_unavailable).to be(true)
       end
     end
+
+    context 'with connect metadata' do
+      let(:test_md_proc) do
+        proc do |mth, md|
+          res = md.clone
+          res['method'] = mth
+          res['connect_k1'] = 'connect_v1'
+          res
+        end
+      end
+      before(:each) do
+        server_opts = {
+          server_override: @server,
+          completion_queue_override: @server_queue,
+          poll_period: 1,
+          connect_md_proc: test_md_proc
+        }
+        @srv = RpcServer.new(**server_opts)
+      end
+
+      it 'should send connect metadata to the client', server: true do
+        service = EchoService.new
+        @srv.handle(service)
+        t = Thread.new { @srv.run }
+        @srv.wait_till_running
+        req = EchoMsg.new
+        stub = EchoStub.new(@host, **client_opts)
+        op = stub.an_rpc(req, k1: 'v1', k2: 'v2', return_op: true)
+        expect(op.metadata).to be nil
+        expect(op.execute).to be_a(EchoMsg)
+        wanted_md = {
+          'k1' => 'v1',
+          'k2' => 'v2',
+          'method' => '/EchoService/an_rpc',
+          'connect_k1' => 'connect_v1'
+        }
+        expect(op.metadata).to eq(wanted_md)
+        @srv.stop
+        t.join
+      end
+    end
+
+    context 'with trailing metadata' do
+      before(:each) do
+        server_opts = {
+          server_override: @server,
+          completion_queue_override: @server_queue,
+          poll_period: 1
+        }
+        @srv = RpcServer.new(**server_opts)
+      end
+
+      it 'should be added to BadStatus when requests fail', server: true do
+        service = FailingService.new
+        @srv.handle(service)
+        t = Thread.new { @srv.run }
+        @srv.wait_till_running
+        req = EchoMsg.new
+        stub = FailingStub.new(@host, **client_opts)
+        blk = proc { stub.an_rpc(req) }
+
+        # confirm it raise the expected error
+        expect(&blk).to raise_error GRPC::BadStatus
+
+        # call again and confirm exception contained the trailing metadata.
+        begin
+          blk.call
+        rescue GRPC::BadStatus => e
+          expect(e.code).to eq(service.code)
+          expect(e.details).to eq(service.details)
+          expect(e.metadata).to eq(service.md)
+        end
+        @srv.stop
+        t.join
+      end
+
+      it 'should be received by the client', server: true do
+        wanted_trailers = { 'k1' => 'out_v1', 'k2' => 'out_v2' }
+        service = EchoService.new(k1: 'out_v1', k2: 'out_v2')
+        @srv.handle(service)
+        t = Thread.new { @srv.run }
+        @srv.wait_till_running
+        req = EchoMsg.new
+        stub = EchoStub.new(@host, **client_opts)
+        op = stub.an_rpc(req, k1: 'v1', k2: 'v2', return_op: true)
+        expect(op.metadata).to be nil
+        expect(op.execute).to be_a(EchoMsg)
+        expect(op.metadata).to eq(wanted_trailers)
+        @srv.stop
+        t.join
+      end
+    end
   end
 end
diff --git a/src/ruby/spec/spec_helper.rb b/src/ruby/spec/spec_helper.rb
index 837d2fc..101165c 100644
--- a/src/ruby/spec/spec_helper.rb
+++ b/src/ruby/spec/spec_helper.rb
@@ -35,14 +35,18 @@
 $LOAD_PATH.unshift(lib_dir)
 $LOAD_PATH.uniq!
 
-require 'faraday'
+# set up coverage
+require 'simplecov'
+SimpleCov.start do
+  add_filter 'spec'
+  add_filter 'bin'
+  SimpleCov.command_name ENV['COVERAGE_NAME']
+end if ENV['COVERAGE_NAME']
+
 require 'rspec'
 require 'logging'
 require 'rspec/logging_helper'
 
-# Allow Faraday to support test stubs
-Faraday::Adapter.load_middleware(:test)
-
 # Configure RSpec to capture log messages for each test. The output from the
 # logs will be stored in the @log_output variable. It is a StringIO instance.
 RSpec.configure do |config|
diff --git a/test/core/end2end/fixtures/chttp2_fake_security.c b/test/core/end2end/fixtures/chttp2_fake_security.c
index 047d482..929f1f5 100644
--- a/test/core/end2end/fixtures/chttp2_fake_security.c
+++ b/test/core/end2end/fixtures/chttp2_fake_security.c
@@ -38,7 +38,6 @@
 
 #include "src/core/channel/channel_args.h"
 #include "src/core/security/credentials.h"
-#include "src/core/security/security_context.h"
 #include <grpc/support/alloc.h>
 #include <grpc/support/host_port.h>
 #include <grpc/support/log.h>
diff --git a/test/core/end2end/fixtures/chttp2_simple_ssl_fullstack.c b/test/core/end2end/fixtures/chttp2_simple_ssl_fullstack.c
index 16433f5..9c4086d 100644
--- a/test/core/end2end/fixtures/chttp2_simple_ssl_fullstack.c
+++ b/test/core/end2end/fixtures/chttp2_simple_ssl_fullstack.c
@@ -38,7 +38,6 @@
 
 #include "src/core/channel/channel_args.h"
 #include "src/core/security/credentials.h"
-#include "src/core/security/security_context.h"
 #include "src/core/support/env.h"
 #include "src/core/support/file.h"
 #include "src/core/support/string.h"
diff --git a/test/core/end2end/fixtures/chttp2_simple_ssl_with_oauth2_fullstack.c b/test/core/end2end/fixtures/chttp2_simple_ssl_with_oauth2_fullstack.c
index 99031df..e9e1c5f 100644
--- a/test/core/end2end/fixtures/chttp2_simple_ssl_with_oauth2_fullstack.c
+++ b/test/core/end2end/fixtures/chttp2_simple_ssl_with_oauth2_fullstack.c
@@ -39,7 +39,6 @@
 #include "src/core/channel/channel_args.h"
 #include "src/core/iomgr/iomgr.h"
 #include "src/core/security/credentials.h"
-#include "src/core/security/security_context.h"
 #include <grpc/support/alloc.h>
 #include <grpc/support/host_port.h>
 #include <grpc/support/log.h>
diff --git a/test/core/security/credentials_test.c b/test/core/security/credentials_test.c
index d1d1ec1..1b657e3 100644
--- a/test/core/security/credentials_test.c
+++ b/test/core/security/credentials_test.c
@@ -313,6 +313,19 @@
                                         composite_creds);
 }
 
+void test_ssl_fake_transport_security_composite_creds_failure(void) {
+  grpc_credentials *ssl_creds =
+      grpc_ssl_credentials_create(NULL, NULL);
+  grpc_credentials *fake_transport_security_creds =
+      grpc_fake_transport_security_credentials_create();
+
+  /* 2 connector credentials: should not work. */
+  GPR_ASSERT(grpc_composite_credentials_create(
+                 ssl_creds, fake_transport_security_creds) == NULL);
+  grpc_credentials_unref(ssl_creds);
+  grpc_credentials_unref(fake_transport_security_creds);
+}
+
 static void check_ssl_oauth2_iam_composite_metadata(
     void *user_data, grpc_mdelem **md_elems, size_t num_md,
     grpc_credentials_status status) {
diff --git a/vsprojects/vs2010/grpc.vcxproj b/vsprojects/vs2010/grpc.vcxproj
index d18c33b..ce973e8 100644
--- a/vsprojects/vs2010/grpc.vcxproj
+++ b/vsprojects/vs2010/grpc.vcxproj
@@ -86,7 +86,7 @@
   <ItemGroup>
     <ClInclude Include="..\..\src\core\httpcli\format_request.h" />
     <ClInclude Include="..\..\src\core\httpcli\httpcli.h" />
-    <ClInclude Include="..\..\src\core\httpcli\httpcli_security_context.h" />
+    <ClInclude Include="..\..\src\core\httpcli\httpcli_security_connector.h" />
     <ClInclude Include="..\..\src\core\httpcli\parser.h" />
     <ClInclude Include="..\..\src\core\security\auth.h" />
     <ClInclude Include="..\..\src\core\security\base64.h" />
@@ -94,7 +94,7 @@
     <ClInclude Include="..\..\src\core\security\json_token.h" />
     <ClInclude Include="..\..\src\core\security\secure_endpoint.h" />
     <ClInclude Include="..\..\src\core\security\secure_transport_setup.h" />
-    <ClInclude Include="..\..\src\core\security\security_context.h" />
+    <ClInclude Include="..\..\src\core\security\security_connector.h" />
     <ClInclude Include="..\..\src\core\tsi\fake_transport_security.h" />
     <ClInclude Include="..\..\src\core\tsi\ssl_transport_security.h" />
     <ClInclude Include="..\..\src\core\tsi\transport_security.h" />
@@ -194,7 +194,7 @@
     </ClCompile>
     <ClCompile Include="..\..\src\core\httpcli\httpcli.c">
     </ClCompile>
-    <ClCompile Include="..\..\src\core\httpcli\httpcli_security_context.c">
+    <ClCompile Include="..\..\src\core\httpcli\httpcli_security_connector.c">
     </ClCompile>
     <ClCompile Include="..\..\src\core\httpcli\parser.c">
     </ClCompile>
@@ -208,8 +208,6 @@
     </ClCompile>
     <ClCompile Include="..\..\src\core\security\credentials_win32.c">
     </ClCompile>
-    <ClCompile Include="..\..\src\core\security\factories.c">
-    </ClCompile>
     <ClCompile Include="..\..\src\core\security\google_default_credentials.c">
     </ClCompile>
     <ClCompile Include="..\..\src\core\security\json_token.c">
@@ -218,7 +216,7 @@
     </ClCompile>
     <ClCompile Include="..\..\src\core\security\secure_transport_setup.c">
     </ClCompile>
-    <ClCompile Include="..\..\src\core\security\security_context.c">
+    <ClCompile Include="..\..\src\core\security\security_connector.c">
     </ClCompile>
     <ClCompile Include="..\..\src\core\security\server_secure_chttp2.c">
     </ClCompile>
diff --git a/vsprojects/vs2010/grpc.vcxproj.filters b/vsprojects/vs2010/grpc.vcxproj.filters
index 7774a78..7619bc1 100644
--- a/vsprojects/vs2010/grpc.vcxproj.filters
+++ b/vsprojects/vs2010/grpc.vcxproj.filters
@@ -7,7 +7,7 @@
     <ClCompile Include="..\..\src\core\httpcli\httpcli.c">
       <Filter>src\core\httpcli</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\src\core\httpcli\httpcli_security_context.c">
+    <ClCompile Include="..\..\src\core\httpcli\httpcli_security_connector.c">
       <Filter>src\core\httpcli</Filter>
     </ClCompile>
     <ClCompile Include="..\..\src\core\httpcli\parser.c">
@@ -28,9 +28,6 @@
     <ClCompile Include="..\..\src\core\security\credentials_win32.c">
       <Filter>src\core\security</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\src\core\security\factories.c">
-      <Filter>src\core\security</Filter>
-    </ClCompile>
     <ClCompile Include="..\..\src\core\security\google_default_credentials.c">
       <Filter>src\core\security</Filter>
     </ClCompile>
@@ -43,7 +40,7 @@
     <ClCompile Include="..\..\src\core\security\secure_transport_setup.c">
       <Filter>src\core\security</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\src\core\security\security_context.c">
+    <ClCompile Include="..\..\src\core\security\security_connector.c">
       <Filter>src\core\security</Filter>
     </ClCompile>
     <ClCompile Include="..\..\src\core\security\server_secure_chttp2.c">
@@ -386,7 +383,7 @@
     <ClInclude Include="..\..\src\core\httpcli\httpcli.h">
       <Filter>src\core\httpcli</Filter>
     </ClInclude>
-    <ClInclude Include="..\..\src\core\httpcli\httpcli_security_context.h">
+    <ClInclude Include="..\..\src\core\httpcli\httpcli_security_connector.h">
       <Filter>src\core\httpcli</Filter>
     </ClInclude>
     <ClInclude Include="..\..\src\core\httpcli\parser.h">
@@ -410,7 +407,7 @@
     <ClInclude Include="..\..\src\core\security\secure_transport_setup.h">
       <Filter>src\core\security</Filter>
     </ClInclude>
-    <ClInclude Include="..\..\src\core\security\security_context.h">
+    <ClInclude Include="..\..\src\core\security\security_connector.h">
       <Filter>src\core\security</Filter>
     </ClInclude>
     <ClInclude Include="..\..\src\core\tsi\fake_transport_security.h">
diff --git a/vsprojects/vs2013/grpc.vcxproj b/vsprojects/vs2013/grpc.vcxproj
index 4c7f0fa..250d480 100644
--- a/vsprojects/vs2013/grpc.vcxproj
+++ b/vsprojects/vs2013/grpc.vcxproj
@@ -88,7 +88,7 @@
   <ItemGroup>
     <ClInclude Include="..\..\src\core\httpcli\format_request.h" />
     <ClInclude Include="..\..\src\core\httpcli\httpcli.h" />
-    <ClInclude Include="..\..\src\core\httpcli\httpcli_security_context.h" />
+    <ClInclude Include="..\..\src\core\httpcli\httpcli_security_connector.h" />
     <ClInclude Include="..\..\src\core\httpcli\parser.h" />
     <ClInclude Include="..\..\src\core\security\auth.h" />
     <ClInclude Include="..\..\src\core\security\base64.h" />
@@ -96,7 +96,7 @@
     <ClInclude Include="..\..\src\core\security\json_token.h" />
     <ClInclude Include="..\..\src\core\security\secure_endpoint.h" />
     <ClInclude Include="..\..\src\core\security\secure_transport_setup.h" />
-    <ClInclude Include="..\..\src\core\security\security_context.h" />
+    <ClInclude Include="..\..\src\core\security\security_connector.h" />
     <ClInclude Include="..\..\src\core\tsi\fake_transport_security.h" />
     <ClInclude Include="..\..\src\core\tsi\ssl_transport_security.h" />
     <ClInclude Include="..\..\src\core\tsi\transport_security.h" />
@@ -196,7 +196,7 @@
     </ClCompile>
     <ClCompile Include="..\..\src\core\httpcli\httpcli.c">
     </ClCompile>
-    <ClCompile Include="..\..\src\core\httpcli\httpcli_security_context.c">
+    <ClCompile Include="..\..\src\core\httpcli\httpcli_security_connector.c">
     </ClCompile>
     <ClCompile Include="..\..\src\core\httpcli\parser.c">
     </ClCompile>
@@ -210,8 +210,6 @@
     </ClCompile>
     <ClCompile Include="..\..\src\core\security\credentials_win32.c">
     </ClCompile>
-    <ClCompile Include="..\..\src\core\security\factories.c">
-    </ClCompile>
     <ClCompile Include="..\..\src\core\security\google_default_credentials.c">
     </ClCompile>
     <ClCompile Include="..\..\src\core\security\json_token.c">
@@ -220,7 +218,7 @@
     </ClCompile>
     <ClCompile Include="..\..\src\core\security\secure_transport_setup.c">
     </ClCompile>
-    <ClCompile Include="..\..\src\core\security\security_context.c">
+    <ClCompile Include="..\..\src\core\security\security_connector.c">
     </ClCompile>
     <ClCompile Include="..\..\src\core\security\server_secure_chttp2.c">
     </ClCompile>
diff --git a/vsprojects/vs2013/grpc.vcxproj.filters b/vsprojects/vs2013/grpc.vcxproj.filters
index 7774a78..7619bc1 100644
--- a/vsprojects/vs2013/grpc.vcxproj.filters
+++ b/vsprojects/vs2013/grpc.vcxproj.filters
@@ -7,7 +7,7 @@
     <ClCompile Include="..\..\src\core\httpcli\httpcli.c">
       <Filter>src\core\httpcli</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\src\core\httpcli\httpcli_security_context.c">
+    <ClCompile Include="..\..\src\core\httpcli\httpcli_security_connector.c">
       <Filter>src\core\httpcli</Filter>
     </ClCompile>
     <ClCompile Include="..\..\src\core\httpcli\parser.c">
@@ -28,9 +28,6 @@
     <ClCompile Include="..\..\src\core\security\credentials_win32.c">
       <Filter>src\core\security</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\src\core\security\factories.c">
-      <Filter>src\core\security</Filter>
-    </ClCompile>
     <ClCompile Include="..\..\src\core\security\google_default_credentials.c">
       <Filter>src\core\security</Filter>
     </ClCompile>
@@ -43,7 +40,7 @@
     <ClCompile Include="..\..\src\core\security\secure_transport_setup.c">
       <Filter>src\core\security</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\src\core\security\security_context.c">
+    <ClCompile Include="..\..\src\core\security\security_connector.c">
       <Filter>src\core\security</Filter>
     </ClCompile>
     <ClCompile Include="..\..\src\core\security\server_secure_chttp2.c">
@@ -386,7 +383,7 @@
     <ClInclude Include="..\..\src\core\httpcli\httpcli.h">
       <Filter>src\core\httpcli</Filter>
     </ClInclude>
-    <ClInclude Include="..\..\src\core\httpcli\httpcli_security_context.h">
+    <ClInclude Include="..\..\src\core\httpcli\httpcli_security_connector.h">
       <Filter>src\core\httpcli</Filter>
     </ClInclude>
     <ClInclude Include="..\..\src\core\httpcli\parser.h">
@@ -410,7 +407,7 @@
     <ClInclude Include="..\..\src\core\security\secure_transport_setup.h">
       <Filter>src\core\security</Filter>
     </ClInclude>
-    <ClInclude Include="..\..\src\core\security\security_context.h">
+    <ClInclude Include="..\..\src\core\security\security_connector.h">
       <Filter>src\core\security</Filter>
     </ClInclude>
     <ClInclude Include="..\..\src\core\tsi\fake_transport_security.h">