Beispiel #1
0
static void on_initial_header(grpc_exec_ctx *exec_ctx, void *tp,
                              grpc_mdelem *md) {
  grpc_chttp2_transport *t = tp;
  grpc_chttp2_stream *s = t->incoming_stream;

  GPR_TIMER_BEGIN("on_initial_header", 0);

  GPR_ASSERT(s != NULL);

  GRPC_CHTTP2_IF_TRACING(gpr_log(
      GPR_INFO, "HTTP:%d:HDR:%s: %s: %s", s->id, t->is_client ? "CLI" : "SVR",
      grpc_mdstr_as_c_string(md->key), grpc_mdstr_as_c_string(md->value)));

  if (md->key == GRPC_MDSTR_GRPC_STATUS && md != GRPC_MDELEM_GRPC_STATUS_0) {
    /* TODO(ctiller): check for a status like " 0" */
    s->seen_error = true;
  }

  if (md->key == GRPC_MDSTR_GRPC_TIMEOUT) {
    gpr_timespec *cached_timeout = grpc_mdelem_get_user_data(md, free_timeout);
    if (!cached_timeout) {
      /* not already parsed: parse it now, and store the result away */
      cached_timeout = gpr_malloc(sizeof(gpr_timespec));
      if (!grpc_http2_decode_timeout(grpc_mdstr_as_c_string(md->value),
                                     cached_timeout)) {
        gpr_log(GPR_ERROR, "Ignoring bad timeout value '%s'",
                grpc_mdstr_as_c_string(md->value));
        *cached_timeout = gpr_inf_future(GPR_TIMESPAN);
      }
      grpc_mdelem_set_user_data(md, free_timeout, cached_timeout);
    }
    grpc_chttp2_incoming_metadata_buffer_set_deadline(
        &s->metadata_buffer[0],
        gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC), *cached_timeout));
    GRPC_MDELEM_UNREF(md);
  } else {
    const size_t new_size = s->metadata_buffer[0].size + GRPC_MDELEM_LENGTH(md);
    const size_t metadata_size_limit =
        t->settings[GRPC_ACKED_SETTINGS]
                   [GRPC_CHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE];
    if (new_size > metadata_size_limit) {
      gpr_log(GPR_DEBUG,
              "received initial metadata size exceeds limit (%" PRIuPTR
              " vs. %" PRIuPTR ")",
              new_size, metadata_size_limit);
      grpc_chttp2_cancel_stream(
          exec_ctx, t, s,
          grpc_error_set_int(
              GRPC_ERROR_CREATE("received initial metadata size exceeds limit"),
              GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_RESOURCE_EXHAUSTED));
      grpc_chttp2_parsing_become_skip_parser(exec_ctx, t);
      s->seen_error = true;
      GRPC_MDELEM_UNREF(md);
    } else {
      grpc_chttp2_incoming_metadata_buffer_add(&s->metadata_buffer[0], md);
    }
  }

  GPR_TIMER_END("on_initial_header", 0);
}
void build_auth_metadata_context(grpc_security_connector *sc,
                                 grpc_auth_context *auth_context,
                                 call_data *calld) {
  char *service = gpr_strdup(grpc_mdstr_as_c_string(calld->method));
  char *last_slash = strrchr(service, '/');
  char *method_name = NULL;
  char *service_url = NULL;
  reset_auth_metadata_context(&calld->auth_md_context);
  if (last_slash == NULL) {
    gpr_log(GPR_ERROR, "No '/' found in fully qualified method name");
    service[0] = '\0';
  } else if (last_slash == service) {
    /* No service part in fully qualified method name: will just be "/". */
    service[1] = '\0';
  } else {
    *last_slash = '\0';
    method_name = gpr_strdup(last_slash + 1);
  }
  if (method_name == NULL) method_name = gpr_strdup("");
  gpr_asprintf(&service_url, "%s://%s%s",
               sc->url_scheme == NULL ? "" : sc->url_scheme,
               grpc_mdstr_as_c_string(calld->host), service);
  calld->auth_md_context.service_url = service_url;
  calld->auth_md_context.method_name = method_name;
  calld->auth_md_context.channel_auth_context =
      GRPC_AUTH_CONTEXT_REF(auth_context, "grpc_auth_metadata_context");
  gpr_free(service);
}
Beispiel #3
0
static void on_trailing_header(void *tp, grpc_mdelem *md) {
  grpc_chttp2_transport_parsing *transport_parsing = tp;
  grpc_chttp2_stream_parsing *stream_parsing =
      transport_parsing->incoming_stream;

  GPR_TIMER_BEGIN("on_trailing_header", 0);

  GPR_ASSERT(stream_parsing);

  GRPC_CHTTP2_IF_TRACING(gpr_log(
      GPR_INFO, "HTTP:%d:TRL:%s: %s: %s", stream_parsing->id,
      transport_parsing->is_client ? "CLI" : "SVR",
      grpc_mdstr_as_c_string(md->key), grpc_mdstr_as_c_string(md->value)));

  if (md->key == GRPC_MDSTR_GRPC_STATUS && md != GRPC_MDELEM_GRPC_STATUS_0) {
    /* TODO(ctiller): check for a status like " 0" */
    stream_parsing->seen_error = 1;
  }

  grpc_chttp2_incoming_metadata_buffer_add(&stream_parsing->metadata_buffer[1],
                                           md);

  grpc_chttp2_list_add_parsing_seen_stream(transport_parsing, stream_parsing);

  GPR_TIMER_END("on_trailing_header", 0);
}
static grpc_mdelem *client_recv_filter(void *user_data, grpc_mdelem *md) {
  client_recv_filter_args *a = user_data;
  if (md == GRPC_MDELEM_STATUS_200) {
    return NULL;
  } else if (md->key == GRPC_MDSTR_STATUS) {
    char *message_string;
    gpr_asprintf(&message_string, "Received http2 header with status: %s",
                 grpc_mdstr_as_c_string(md->value));
    gpr_slice message = gpr_slice_from_copied_string(message_string);
    gpr_free(message_string);
    grpc_call_element_send_cancel_with_message(a->exec_ctx, a->elem,
                                               GRPC_STATUS_CANCELLED, &message);
    return NULL;
  } else if (md == GRPC_MDELEM_CONTENT_TYPE_APPLICATION_SLASH_GRPC) {
    return NULL;
  } else if (md->key == GRPC_MDSTR_CONTENT_TYPE) {
    const char *value_str = grpc_mdstr_as_c_string(md->value);
    if (strncmp(value_str, EXPECTED_CONTENT_TYPE,
                EXPECTED_CONTENT_TYPE_LENGTH) == 0 &&
        (value_str[EXPECTED_CONTENT_TYPE_LENGTH] == '+' ||
         value_str[EXPECTED_CONTENT_TYPE_LENGTH] == ';')) {
      /* 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'", value_str);
    }
    return NULL;
  }
  return md;
}
Beispiel #5
0
grpc_metadata *grpc_metadata_buffer_extract_elements(
    grpc_metadata_buffer *buffer) {
  grpc_metadata_buffer_impl *impl;
  elems_hdr *hdr;
  qelem *src;
  grpc_metadata *out;
  size_t i;

  impl = *buffer;

  if (!impl) {
    return NULL;
  }

  hdr = gpr_malloc(sizeof(elems_hdr) + impl->elems * sizeof(grpc_metadata));
  src = ELEMS(impl);
  out = (grpc_metadata *)(hdr + 1);

  hdr->impl = impl;
  for (i = 0; i < impl->elems; i++) {
    out[i].key = (char *)grpc_mdstr_as_c_string(src[i].md->key);
    out[i].value = (char *)grpc_mdstr_as_c_string(src[i].md->value);
    out[i].value_length = GPR_SLICE_LENGTH(src[i].md->value->slice);
  }

  /* clear out buffer (it's not possible to extract elements twice */
  *buffer = NULL;

  return out;
}
Beispiel #6
0
static void recv_metadata(grpc_call *call, grpc_metadata_batch *md) {
  grpc_linked_mdelem *l;
  grpc_metadata_array *dest;
  grpc_metadata *mdusr;
  int is_trailing;
  grpc_mdctx *mdctx = call->metadata_context;

  is_trailing = call->read_state >= READ_STATE_GOT_INITIAL_METADATA;
  for (l = md->list.head; l != NULL; l = l->next) {
    grpc_mdelem *md = l->md;
    grpc_mdstr *key = md->key;
    if (key == grpc_channel_get_status_string(call->channel)) {
      set_status_code(call, STATUS_FROM_WIRE, decode_status(md));
    } else if (key == grpc_channel_get_message_string(call->channel)) {
      set_status_details(call, STATUS_FROM_WIRE, grpc_mdstr_ref(md->value));
    } else {
      dest = &call->buffered_metadata[is_trailing];
      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;
      l->md = 0;
    }
  }
  if (gpr_time_cmp(md->deadline, gpr_inf_future) != 0) {
    set_deadline_alarm(call, md->deadline);
  }
  if (!is_trailing) {
    call->read_state = READ_STATE_GOT_INITIAL_METADATA;
  }

  grpc_mdctx_lock(mdctx);
  for (l = md->list.head; l; l = l->next) {
    if (l->md) grpc_mdctx_locked_mdelem_unref(mdctx, l->md);
  }
  for (l = md->garbage.head; l; l = l->next) {
    grpc_mdctx_locked_mdelem_unref(mdctx, l->md);
  }
  grpc_mdctx_unlock(mdctx);
}
Beispiel #7
0
static grpc_mdelem *recv_md_filter(void *user_data, grpc_mdelem *md) {
  recv_md_filter_args *a = user_data;
  grpc_call_element *elem = a->elem;
  call_data *calld = elem->call_data;

  if (md->key == GRPC_MDSTR_PATH) {
    calld->service_method = grpc_mdstr_as_c_string(md->value);
  } else if (md->key == GRPC_MDSTR_LB_TOKEN) {
    calld->initial_md_string = gpr_strdup(grpc_mdstr_as_c_string(md->value));
    return NULL;
  }

  return md;
}
Beispiel #8
0
/** For each \a md element from the incoming metadata, filter out the entry for
 * "grpc-encoding", using its value to populate the call data's
 * compression_algorithm field. */
static grpc_mdelem *compression_md_filter(void *user_data, grpc_mdelem *md) {
    grpc_call_element *elem = user_data;
    call_data *calld = elem->call_data;
    channel_data *channeld = elem->channel_data;

    if (md->key == GRPC_MDSTR_GRPC_INTERNAL_ENCODING_REQUEST) {
        const char *md_c_str = grpc_mdstr_as_c_string(md->value);
        if (!grpc_compression_algorithm_parse(md_c_str, strlen(md_c_str),
                                              &calld->compression_algorithm)) {
            gpr_log(GPR_ERROR,
                    "Invalid compression algorithm: '%s' (unknown). Ignoring.",
                    md_c_str);
            calld->compression_algorithm = GRPC_COMPRESS_NONE;
        }
        if (grpc_compression_options_is_algorithm_enabled(
                    &channeld->compression_options, calld->compression_algorithm) ==
                0) {
            gpr_log(GPR_ERROR,
                    "Invalid compression algorithm: '%s' (previously disabled). "
                    "Ignoring.",
                    md_c_str);
            calld->compression_algorithm = GRPC_COMPRESS_NONE;
        }
        calld->has_compression_algorithm = 1;
        return NULL;
    }

    return md;
}
static void on_trailing_header(void *tp, grpc_mdelem *md) {
  grpc_chttp2_transport_parsing *transport_parsing = tp;
  grpc_chttp2_stream_parsing *stream_parsing =
      transport_parsing->incoming_stream;

  GPR_TIMER_BEGIN("on_trailing_header", 0);

  GPR_ASSERT(stream_parsing);

  GRPC_CHTTP2_IF_TRACING(gpr_log(
      GPR_INFO, "HTTP:%d:TRL:%s: %s: %s", stream_parsing->id,
      transport_parsing->is_client ? "CLI" : "SVR",
      grpc_mdstr_as_c_string(md->key), grpc_mdstr_as_c_string(md->value)));

  if (md->key == GRPC_MDSTR_GRPC_STATUS && md != GRPC_MDELEM_GRPC_STATUS_0) {
    /* TODO(ctiller): check for a status like " 0" */
    stream_parsing->seen_error = true;
  }

  const size_t new_size =
      stream_parsing->metadata_buffer[1].size + GRPC_MDELEM_LENGTH(md);
  grpc_chttp2_transport_global *transport_global =
      &TRANSPORT_FROM_PARSING(transport_parsing)->global;
  const size_t metadata_size_limit =
      transport_global->settings[GRPC_LOCAL_SETTINGS]
                                [GRPC_CHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE];
  if (new_size > metadata_size_limit) {
    if (!stream_parsing->exceeded_metadata_size) {
      gpr_log(GPR_DEBUG,
              "received trailing metadata size exceeds limit (%" PRIuPTR
              " vs. %" PRIuPTR ")",
              new_size, metadata_size_limit);
      stream_parsing->seen_error = true;
      stream_parsing->exceeded_metadata_size = true;
    }
    GRPC_MDELEM_UNREF(md);
  } else {
    grpc_chttp2_incoming_metadata_buffer_add(
        &stream_parsing->metadata_buffer[1], md);
  }

  grpc_chttp2_list_add_parsing_seen_stream(transport_parsing, stream_parsing);

  GPR_TIMER_END("on_trailing_header", 0);
}
Beispiel #10
0
static void on_initial_header(void *tp, grpc_mdelem *md) {
  grpc_chttp2_transport_parsing *transport_parsing = tp;
  grpc_chttp2_stream_parsing *stream_parsing =
      transport_parsing->incoming_stream;

  GPR_TIMER_BEGIN("on_initial_header", 0);

  GPR_ASSERT(stream_parsing);

  GRPC_CHTTP2_IF_TRACING(gpr_log(
      GPR_INFO, "HTTP:%d:HDR:%s: %s: %s", stream_parsing->id,
      transport_parsing->is_client ? "CLI" : "SVR",
      grpc_mdstr_as_c_string(md->key), grpc_mdstr_as_c_string(md->value)));

  if (md->key == GRPC_MDSTR_GRPC_STATUS && md != GRPC_MDELEM_GRPC_STATUS_0) {
    /* TODO(ctiller): check for a status like " 0" */
    stream_parsing->seen_error = 1;
  }

  if (md->key == GRPC_MDSTR_GRPC_TIMEOUT) {
    gpr_timespec *cached_timeout = grpc_mdelem_get_user_data(md, free_timeout);
    if (!cached_timeout) {
      /* not already parsed: parse it now, and store the result away */
      cached_timeout = gpr_malloc(sizeof(gpr_timespec));
      if (!grpc_chttp2_decode_timeout(grpc_mdstr_as_c_string(md->value),
                                      cached_timeout)) {
        gpr_log(GPR_ERROR, "Ignoring bad timeout value '%s'",
                grpc_mdstr_as_c_string(md->value));
        *cached_timeout = gpr_inf_future(GPR_TIMESPAN);
      }
      grpc_mdelem_set_user_data(md, free_timeout, cached_timeout);
    }
    grpc_chttp2_incoming_metadata_buffer_set_deadline(
        &stream_parsing->metadata_buffer[0],
        gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC), *cached_timeout));
    GRPC_MDELEM_UNREF(md);
  } else {
    grpc_chttp2_incoming_metadata_buffer_add(
        &stream_parsing->metadata_buffer[0], md);
  }

  grpc_chttp2_list_add_parsing_seen_stream(transport_parsing, stream_parsing);

  GPR_TIMER_END("on_initial_header", 0);
}
Beispiel #11
0
static grpc_mdelem *publish_app_metadata(grpc_call *call, grpc_mdelem *elem,
                                         int is_trailing) {
  grpc_metadata_array *dest;
  grpc_metadata *mdusr;
  GPR_TIMER_BEGIN("publish_app_metadata", 0);
  dest = call->buffered_metadata[is_trailing];
  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(elem->key);
  mdusr->value = grpc_mdstr_as_c_string(elem->value);
  mdusr->value_length = GPR_SLICE_LENGTH(elem->value->slice);
  GPR_TIMER_END("publish_app_metadata", 0);
  return elem;
}
Beispiel #12
0
void build_service_url(const char *url_scheme, call_data *calld) {
  char *service = gpr_strdup(grpc_mdstr_as_c_string(calld->method));
  char *last_slash = strrchr(service, '/');
  if (last_slash == NULL) {
    gpr_log(GPR_ERROR, "No '/' found in fully qualified method name");
    service[0] = '\0';
  } else if (last_slash == service) {
    /* No service part in fully qualified method name: will just be "/". */
    service[1] = '\0';
  } else {
    *last_slash = '\0';
  }
  if (url_scheme == NULL) url_scheme = "";
  reset_service_url(calld);
  gpr_asprintf(&calld->service_url, "%s://%s%s", url_scheme,
               grpc_mdstr_as_c_string(calld->host), service);
  gpr_free(service);
}
Beispiel #13
0
static void publish_legacy(grpc_call *call, grpc_op_error status, void *tag) {
  grpc_call_element *elem =
      grpc_call_stack_element(grpc_call_get_call_stack(call), 0);
  call_data *calld = elem->call_data;
  channel_data *chand = elem->channel_data;
  grpc_server *server = chand->server;

  if (status == GRPC_OP_OK) {
    grpc_cq_end_new_rpc(server->unregistered_cq, tag, call, do_nothing, NULL,
                        grpc_mdstr_as_c_string(calld->path),
                        grpc_mdstr_as_c_string(calld->host), calld->deadline,
                        calld->legacy->initial_metadata.count,
                        calld->legacy->initial_metadata.metadata);
  } else {
    gpr_log(GPR_ERROR, "should never reach here");
    abort();
  }
}
Beispiel #14
0
static void cpstr(char **dest, size_t *capacity, grpc_mdstr *value) {
  gpr_slice slice = value->slice;
  size_t len = GPR_SLICE_LENGTH(slice);

  if (len + 1 > *capacity) {
    *capacity = GPR_MAX(len + 1, *capacity * 2);
    *dest = gpr_realloc(*dest, *capacity);
  }
  memcpy(*dest, grpc_mdstr_as_c_string(value), len + 1);
}
Beispiel #15
0
static grpc_mdelem *lr_trailing_md_filter(void *user_data, grpc_mdelem *md) {
  grpc_call_element *elem = user_data;
  call_data *calld = elem->call_data;

  if (md->key == GRPC_MDSTR_LB_COST_BIN) {
    calld->trailing_md_string = gpr_strdup(grpc_mdstr_as_c_string(md->value));
    return NULL;
  }

  return md;
}
Beispiel #16
0
static void on_trailing_header(grpc_exec_ctx *exec_ctx, void *tp,
                               grpc_mdelem *md) {
  grpc_chttp2_transport *t = tp;
  grpc_chttp2_stream *s = t->incoming_stream;

  GPR_TIMER_BEGIN("on_trailing_header", 0);

  GPR_ASSERT(s != NULL);

  GRPC_CHTTP2_IF_TRACING(gpr_log(
      GPR_INFO, "HTTP:%d:TRL:%s: %s: %s", s->id, t->is_client ? "CLI" : "SVR",
      grpc_mdstr_as_c_string(md->key), grpc_mdstr_as_c_string(md->value)));

  if (md->key == GRPC_MDSTR_GRPC_STATUS && md != GRPC_MDELEM_GRPC_STATUS_0) {
    /* TODO(ctiller): check for a status like " 0" */
    s->seen_error = true;
  }

  const size_t new_size = s->metadata_buffer[1].size + GRPC_MDELEM_LENGTH(md);
  const size_t metadata_size_limit =
      t->settings[GRPC_ACKED_SETTINGS]
                 [GRPC_CHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE];
  if (new_size > metadata_size_limit) {
    gpr_log(GPR_DEBUG,
            "received trailing metadata size exceeds limit (%" PRIuPTR
            " vs. %" PRIuPTR ")",
            new_size, metadata_size_limit);
    grpc_chttp2_cancel_stream(
        exec_ctx, t, s,
        grpc_error_set_int(
            GRPC_ERROR_CREATE("received trailing metadata size exceeds limit"),
            GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_RESOURCE_EXHAUSTED));
    grpc_chttp2_parsing_become_skip_parser(exec_ctx, t);
    s->seen_error = true;
    GRPC_MDELEM_UNREF(md);
  } else {
    grpc_chttp2_incoming_metadata_buffer_add(&s->metadata_buffer[1], md);
  }

  GPR_TIMER_END("on_trailing_header", 0);
}
Beispiel #17
0
static grpc_metadata_array metadata_batch_to_md_array(
    const grpc_metadata_batch *batch) {
  grpc_linked_mdelem *l;
  grpc_metadata_array result;
  grpc_metadata_array_init(&result);
  for (l = batch->list.head; l != NULL; l = l->next) {
    grpc_metadata *usr_md = NULL;
    grpc_mdelem *md = l->md;
    grpc_mdstr *key = md->key;
    grpc_mdstr *value = md->value;
    if (result.count == result.capacity) {
      result.capacity = GPR_MAX(result.capacity + 8, result.capacity * 2);
      result.metadata =
          gpr_realloc(result.metadata, result.capacity * sizeof(grpc_metadata));
    }
    usr_md = &result.metadata[result.count++];
    usr_md->key = grpc_mdstr_as_c_string(key);
    usr_md->value = grpc_mdstr_as_c_string(value);
    usr_md->value_length = GPR_SLICE_LENGTH(value->slice);
  }
  return result;
}
Beispiel #18
0
/* Called either:
     - in response to an API call (or similar) from above, to send something
     - a network event (or similar) from below, to receive something
   op contains type and call direction information, in addition to the data
   that is being sent or received. */
