Remove metadata context from the channel stack
diff --git a/src/core/channel/http_client_filter.c b/src/core/channel/http_client_filter.c
index 3a0f68f..ec77916 100644
--- a/src/core/channel/http_client_filter.c
+++ b/src/core/channel/http_client_filter.c
@@ -37,6 +37,7 @@
 #include <grpc/support/string_util.h>
 #include "src/core/support/string.h"
 #include "src/core/profiling/timers.h"
+#include "src/core/transport/static_metadata.h"
 
 typedef struct call_data {
   grpc_linked_mdelem method;
@@ -54,17 +55,11 @@
       up-call on transport_op, and remember to call our on_done_recv member
       after handling it. */
   grpc_closure hc_on_recv;
+
+  grpc_mdctx *mdctx;
 } call_data;
 
-typedef struct channel_data {
-  grpc_mdelem *te_trailers;
-  grpc_mdelem *method;
-  grpc_mdelem *scheme;
-  grpc_mdelem *content_type;
-  grpc_mdelem *status;
-  /** complete user agent mdelem */
-  grpc_mdelem *user_agent;
-} channel_data;
+typedef struct channel_data { grpc_mdelem *static_scheme; } channel_data;
 
 typedef struct {
   grpc_call_element *elem;
@@ -73,14 +68,12 @@
 
 static grpc_mdelem *client_recv_filter(void *user_data, grpc_mdelem *md) {
   client_recv_filter_args *a = user_data;
-  grpc_call_element *elem = a->elem;
-  channel_data *channeld = elem->channel_data;
-  if (md == channeld->status) {
+  if (md == GRPC_MDELEM_STATUS_200) {
     return NULL;
-  } else if (md->key == channeld->status->key) {
-    grpc_call_element_send_cancel(a->exec_ctx, elem);
+  } else if (md->key == GRPC_MDSTR_STATUS) {
+    grpc_call_element_send_cancel(a->exec_ctx, a->elem);
     return NULL;
-  } else if (md->key == channeld->content_type->key) {
+  } else if (md->key == GRPC_MDSTR_CONTENT_TYPE) {
     return NULL;
   }
   return md;
@@ -98,14 +91,12 @@
 }
 
 static grpc_mdelem *client_strip_filter(void *user_data, grpc_mdelem *md) {
-  grpc_call_element *elem = user_data;
-  channel_data *channeld = elem->channel_data;
   /* eat the things we'd like to set ourselves */
-  if (md->key == channeld->method->key) return NULL;
-  if (md->key == channeld->scheme->key) return NULL;
-  if (md->key == channeld->te_trailers->key) return NULL;
-  if (md->key == channeld->content_type->key) return NULL;
-  if (md->key == channeld->user_agent->key) return NULL;
+  if (md->key == GRPC_MDSTR_METHOD) return NULL;
+  if (md->key == GRPC_MDSTR_SCHEME) return NULL;
+  if (md->key == GRPC_MDSTR_TE) return NULL;
+  if (md->key == GRPC_MDSTR_CONTENT_TYPE) return NULL;
+  if (md->key == GRPC_MDSTR_USER_AGENT) return NULL;
   return md;
 }
 
@@ -120,16 +111,18 @@
     /* Send : prefixed headers, which have to be before any application
        layer headers. */
     grpc_metadata_batch_add_head(op->send_initial_metadata, &calld->method,
-                                 GRPC_MDELEM_REF(channeld->method));
+                                 GRPC_MDELEM_METHOD_POST);
     grpc_metadata_batch_add_head(op->send_initial_metadata, &calld->scheme,
-                                 GRPC_MDELEM_REF(channeld->scheme));
+                                 channeld->static_scheme);
     grpc_metadata_batch_add_tail(op->send_initial_metadata, &calld->te_trailers,
-                                 GRPC_MDELEM_REF(channeld->te_trailers));
-    grpc_metadata_batch_add_tail(op->send_initial_metadata,
-                                 &calld->content_type,
-                                 GRPC_MDELEM_REF(channeld->content_type));
-    grpc_metadata_batch_add_tail(op->send_initial_metadata, &calld->user_agent,
-                                 GRPC_MDELEM_REF(channeld->user_agent));
+                                 GRPC_MDELEM_TE_TRAILERS);
+    grpc_metadata_batch_add_tail(
+        op->send_initial_metadata, &calld->content_type,
+        GRPC_MDELEM_CONTENT_TYPE_APPLICATION_SLASH_GRPC);
+    grpc_metadata_batch_add_tail(
+        op->send_initial_metadata, &calld->user_agent,
+        GRPC_MDELEM_REF(grpc_mdelem_from_cache(calld->mdctx,
+                                               GRPC_MDELEM_CACHED_USER_AGENT)));
   }
 
   if (op->recv_initial_metadata != NULL) {
@@ -155,6 +148,7 @@
                            grpc_call_element_args *args) {
   call_data *calld = elem->call_data;
   calld->on_done_recv = NULL;
+  calld->mdctx = args->metadata_context;
   grpc_closure_init(&calld->hc_on_recv, hc_on_recv, elem);
 }
 
@@ -162,109 +156,39 @@
 static void destroy_call_elem(grpc_exec_ctx *exec_ctx,
                               grpc_call_element *elem) {}
 
