/* Destructor for channel data */
static void destroy_channel_elem(grpc_channel_element *elem) {
  size_t i;

  /* grab pointers to our data from the channel element */
  channel_data *channeld = elem->channel_data;

  for (i = 0; i < channeld->gettable_count; i++) {
    grpc_mdelem_unref(channeld->gettables[i].path);
    grpc_mdelem_unref(channeld->gettables[i].content_type);
    grpc_byte_buffer_destroy(channeld->gettables[i].content);
  }
  gpr_free(channeld->gettables);

  grpc_mdelem_unref(channeld->te_trailers);
  grpc_mdelem_unref(channeld->status_ok);
  grpc_mdelem_unref(channeld->status_not_found);
  grpc_mdelem_unref(channeld->method_post);
  grpc_mdelem_unref(channeld->http_scheme);
  grpc_mdelem_unref(channeld->https_scheme);
  grpc_mdelem_unref(channeld->grpc_scheme);
  grpc_mdelem_unref(channeld->content_type);
  grpc_mdstr_unref(channeld->path_key);
  grpc_mdstr_unref(channeld->authority_key);
  grpc_mdstr_unref(channeld->host_key);
}
Beispiel #2
0
static void iam_destroy(grpc_credentials *creds) {
  grpc_iam_credentials *c = (grpc_iam_credentials *)creds;
  grpc_mdelem_unref(c->token_md);
  grpc_mdelem_unref(c->authority_selector_md);
  grpc_mdctx_unref(c->md_ctx);
  gpr_free(c);
}
Beispiel #3
0
static void destroy_call(void *call, int ignored_success) {
  size_t i;
  grpc_call *c = call;
  grpc_call_stack_destroy(CALL_STACK_FROM_CALL(c));
  grpc_channel_internal_unref(c->channel);
  gpr_mu_destroy(&c->mu);
  for (i = 0; i < STATUS_SOURCE_COUNT; i++) {
    if (c->status[i].details) {
      grpc_mdstr_unref(c->status[i].details);
    }
  }
  for (i = 0; i < c->owned_metadata_count; i++) {
    grpc_mdelem_unref(c->owned_metadata[i]);
  }
  gpr_free(c->owned_metadata);
  for (i = 0; i < GPR_ARRAY_SIZE(c->buffered_metadata); i++) {
    gpr_free(c->buffered_metadata[i].metadata);
  }
  for (i = 0; i < c->send_initial_metadata_count; i++) {
    grpc_mdelem_unref(c->send_initial_metadata[i].md);
  }
  for (i = 0; i < GRPC_CONTEXT_COUNT; i++) {
    if (c->destroy_context[i]) {
      c->destroy_context[i](c->context[i]);
    }
  }
  grpc_sopb_destroy(&c->send_ops);
  grpc_sopb_destroy(&c->recv_ops);
  grpc_bbq_destroy(&c->incoming_queue);
  gpr_slice_buffer_destroy(&c->incoming_message);
  gpr_free(c);
}
Beispiel #4
0
static void chk_hdr(void *p, grpc_mdelem *el) {
  test_decode_random_header_state *st = p;
  GPR_ASSERT(0 == gpr_slice_str_cmp(el->key->slice, st->key));
  GPR_ASSERT(0 == gpr_slice_str_cmp(el->value->slice, st->value));
  st->got_hdr = 1;
  grpc_mdelem_unref(el);
}
Beispiel #5
0
static void oauth2_token_fetcher_get_request_metadata(
    grpc_credentials *creds, const char *service_url,
    grpc_credentials_metadata_cb cb, void *user_data) {
  grpc_oauth2_token_fetcher_credentials *c =
      (grpc_oauth2_token_fetcher_credentials *)creds;
  gpr_timespec refresh_threshold = {GRPC_SECURE_TOKEN_REFRESH_THRESHOLD_SECS,
                                    0};
  grpc_mdelem *cached_access_token_md = NULL;
  {
    gpr_mu_lock(&c->mu);
    if (c->access_token_md != NULL &&
        (gpr_time_cmp(gpr_time_sub(c->token_expiration, gpr_now()),
                      refresh_threshold) > 0)) {
      cached_access_token_md = grpc_mdelem_ref(c->access_token_md);
    }
    gpr_mu_unlock(&c->mu);
  }
  if (cached_access_token_md != NULL) {
    cb(user_data, &cached_access_token_md, 1, GRPC_CREDENTIALS_OK);
    grpc_mdelem_unref(cached_access_token_md);
  } else {
    c->fetch_func(
        grpc_credentials_metadata_request_create(creds, cb, user_data),
        on_oauth2_token_fetcher_http_response,
        gpr_time_add(gpr_now(), refresh_threshold));
  }
}
Beispiel #6
0
static grpc_chttp2_hptbl_find_result find_simple(grpc_chttp2_hptbl *tbl,
                                                 const char *key,
                                                 const char *value) {
  grpc_mdelem *md = grpc_mdelem_from_strings(tbl->mdctx, key, value);
  grpc_chttp2_hptbl_find_result r = grpc_chttp2_hptbl_find(tbl, md);
  grpc_mdelem_unref(md);
  return r;
}
Beispiel #7
0
void grpc_chttp2_incoming_metadata_buffer_destroy(
    grpc_chttp2_incoming_metadata_buffer *buffer) {
  size_t i;
  for (i = 0; i < buffer->count; i++) {
    grpc_mdelem_unref(buffer->elems[i].md);
  }
  gpr_free(buffer->elems);
}
Beispiel #8
0
static void fake_oauth2_destroy(grpc_credentials *creds) {
  grpc_fake_oauth2_credentials *c = (grpc_fake_oauth2_credentials *)creds;
  if (c->access_token_md != NULL) {
    grpc_mdelem_unref(c->access_token_md);
  }
  grpc_mdctx_unref(c->md_ctx);
  gpr_free(c);
}
Beispiel #9
0
static void destroy_channel(void *p, int ok) {
  grpc_channel *channel = p;
  grpc_channel_stack_destroy(CHANNEL_STACK_FROM_CHANNEL(channel));
  grpc_mdstr_unref(channel->grpc_status_string);
  grpc_mdstr_unref(channel->grpc_message_string);
  grpc_mdstr_unref(channel->path_string);
  grpc_mdstr_unref(channel->authority_string);
  while (channel->registered_calls) {
    registered_call *rc = channel->registered_calls;
    channel->registered_calls = rc->next;
    grpc_mdelem_unref(rc->path);
    grpc_mdelem_unref(rc->authority);
    gpr_free(rc);
  }
  grpc_mdctx_unref(channel->metadata_context);
  gpr_mu_destroy(&channel->registered_call_mu);
  gpr_free(channel);
}
Beispiel #10
0
static void call_op(grpc_call_element *elem, grpc_call_element *from_elemn,
                    grpc_call_op *op) {
  channel_data *chand = elem->channel_data;
  call_data *calld = elem->call_data;
  grpc_mdelem *md;
  GRPC_CALL_LOG_OP(GPR_INFO, elem, op);
  switch (op->type) {
    case GRPC_RECV_METADATA:
      md = op->data.metadata;
      if (md->key == chand->path_key) {
        calld->path = grpc_mdstr_ref(md->value);
        grpc_mdelem_unref(md);
      } else if (md->key == chand->authority_key) {
        calld->host = grpc_mdstr_ref(md->value);
        grpc_mdelem_unref(md);
      } else {
        grpc_call_recv_metadata(elem, md);
      }
      break;
    case GRPC_RECV_END_OF_INITIAL_METADATA:
      start_new_rpc(elem);
      grpc_call_initial_metadata_complete(elem);
      break;
    case GRPC_RECV_MESSAGE:
      grpc_call_recv_message(elem, op->data.message);
      op->done_cb(op->user_data, GRPC_OP_OK);
      break;
    case GRPC_RECV_HALF_CLOSE:
      read_closed(elem);
      break;
    case GRPC_RECV_FINISH:
      stream_closed(elem);
      break;
    case GRPC_RECV_DEADLINE:
      grpc_call_set_deadline(elem, op->data.deadline);
      ((call_data *)elem->call_data)->deadline = op->data.deadline;
      break;
    default:
      GPR_ASSERT(op->dir == GRPC_CALL_DOWN);
      grpc_call_next_op(elem, op);
      break;
  }
}
Beispiel #11
0
static void composite_md_context_destroy(
    grpc_composite_credentials_metadata_context *ctx) {
  size_t i;
  for (i = 0; i < ctx->num_md; i++) {
    grpc_mdelem_unref(ctx->md_elems[i]);
  }
  gpr_free(ctx->md_elems);
  if (ctx->service_url != NULL) gpr_free(ctx->service_url);
  gpr_free(ctx);
}
Beispiel #12
0
static void oauth2_token_fetcher_destroy(grpc_credentials *creds) {
  grpc_oauth2_token_fetcher_credentials *c =
      (grpc_oauth2_token_fetcher_credentials *)creds;
  if (c->access_token_md != NULL) {
    grpc_mdelem_unref(c->access_token_md);
  }
  gpr_mu_destroy(&c->mu);
  grpc_mdctx_unref(c->md_ctx);
  gpr_free(c);
}
Beispiel #13
0
static void onhdr(void *ud, grpc_mdelem *md) {
  const char *ekey, *evalue;
  test_checker *chk = ud;
  ekey = va_arg(chk->args, char *);
  GPR_ASSERT(ekey);
  evalue = va_arg(chk->args, char *);
  GPR_ASSERT(evalue);
  GPR_ASSERT(gpr_slice_str_cmp(md->key->slice, ekey) == 0);
  GPR_ASSERT(gpr_slice_str_cmp(md->value->slice, evalue) == 0);
  grpc_mdelem_unref(md);
}
Beispiel #14
0
static void jwt_reset_cache(grpc_jwt_credentials *c) {
  if (c->cached.jwt_md != NULL) {
    grpc_mdelem_unref(c->cached.jwt_md);
    c->cached.jwt_md = NULL;
  }
  if (c->cached.service_url != NULL) {
    gpr_free(c->cached.service_url);
    c->cached.service_url = NULL;
  }
  c->cached.jwt_expiration = gpr_inf_past;
}
Beispiel #15
0
void grpc_metadata_buffer_destroy(grpc_metadata_buffer *buffer,
                                  grpc_op_error error) {
  size_t i;
  qelem *qe;
  if (*buffer) {
    for (i = 0; i < (*buffer)->elems; i++) {
      qe = &ELEMS(*buffer)[i];
      grpc_mdelem_unref(qe->md);
      qe->cb(qe->user_data, error);
    }
    gpr_free(*buffer);
  }
}
Beispiel #16
0
/* 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_mdelem_unref(channeld->te_trailers);
  grpc_mdelem_unref(channeld->status_ok);
  grpc_mdelem_unref(channeld->status_not_found);
  grpc_mdelem_unref(channeld->method_post);
  grpc_mdelem_unref(channeld->http_scheme);
  grpc_mdelem_unref(channeld->https_scheme);
  grpc_mdelem_unref(channeld->grpc_scheme);
  grpc_mdelem_unref(channeld->content_type);
  grpc_mdstr_unref(channeld->path_key);
  grpc_mdstr_unref(channeld->authority_key);
  grpc_mdstr_unref(channeld->host_key);
}
Beispiel #17
0
static void destroy_channel(void *p, int ok) {
  grpc_channel *channel = p;
  size_t i;
  grpc_channel_stack_destroy(CHANNEL_STACK_FROM_CHANNEL(channel));
  for (i = 0; i < NUM_CACHED_STATUS_ELEMS; i++) {
    grpc_mdelem_unref(channel->grpc_status_elem[i]);
  }
  grpc_mdstr_unref(channel->grpc_status_string);
  grpc_mdstr_unref(channel->grpc_compression_level_string);
  grpc_mdstr_unref(channel->grpc_message_string);
  grpc_mdstr_unref(channel->path_string);
  grpc_mdstr_unref(channel->authority_string);
  while (channel->registered_calls) {
    registered_call *rc = channel->registered_calls;
    channel->registered_calls = rc->next;
    grpc_mdelem_unref(rc->path);
    grpc_mdelem_unref(rc->authority);
    gpr_free(rc);
  }
  grpc_mdctx_unref(channel->metadata_context);
  gpr_mu_destroy(&channel->registered_call_mu);
  gpr_free(channel);
}
Beispiel #18
0
static void jwt_get_request_metadata(grpc_credentials *creds,
                                     const char *service_url,
                                     grpc_credentials_metadata_cb cb,
                                     void *user_data) {
  grpc_jwt_credentials *c = (grpc_jwt_credentials *)creds;
  gpr_timespec refresh_threshold = {GRPC_SECURE_TOKEN_REFRESH_THRESHOLD_SECS,
                                    0};

  /* See if we can return a cached jwt. */
  grpc_mdelem *jwt_md = NULL;
  {
    gpr_mu_lock(&c->cache_mu);
    if (c->cached.service_url != NULL &&
        strcmp(c->cached.service_url, service_url) == 0 &&
        c->cached.jwt_md != NULL &&
        (gpr_time_cmp(gpr_time_sub(c->cached.jwt_expiration, gpr_now()),
                      refresh_threshold) > 0)) {
      jwt_md = grpc_mdelem_ref(c->cached.jwt_md);
    }
    gpr_mu_unlock(&c->cache_mu);
  }

  if (jwt_md == NULL) {
    char *jwt = NULL;
    /* Generate a new jwt. */
    gpr_mu_lock(&c->cache_mu);
    jwt_reset_cache(c);
    jwt = grpc_jwt_encode_and_sign(&c->key, service_url, c->jwt_lifetime, NULL);
    if (jwt != NULL) {
      char *md_value;
      gpr_asprintf(&md_value, "Bearer %s", jwt);
      gpr_free(jwt);
      c->cached.jwt_expiration = gpr_time_add(gpr_now(), c->jwt_lifetime);
      c->cached.service_url = gpr_strdup(service_url);
      c->cached.jwt_md = grpc_mdelem_from_strings(
          c->md_ctx, GRPC_AUTHORIZATION_METADATA_KEY, md_value);
      gpr_free(md_value);
      jwt_md = grpc_mdelem_ref(c->cached.jwt_md);
    }
    gpr_mu_unlock(&c->cache_mu);
  }

  if (jwt_md != NULL) {
    cb(user_data, &jwt_md, 1, GRPC_CREDENTIALS_OK);
    grpc_mdelem_unref(jwt_md);
  } else {
    cb(user_data, NULL, 0, GRPC_CREDENTIALS_ERROR);
  }
}
Beispiel #19
0
void grpc_call_recv_metadata(grpc_call_element *elem, grpc_mdelem *md) {
  grpc_call *call = CALL_FROM_TOP_ELEM(elem);
  grpc_mdstr *key = md->key;
  grpc_metadata_array *dest;
  grpc_metadata *mdusr;

  lock(call);
  if (key == grpc_channel_get_status_string(call->channel)) {
    set_status_code(call, STATUS_FROM_WIRE, decode_status(md));
    grpc_mdelem_unref(md);
  } else if (key == grpc_channel_get_message_string(call->channel)) {
    set_status_details(call, STATUS_FROM_WIRE, grpc_mdstr_ref(md->value));
    grpc_mdelem_unref(md);
  } else {
    dest = &call->buffered_metadata[call->read_state >=
                                    READ_STATE_GOT_INITIAL_METADATA];
    if (dest->count == dest->capacity) {
      dest->capacity = GPR_MAX(dest->capacity + 8, dest->capacity * 2);
      dest->metadata =
          gpr_realloc(dest->metadata, sizeof(grpc_metadata) * dest->capacity);
    }
    mdusr = &dest->metadata[dest->count++];
    mdusr->key = grpc_mdstr_as_c_string(md->key);
    mdusr->value = grpc_mdstr_as_c_string(md->value);
    mdusr->value_length = GPR_SLICE_LENGTH(md->value->slice);
    if (call->owned_metadata_count == call->owned_metadata_capacity) {
      call->owned_metadata_capacity = GPR_MAX(
          call->owned_metadata_capacity + 8, call->owned_metadata_capacity * 2);
      call->owned_metadata =
          gpr_realloc(call->owned_metadata,
                      sizeof(grpc_mdelem *) * call->owned_metadata_capacity);
    }
    call->owned_metadata[call->owned_metadata_count++] = md;
  }
  unlock(call);
}
Beispiel #20
0
/* Destructor for channel_data */
static void destroy_channel_elem(grpc_channel_element *elem) {
  channel_data *chand = elem->channel_data;

  grpc_transport_setup_cancel(chand->transport_setup);

  if (chand->active_child) {
    grpc_child_channel_destroy(chand->active_child, 1);
    chand->active_child = NULL;
  }

  grpc_channel_args_destroy(chand->args);
  grpc_mdelem_unref(chand->cancel_status);

  gpr_mu_destroy(&chand->mu);
  GPR_ASSERT(chand->waiting_child_count == 0);
  gpr_free(chand->waiting_children);
}
Beispiel #21
0
static void call_op(grpc_call_element *elem, grpc_call_element *from_elem,
                    grpc_call_op *op) {
  channel_data *channeld = elem->channel_data;
  GRPC_CALL_LOG_OP(GPR_INFO, elem, op);

  switch (op->type) {
    case GRPC_SEND_START:
      grpc_call_recv_metadata(elem, grpc_mdelem_ref(channeld->status));
      grpc_call_recv_metadata(elem, grpc_mdelem_ref(channeld->message));
      grpc_call_stream_closed(elem);
      break;
    case GRPC_SEND_METADATA:
      grpc_mdelem_unref(op->data.metadata);
      break;
    default:
      break;
  }

  op->done_cb(op->user_data, GRPC_OP_ERROR);
}
Beispiel #22
0
void grpc_stream_ops_unref_owned_objects(grpc_stream_op *ops, size_t nops) {
  size_t i;
  for (i = 0; i < nops; i++) {
    switch (ops[i].type) {
      case GRPC_OP_SLICE:
        gpr_slice_unref(ops[i].data.slice);
        break;
      case GRPC_OP_METADATA:
        grpc_mdelem_unref(ops[i].data.metadata);
        break;
      case GRPC_OP_FLOW_CTL_CB:
        ops[i].data.flow_ctl_cb.cb(ops[i].data.flow_ctl_cb.arg, GRPC_OP_ERROR);
        break;
      case GRPC_NO_OP:
      case GRPC_OP_DEADLINE:
      case GRPC_OP_METADATA_BOUNDARY:
      case GRPC_OP_BEGIN_MESSAGE:
        break;
    }
  }
}
Beispiel #23
0
static void destroy_call(void *call, int ignored_success) {
  size_t i;
  grpc_call *c = call;
  grpc_call_stack_destroy(CALL_STACK_FROM_CALL(c));
  grpc_channel_internal_unref(c->channel);
  gpr_mu_destroy(&c->mu);
  for (i = 0; i < STATUS_SOURCE_COUNT; i++) {
    if (c->status[i].details) {
      grpc_mdstr_unref(c->status[i].details);
    }
  }
  for (i = 0; i < c->owned_metadata_count; i++) {
    grpc_mdelem_unref(c->owned_metadata[i]);
  }
  gpr_free(c->owned_metadata);
  for (i = 0; i < GPR_ARRAY_SIZE(c->buffered_metadata); i++) {
    gpr_free(c->buffered_metadata[i].metadata);
  }
  if (c->legacy_state) {
    destroy_legacy_state(c->legacy_state);
  }
  grpc_bbq_destroy(&c->incoming_queue);
  gpr_free(c);
}
Beispiel #24
0
grpc_credentials_status
grpc_oauth2_token_fetcher_credentials_parse_server_response(
    const grpc_httpcli_response *response, grpc_mdctx *ctx,
    grpc_mdelem **token_elem, gpr_timespec *token_lifetime) {
  char *null_terminated_body = NULL;
  char *new_access_token = NULL;
  grpc_credentials_status status = GRPC_CREDENTIALS_OK;
  grpc_json *json = NULL;

  if (response == NULL) {
    gpr_log(GPR_ERROR, "Received NULL response.");
    status = GRPC_CREDENTIALS_ERROR;
    goto end;
  }

  if (response->body_length > 0) {
    null_terminated_body = gpr_malloc(response->body_length + 1);
    null_terminated_body[response->body_length] = '\0';
    memcpy(null_terminated_body, response->body, response->body_length);
  }

  if (response->status != 200) {
    gpr_log(GPR_ERROR, "Call to http server ended with error %d [%s].",
            response->status,
            null_terminated_body != NULL ? null_terminated_body : "");
    status = GRPC_CREDENTIALS_ERROR;
    goto end;
  } else {
    grpc_json *access_token = NULL;
    grpc_json *token_type = NULL;
    grpc_json *expires_in = NULL;
    grpc_json *ptr;
    json = grpc_json_parse_string(null_terminated_body);
    if (json == NULL) {
      gpr_log(GPR_ERROR, "Could not parse JSON from %s", null_terminated_body);
      status = GRPC_CREDENTIALS_ERROR;
      goto end;
    }
    if (json->type != GRPC_JSON_OBJECT) {
      gpr_log(GPR_ERROR, "Response should be a JSON object");
      status = GRPC_CREDENTIALS_ERROR;
      goto end;
    }
    for (ptr = json->child; ptr; ptr = ptr->next) {
      if (strcmp(ptr->key, "access_token") == 0) {
        access_token = ptr;
      } else if (strcmp(ptr->key, "token_type") == 0) {
        token_type = ptr;
      } else if (strcmp(ptr->key, "expires_in") == 0) {
        expires_in = ptr;
      }
    }
    if (access_token == NULL || access_token->type != GRPC_JSON_STRING) {
      gpr_log(GPR_ERROR, "Missing or invalid access_token in JSON.");
      status = GRPC_CREDENTIALS_ERROR;
      goto end;
    }
    if (token_type == NULL || token_type->type != GRPC_JSON_STRING) {
      gpr_log(GPR_ERROR, "Missing or invalid token_type in JSON.");
      status = GRPC_CREDENTIALS_ERROR;
      goto end;
    }
    if (expires_in == NULL || expires_in->type != GRPC_JSON_NUMBER) {
      gpr_log(GPR_ERROR, "Missing or invalid expires_in in JSON.");
      status = GRPC_CREDENTIALS_ERROR;
      goto end;
    }
    gpr_asprintf(&new_access_token, "%s %s", token_type->value,
                 access_token->value);
    token_lifetime->tv_sec = strtol(expires_in->value, NULL, 10);
    token_lifetime->tv_nsec = 0;
    if (*token_elem != NULL) grpc_mdelem_unref(*token_elem);
    *token_elem = grpc_mdelem_from_strings(ctx, GRPC_AUTHORIZATION_METADATA_KEY,
                                           new_access_token);
    status = GRPC_CREDENTIALS_OK;
  }

end:
  if (status != GRPC_CREDENTIALS_OK && (*token_elem != NULL)) {
    grpc_mdelem_unref(*token_elem);
    *token_elem = NULL;
  }
  if (null_terminated_body != NULL) gpr_free(null_terminated_body);
  if (new_access_token != NULL) gpr_free(new_access_token);
  if (json != NULL) grpc_json_destroy(json);
  return status;
}
Beispiel #25
0
static void destroy_channel_elem(grpc_channel_element *elem) {
  channel_data *channeld = elem->channel_data;

  grpc_mdelem_unref(channeld->message);
  grpc_mdelem_unref(channeld->status);
}
Beispiel #26
0
static grpc_mdelem *server_filter(void *user_data, grpc_mdelem *md) {
  grpc_call_element *elem = user_data;
  channel_data *channeld = elem->channel_data;
  call_data *calld = elem->call_data;

  /* Check if it is one of the headers we care about. */
  if (md == channeld->te_trailers || md == channeld->method_post ||
      md == channeld->http_scheme || md == channeld->https_scheme ||
      md == channeld->grpc_scheme || md == channeld->content_type) {
    /* swallow it */
    if (md == channeld->method_post) {
      calld->seen_post = 1;
    } else if (md->key == channeld->http_scheme->key) {
      calld->seen_scheme = 1;
    } else if (md == channeld->te_trailers) {
      calld->seen_te_trailers = 1;
    }
    /* TODO(klempner): Track that we've seen all the headers we should
       require */
    return NULL;
  } else if (md->key == channeld->content_type->key) {
    if (strncmp(grpc_mdstr_as_c_string(md->value), "application/grpc+", 17) ==
        0) {
      /* Although the C implementation doesn't (currently) generate them,
         any custom +-suffix is explicitly valid. */
      /* TODO(klempner): We should consider preallocating common values such
         as +proto or +json, or at least stashing them if we see them. */
      /* TODO(klempner): Should we be surfacing this to application code? */
    } else {
      /* TODO(klempner): We're currently allowing this, but we shouldn't
         see it without a proxy so log for now. */
      gpr_log(GPR_INFO, "Unexpected content-type %s",
              channeld->content_type->key);
    }
    return NULL;
  } else if (md->key == channeld->te_trailers->key ||
             md->key == channeld->method_post->key ||
             md->key == channeld->http_scheme->key ||
             md->key == channeld->content_type->key) {
    gpr_log(GPR_ERROR, "Invalid %s: header: '%s'",
            grpc_mdstr_as_c_string(md->key), grpc_mdstr_as_c_string(md->value));
    /* swallow it and error everything out. */
    /* TODO(klempner): We ought to generate more descriptive error messages
       on the wire here. */
    grpc_call_element_send_cancel(elem);
    return NULL;
  } else if (md->key == channeld->path_key) {
    if (calld->seen_path) {
      gpr_log(GPR_ERROR, "Received :path twice");
      return NULL;
    }
    calld->seen_path = 1;
    return md;
  } else if (md->key == channeld->host_key) {
    /* translate host to :authority since :authority may be
       omitted */
    grpc_mdelem *authority = grpc_mdelem_from_metadata_strings(
        channeld->mdctx, grpc_mdstr_ref(channeld->authority_key),
        grpc_mdstr_ref(md->value));
    grpc_mdelem_unref(md);
    return authority;
  } else {
    return md;
  }
}