static void auth_start_transport_op(grpc_exec_ctx *exec_ctx,
                                    grpc_call_element *elem,
                                    grpc_transport_stream_op *op) {
  /* grab pointers to our data from the call element */
  call_data *calld = elem->call_data;
  channel_data *chand = elem->channel_data;
  grpc_linked_mdelem *l;
  grpc_client_security_context *sec_ctx = NULL;

  if (calld->security_context_set == 0 &&
      op->cancel_with_status == GRPC_STATUS_OK) {
    calld->security_context_set = 1;
    GPR_ASSERT(op->context);
    if (op->context[GRPC_CONTEXT_SECURITY].value == NULL) {
      op->context[GRPC_CONTEXT_SECURITY].value =
          grpc_client_security_context_create();
      op->context[GRPC_CONTEXT_SECURITY].destroy =
          grpc_client_security_context_destroy;
    }
    sec_ctx = op->context[GRPC_CONTEXT_SECURITY].value;
    GRPC_AUTH_CONTEXT_UNREF(sec_ctx->auth_context, "client auth filter");
    sec_ctx->auth_context =
        GRPC_AUTH_CONTEXT_REF(chand->auth_context, "client_auth_filter");
  }

  if (op->send_initial_metadata != NULL) {
    for (l = op->send_initial_metadata->list.head; l != NULL; l = l->next) {
      grpc_mdelem *md = l->md;
      /* Pointer comparison is OK for md_elems created from the same context.
       */
      if (md->key == GRPC_MDSTR_AUTHORITY) {
        if (calld->host != NULL) GRPC_MDSTR_UNREF(calld->host);
        calld->host = GRPC_MDSTR_REF(md->value);
      } else if (md->key == GRPC_MDSTR_PATH) {
        if (calld->method != NULL) GRPC_MDSTR_UNREF(calld->method);
        calld->method = GRPC_MDSTR_REF(md->value);
      }
    }
    if (calld->host != NULL) {
      const char *call_host = grpc_mdstr_as_c_string(calld->host);
      calld->op = *op; /* Copy op (originates from the caller's stack). */
      grpc_channel_security_connector_check_call_host(
          exec_ctx, chand->security_connector, call_host, chand->auth_context,
          on_host_checked, elem);
      return; /* early exit */
    }
  }

  /* pass control down the stack */
  grpc_call_next_op(exec_ctx, elem, op);
}
Beispiel #19
0
static void on_host_checked(void *user_data, grpc_security_status status) {
  grpc_call_element *elem = (grpc_call_element *)user_data;
  call_data *calld = elem->call_data;

  if (status == GRPC_SECURITY_OK) {
    send_security_metadata(elem, &calld->op);
  } else {
    char *error_msg;
    gpr_asprintf(&error_msg, "Invalid host %s set in :authority metadata.",
                 grpc_mdstr_as_c_string(calld->host));
    bubble_up_error(elem, GRPC_STATUS_INVALID_ARGUMENT, error_msg);
    gpr_free(error_msg);
  }
}
Beispiel #20
0
char *grpc_transport_op_string(grpc_transport_op *op) {
  char *tmp;
  char *out;
  int first = 1;

  gpr_strvec b;
  gpr_strvec_init(&b);

  if (op->send_ops) {
    if (!first) gpr_strvec_add(&b, gpr_strdup(" "));
    first = 0;
    gpr_strvec_add(&b, gpr_strdup("SEND"));
    if (op->is_last_send) {
      gpr_strvec_add(&b, gpr_strdup("_LAST"));
    }
    gpr_strvec_add(&b, gpr_strdup("["));
    gpr_strvec_add(&b, grpc_sopb_string(op->send_ops));
    gpr_strvec_add(&b, gpr_strdup("]"));
  }

  if (op->recv_ops) {
    if (!first) gpr_strvec_add(&b, gpr_strdup(" "));
    first = 0;
    gpr_strvec_add(&b, gpr_strdup("RECV"));
  }

  if (op->bind_pollset) {
    if (!first) gpr_strvec_add(&b, gpr_strdup(" "));
    first = 0;
    gpr_strvec_add(&b, gpr_strdup("BIND"));
  }

  if (op->cancel_with_status != GRPC_STATUS_OK) {
    if (!first) gpr_strvec_add(&b, gpr_strdup(" "));
    first = 0;
    gpr_asprintf(&tmp, "CANCEL:%d", op->cancel_with_status);
    gpr_strvec_add(&b, tmp);
    if (op->cancel_message) {
      gpr_asprintf(&tmp, ";msg='%s'",
                   grpc_mdstr_as_c_string(op->cancel_message));
      gpr_strvec_add(&b, tmp);
    }
  }

  out = gpr_strvec_flatten(&b, NULL);
  gpr_strvec_destroy(&b);

  return out;
}
Beispiel #21
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 #22
0
static void on_header(void *tp, grpc_mdelem *md) {
    grpc_chttp2_transport_parsing *transport_parsing = tp;
    grpc_chttp2_stream_parsing *stream_parsing =
        transport_parsing->incoming_stream;

    GPR_ASSERT(stream_parsing);

    GRPC_CHTTP2_IF_TRACING(gpr_log(
                               GPR_INFO, "HTTP:%d:HDR:%s: %s: %s", stream_parsing->id,
                               transport_parsing->is_client ? "CLI" : "SVR",
                               grpc_mdstr_as_c_string(md->key), grpc_mdstr_as_c_string(md->value)));

    if (md->key == transport_parsing->str_grpc_timeout) {
        gpr_timespec *cached_timeout = grpc_mdelem_get_user_data(md, free_timeout);
        if (!cached_timeout) {
            /* not already parsed: parse it now, and store the result away */
            cached_timeout = gpr_malloc(sizeof(gpr_timespec));
            if (!grpc_chttp2_decode_timeout(grpc_mdstr_as_c_string(md->value),
                                            cached_timeout)) {
                gpr_log(GPR_ERROR, "Ignoring bad timeout value '%s'",
                        grpc_mdstr_as_c_string(md->value));
                *cached_timeout = gpr_inf_future(GPR_CLOCK_REALTIME);
            }
            grpc_mdelem_set_user_data(md, free_timeout, cached_timeout);
        }
        grpc_chttp2_incoming_metadata_buffer_set_deadline(
            &stream_parsing->incoming_metadata,
            gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), *cached_timeout));
        GRPC_MDELEM_UNREF(md);
    } else {
        grpc_chttp2_incoming_metadata_buffer_add(&stream_parsing->incoming_metadata,
                md);
    }

    grpc_chttp2_list_add_parsing_seen_stream(transport_parsing, stream_parsing);
}
Beispiel #23
0
static gpr_uint32 decode_status(grpc_mdelem *md) {
  gpr_uint32 status;
  void *user_data = grpc_mdelem_get_user_data(md, destroy_status);
  if (user_data) {
    status = ((gpr_uint32)(gpr_intptr) user_data) - STATUS_OFFSET;
  } else {
    if (!gpr_parse_bytes_to_uint32(grpc_mdstr_as_c_string(md->value),
                                   GPR_SLICE_LENGTH(md->value->slice),
                                   &status)) {
      status = GRPC_STATUS_UNKNOWN; /* could not parse status code */
    }
    grpc_mdelem_set_user_data(md, destroy_status,
                              (void *)(gpr_intptr)(status + STATUS_OFFSET));
  }
  return status;
}
Beispiel #24
0
/** For each \a md element from the incoming metadata, filter out the entry for
 * "grpc-encoding", using its value to populate the call data's
 * compression_algorithm field. */