-static const char *scheme_from_args(const grpc_channel_args *args) {
+static grpc_mdelem *scheme_from_args(const grpc_channel_args *args) {
   unsigned i;
+  size_t j;
+  grpc_mdelem *valid_schemes[] = {GRPC_MDELEM_SCHEME_HTTP,
+                                  GRPC_MDELEM_SCHEME_HTTPS};
   if (args != NULL) {
     for (i = 0; i < args->num_args; ++i) {
       if (args->args[i].type == GRPC_ARG_STRING &&
           strcmp(args->args[i].key, GRPC_ARG_HTTP2_SCHEME) == 0) {
-        return args->args[i].value.string;
+        for (j = 0; j < GPR_ARRAY_SIZE(valid_schemes); j++) {
+          if (0 == strcmp(grpc_mdstr_as_c_string(valid_schemes[j]->value),
+                          args->args[i].value.string)) {
+            return valid_schemes[j];
+          }
+        }
       }
     }
   }
-  return "http";
-}
-
-static grpc_mdstr *user_agent_from_args(grpc_mdctx *mdctx,
-                                        const grpc_channel_args *args) {
-  gpr_strvec v;
-  size_t i;
-  int is_first = 1;
-  char *tmp;
-  grpc_mdstr *result;
-
-  gpr_strvec_init(&v);
-
-  for (i = 0; args && i < args->num_args; i++) {
-    if (0 == strcmp(args->args[i].key, GRPC_ARG_PRIMARY_USER_AGENT_STRING)) {
-      if (args->args[i].type != GRPC_ARG_STRING) {
-        gpr_log(GPR_ERROR, "Channel argument '%s' should be a string",
-                GRPC_ARG_PRIMARY_USER_AGENT_STRING);
-      } else {
-        if (!is_first) gpr_strvec_add(&v, gpr_strdup(" "));
-        is_first = 0;
-        gpr_strvec_add(&v, gpr_strdup(args->args[i].value.string));
-      }
-    }
-  }
-
-  gpr_asprintf(&tmp, "%sgrpc-c/%s (%s)", is_first ? "" : " ",
-               grpc_version_string(), GPR_PLATFORM_STRING);
-  is_first = 0;
-  gpr_strvec_add(&v, tmp);
-
-  for (i = 0; args && i < args->num_args; i++) {
-    if (0 == strcmp(args->args[i].key, GRPC_ARG_SECONDARY_USER_AGENT_STRING)) {
-      if (args->args[i].type != GRPC_ARG_STRING) {
-        gpr_log(GPR_ERROR, "Channel argument '%s' should be a string",
-                GRPC_ARG_SECONDARY_USER_AGENT_STRING);
-      } else {
-        if (!is_first) gpr_strvec_add(&v, gpr_strdup(" "));
-        is_first = 0;
-        gpr_strvec_add(&v, gpr_strdup(args->args[i].value.string));
-      }
-    }
-  }
-
-  tmp = gpr_strvec_flatten(&v, NULL);
-  gpr_strvec_destroy(&v);
-  result = grpc_mdstr_from_string(mdctx, tmp);
-  gpr_free(tmp);
-
-  return result;
+  return GRPC_MDELEM_SCHEME_HTTP;
 }
 
 /* Constructor for channel_data */
 static void init_channel_elem(grpc_exec_ctx *exec_ctx,
                               grpc_channel_element *elem,
                               grpc_channel_element_args *args) {
-  /* grab pointers to our data from the channel element */
-  channel_data *channeld = elem->channel_data;
-
-  /* The first and the last filters tend to be implemented differently to
-     handle the case that there's no 'next' filter to call on the up or down
-     path */
+  channel_data *chand = elem->channel_data;
   GPR_ASSERT(!args->is_last);
-
-  /* initialize members */
-  channeld->te_trailers =
-      grpc_mdelem_from_strings(args->metadata_context, "te", "trailers");
-  channeld->method =
-      grpc_mdelem_from_strings(args->metadata_context, ":method", "POST");
-  channeld->scheme = grpc_mdelem_from_strings(
-      args->metadata_context, ":scheme", scheme_from_args(args->channel_args));
-  channeld->content_type = grpc_mdelem_from_strings(
-      args->metadata_context, "content-type", "application/grpc");
-  channeld->status =
-      grpc_mdelem_from_strings(args->metadata_context, ":status", "200");
-  channeld->user_agent = grpc_mdelem_from_metadata_strings(
-      args->metadata_context,
-      grpc_mdstr_from_string(args->metadata_context, "user-agent"),
-      user_agent_from_args(args->metadata_context, args->channel_args));
+  chand->static_scheme = scheme_from_args(args->channel_args);
 }
 
 /* Destructor for channel data */
 static void destroy_channel_elem(grpc_exec_ctx *exec_ctx,
                                  grpc_channel_element *elem) {
-  /* grab pointers to our data from the channel element */
-  channel_data *channeld = elem->channel_data;
-
-  GRPC_MDELEM_UNREF(channeld->te_trailers);
-  GRPC_MDELEM_UNREF(channeld->method);
-  GRPC_MDELEM_UNREF(channeld->scheme);
-  GRPC_MDELEM_UNREF(channeld->content_type);
-  GRPC_MDELEM_UNREF(channeld->status);
-  GRPC_MDELEM_UNREF(channeld->user_agent);
 }
 
 const grpc_channel_filter grpc_http_client_filter = {