static grpc_mdelem *compression_md_filter(void *user_data, grpc_mdelem *md) {
    grpc_call_element *elem = user_data;
    call_data *calld = elem->call_data;
    channel_data *channeld = elem->channel_data;

    if (md->key == channeld->mdstr_request_compression_algorithm_key) {
        const char *md_c_str = grpc_mdstr_as_c_string(md->value);
        if (!grpc_compression_algorithm_parse(md_c_str, strlen(md_c_str),
                                              &calld->compression_algorithm)) {
            gpr_log(GPR_ERROR, "Invalid compression algorithm: '%s'. Ignoring.",
                    md_c_str);
            calld->compression_algorithm = GRPC_COMPRESS_NONE;
        }
        calld->has_compression_algorithm = 1;
        return NULL;
    }

    return md;
}
Beispiel #25
0
static gpr_uint32 decode_compression(grpc_mdelem *md) {
  grpc_compression_algorithm algorithm;
  void *user_data = grpc_mdelem_get_user_data(md, destroy_compression);
  if (user_data) {
    algorithm =
        ((grpc_compression_algorithm)(gpr_intptr)user_data) - COMPRESS_OFFSET;
  } else {
    const char *md_c_str = grpc_mdstr_as_c_string(md->value);
    if (!grpc_compression_algorithm_parse(md_c_str, strlen(md_c_str),
                                          &algorithm)) {
      gpr_log(GPR_ERROR, "Invalid compression algorithm: '%s'", md_c_str);
      assert(0);
    }
    grpc_mdelem_set_user_data(
        md, destroy_compression,
        (void *)(gpr_intptr)(algorithm + COMPRESS_OFFSET));
  }
  return algorithm;
}
Beispiel #26
0
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) {
        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 GRPC_MDELEM_SCHEME_HTTP;
}
Beispiel #27
0
void* grpc_method_config_table_get(const grpc_mdstr_hash_table* table,
                                   const grpc_mdstr* path) {
  void* value = grpc_mdstr_hash_table_get(table, path);
  // If we didn't find a match for the path, try looking for a wildcard
  // entry (i.e., change "/service/method" to "/service/*").
  if (value == NULL) {
    const char* path_str = grpc_mdstr_as_c_string(path);
    const char* sep = strrchr(path_str, '/') + 1;
    const size_t len = (size_t)(sep - path_str);
    char* buf = gpr_malloc(len + 2);  // '*' and NUL
    memcpy(buf, path_str, len);
    buf[len] = '*';
    buf[len + 1] = '\0';
    grpc_mdstr* wildcard_path = grpc_mdstr_from_string(buf);
    gpr_free(buf);
    value = grpc_mdstr_hash_table_get(table, wildcard_path);
    GRPC_MDSTR_UNREF(wildcard_path);
  }
  return value;
}
Beispiel #28
0
void grpc_mdctx_global_shutdown(void) {
  size_t i;
  for (i = 0; i < MDTAB_SHARD_COUNT; i++) {
    mdtab_shard *shard = &g_mdtab_shard[i];
    gpr_mu_destroy(&shard->mu);
    gc_mdtab(shard);
    /* TODO(ctiller): GPR_ASSERT(shard->count == 0); */
    if (shard->count != 0) {
      gpr_log(GPR_DEBUG, "WARNING: %" PRIuPTR " metadata elements were leaked",
              shard->count);
      if (grpc_iomgr_abort_on_leaks()) {
        abort();
      }
    }
    gpr_free(shard->elems);
  }
  for (i = 0; i < STRTAB_SHARD_COUNT; i++) {
    strtab_shard *shard = &g_strtab_shard[i];
    gpr_mu_destroy(&shard->mu);
    /* TODO(ctiller): GPR_ASSERT(shard->count == 0); */
    if (shard->count != 0) {
      gpr_log(GPR_DEBUG, "WARNING: %" PRIuPTR " metadata strings were leaked",
              shard->count);
      for (size_t j = 0; j < shard->capacity; j++) {
        for (internal_string *s = shard->strs[j]; s; s = s->bucket_next) {
          gpr_log(GPR_DEBUG, "LEAKED: %s",
                  grpc_mdstr_as_c_string((grpc_mdstr *)s));
        }
      }
      if (grpc_iomgr_abort_on_leaks()) {
        abort();
      }
    }
    gpr_free(shard->strs);
  }
}
Beispiel #29
0
static grpc_mdelem *server_filter(void *user_data, grpc_mdelem *md) {
  server_filter_args *a = user_data;
  grpc_call_element *elem = a->elem;
  call_data *calld = elem->call_data;

  /* Check if it is one of the headers we care about. */
  if (md == GRPC_MDELEM_TE_TRAILERS || md == GRPC_MDELEM_METHOD_POST ||
      md == GRPC_MDELEM_METHOD_PUT || md == GRPC_MDELEM_SCHEME_HTTP ||
      md == GRPC_MDELEM_SCHEME_HTTPS ||
      md == GRPC_MDELEM_CONTENT_TYPE_APPLICATION_SLASH_GRPC) {
    /* swallow it */
    if (md == GRPC_MDELEM_METHOD_POST) {
      calld->seen_method = 1;
      *calld->recv_idempotent_request = false;
    } else if (md == GRPC_MDELEM_METHOD_PUT) {
      calld->seen_method = 1;
      *calld->recv_idempotent_request = true;
    } else if (md->key == GRPC_MDSTR_SCHEME) {
      calld->seen_scheme = 1;
    } else if (md == GRPC_MDELEM_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 == GRPC_MDSTR_CONTENT_TYPE) {
    const char *value_str = grpc_mdstr_as_c_string(md->value);
    if (strncmp(value_str, EXPECTED_CONTENT_TYPE,
                EXPECTED_CONTENT_TYPE_LENGTH) == 0 &&
        (value_str[EXPECTED_CONTENT_TYPE_LENGTH] == '+' ||
         value_str[EXPECTED_CONTENT_TYPE_LENGTH] == ';')) {
      /* 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'", value_str);
    }
    return NULL;
  } else if (md->key == GRPC_MDSTR_TE || md->key == GRPC_MDSTR_METHOD ||
             md->key == GRPC_MDSTR_SCHEME) {
    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(a->exec_ctx, elem);
    return NULL;
  } else if (md->key == GRPC_MDSTR_PATH) {
    if (calld->seen_path) {
      gpr_log(GPR_ERROR, "Received :path twice");
      return NULL;
    }
    calld->seen_path = 1;
    return md;
  } else if (md->key == GRPC_MDSTR_AUTHORITY) {
    calld->seen_authority = 1;
    return md;
  } else if (md->key == GRPC_MDSTR_HOST) {
    /* translate host to :authority since :authority may be
       omitted */
    grpc_mdelem *authority = grpc_mdelem_from_metadata_strings(
        GRPC_MDSTR_AUTHORITY, GRPC_MDSTR_REF(md->value));
    calld->seen_authority = 1;
    return authority;
  } else {
    return md;
  }
}
Beispiel #30
0
        }
        if (ctx->strtab_count == 0) {
            metadata_context_destroy_locked(ctx);
            return;
        }
    }
    gpr_mu_unlock(&ctx->mu);
}

static void ref_md_locked(internal_metadata *md DEBUG_ARGS) {
#ifdef GRPC_METADATA_REFCOUNT_DEBUG
    gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
            "ELM   REF:%p:%d->%d: '%s' = '%s'", md,
            gpr_atm_no_barrier_load(&md->refcnt),
            gpr_atm_no_barrier_load(&md->refcnt) + 1,
            grpc_mdstr_as_c_string((grpc_mdstr *)md->key),
            grpc_mdstr_as_c_string((grpc_mdstr *)md->value));
#endif
    if (0 == gpr_atm_no_barrier_fetch_add(&md->refcnt, 1)) {
        md->context->mdtab_free--;
    }
}

grpc_mdctx *grpc_mdctx_create_with_seed(gpr_uint32 seed) {
    grpc_mdctx *ctx = gpr_malloc(sizeof(grpc_mdctx));

    ctx->refs = 1;
    ctx->hash_seed = seed;
    gpr_mu_init(&ctx->mu);
    ctx->strtab = gpr_malloc(sizeof(internal_string *) * INITIAL_STRTAB_CAPACITY);
    memset(ctx->strtab, 0, sizeof(grpc_mdstr *) * INITIAL_STRTAB_CAPACITY);