aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core/lib/surface
diff options
context:
space:
mode:
authorGravatar Craig Tiller <ctiller@google.com>2017-01-20 18:11:52 -0800
committerGravatar GitHub <noreply@github.com>2017-01-20 18:11:52 -0800
commit5e01e2ac977655aa074faf7fde0a74298f5e4c55 (patch)
tree9acab9c5952f292683a6d474861e2997e2a9d664 /src/core/lib/surface
parentc84725fd02dc58a819c8c4e8acdc321e81f44764 (diff)
Revert "Metadata handling rewrite"
Diffstat (limited to 'src/core/lib/surface')
-rw-r--r--src/core/lib/surface/call.c988
-rw-r--r--src/core/lib/surface/call.h2
-rw-r--r--src/core/lib/surface/call_details.c10
-rw-r--r--src/core/lib/surface/call_log_batch.c23
-rw-r--r--src/core/lib/surface/channel.c106
-rw-r--r--src/core/lib/surface/channel.h11
-rw-r--r--src/core/lib/surface/completion_queue.c15
-rw-r--r--src/core/lib/surface/init.c3
-rw-r--r--src/core/lib/surface/lame_client.c16
-rw-r--r--src/core/lib/surface/server.c142
-rw-r--r--src/core/lib/surface/validate_metadata.c61
-rw-r--r--src/core/lib/surface/validate_metadata.h43
12 files changed, 702 insertions, 718 deletions
diff --git a/src/core/lib/surface/call.c b/src/core/lib/surface/call.c
index 63b0683df5..899e8fab3f 100644
--- a/src/core/lib/surface/call.c
+++ b/src/core/lib/surface/call.c
@@ -56,15 +56,13 @@
#include "src/core/lib/surface/call.h"
#include "src/core/lib/surface/channel.h"
#include "src/core/lib/surface/completion_queue.h"
-#include "src/core/lib/surface/validate_metadata.h"
-#include "src/core/lib/transport/error_utils.h"
#include "src/core/lib/transport/metadata.h"
#include "src/core/lib/transport/static_metadata.h"
#include "src/core/lib/transport/transport.h"
/** The maximum number of concurrent batches possible.
Based upon the maximum number of individually queueable ops in the batch
- api:
+ api:
- initial metadata send
- message send
- status/close send (depending on client/server)
@@ -94,21 +92,18 @@ typedef enum {
} status_source;
typedef struct {
- bool is_set;
- grpc_error *error;
+ uint8_t is_set;
+ grpc_status_code code;
+ grpc_mdstr *details;
} received_status;
-#define MAX_ERRORS_PER_BATCH 3
-
typedef struct batch_control {
grpc_call *call;
grpc_cq_completion cq_completion;
grpc_closure finish_batch;
void *notify_tag;
gpr_refcount steps_to_complete;
-
- grpc_error *errors[MAX_ERRORS_PER_BATCH];
- gpr_atm num_errors;
+ grpc_error *error;
uint8_t send_initial_metadata;
uint8_t send_message;
@@ -190,7 +185,6 @@ struct grpc_call {
grpc_call *sibling_prev;
grpc_slice_buffer_stream sending_stream;
-
grpc_byte_stream *receiving_stream;
grpc_byte_buffer **receiving_buffer;
grpc_slice receiving_slice;
@@ -202,7 +196,8 @@ struct grpc_call {
union {
struct {
grpc_status_code *status;
- grpc_slice *status_details;
+ char **status_details;
+ size_t *status_details_capacity;
} client;
struct {
int *cancelled;
@@ -224,23 +219,13 @@ static void execute_op(grpc_exec_ctx *exec_ctx, grpc_call *call,
static grpc_call_error cancel_with_status(grpc_exec_ctx *exec_ctx, grpc_call *c,
grpc_status_code status,
const char *description);
-static void cancel_with_error(grpc_exec_ctx *exec_ctx, grpc_call *c,
- grpc_error *error);
+static grpc_call_error close_with_status(grpc_exec_ctx *exec_ctx, grpc_call *c,
+ grpc_status_code status,
+ const char *description);
static void destroy_call(grpc_exec_ctx *exec_ctx, void *call_stack,
grpc_error *error);
static void receiving_slice_ready(grpc_exec_ctx *exec_ctx, void *bctlp,
grpc_error *error);
-static void get_final_status(grpc_call *call,
- void (*set_value)(grpc_status_code code,
- void *user_data),
- void *set_value_user_data, grpc_slice *details);
-static void set_status_value_directly(grpc_status_code status, void *dest);
-static void set_status_from_error(grpc_exec_ctx *exec_ctx, grpc_call *call,
- status_source source, grpc_error *error);
-static void process_data_after_md(grpc_exec_ctx *exec_ctx, batch_control *bctl);
-static void post_batch_completion(grpc_exec_ctx *exec_ctx, batch_control *bctl);
-static void add_batch_error(grpc_exec_ctx *exec_ctx, batch_control *bctl,
- grpc_error *error);
grpc_error *grpc_call_create(grpc_exec_ctx *exec_ctx,
const grpc_call_create_args *args,
@@ -261,16 +246,14 @@ grpc_error *grpc_call_create(grpc_exec_ctx *exec_ctx,
/* Always support no compression */
GPR_BITSET(&call->encodings_accepted_by_peer, GRPC_COMPRESS_NONE);
call->is_client = args->server_transport_data == NULL;
- grpc_slice path = grpc_empty_slice();
+ grpc_mdstr *path = NULL;
if (call->is_client) {
GPR_ASSERT(args->add_initial_metadata_count <
MAX_SEND_EXTRA_METADATA_COUNT);
for (i = 0; i < args->add_initial_metadata_count; i++) {
call->send_extra_metadata[i].md = args->add_initial_metadata[i];
- if (grpc_slice_eq(GRPC_MDKEY(args->add_initial_metadata[i]),
- GRPC_MDSTR_PATH)) {
- path = grpc_slice_ref_internal(
- GRPC_MDVALUE(args->add_initial_metadata[i]));
+ if (args->add_initial_metadata[i]->key == GRPC_MDSTR_PATH) {
+ path = GRPC_MDSTR_REF(args->add_initial_metadata[i]->value);
}
}
call->send_extra_metadata_count = (int)args->add_initial_metadata_count;
@@ -337,7 +320,10 @@ grpc_error *grpc_call_create(grpc_exec_ctx *exec_ctx,
args->server_transport_data, path, call->start_time, send_deadline,
CALL_STACK_FROM_CALL(call));
if (error != GRPC_ERROR_NONE) {
- cancel_with_error(exec_ctx, call, GRPC_ERROR_REF(error));
+ grpc_status_code status;
+ const char *error_str;
+ grpc_error_get_status(error, &status, &error_str);
+ close_with_status(exec_ctx, call, status, error_str);
}
if (args->cq != NULL) {
GPR_ASSERT(
@@ -356,7 +342,7 @@ grpc_error *grpc_call_create(grpc_exec_ctx *exec_ctx,
exec_ctx, CALL_STACK_FROM_CALL(call), &call->pollent);
}
- grpc_slice_unref_internal(exec_ctx, path);
+ if (path != NULL) GRPC_MDSTR_UNREF(exec_ctx, path);
GPR_TIMER_END("grpc_call_create", 0);
return error;
@@ -391,6 +377,24 @@ void grpc_call_internal_unref(grpc_exec_ctx *exec_ctx, grpc_call *c REF_ARG) {
GRPC_CALL_STACK_UNREF(exec_ctx, CALL_STACK_FROM_CALL(c), REF_REASON);
}
+static void get_final_status(grpc_call *call,
+ void (*set_value)(grpc_status_code code,
+ void *user_data),
+ void *set_value_user_data) {
+ int i;
+ for (i = 0; i < STATUS_SOURCE_COUNT; i++) {
+ if (call->status[i].is_set) {
+ set_value(call->status[i].code, set_value_user_data);
+ return;
+ }
+ }
+ if (call->is_client) {
+ set_value(GRPC_STATUS_UNKNOWN, set_value_user_data);
+ } else {
+ set_value(GRPC_STATUS_OK, set_value_user_data);
+ }
+}
+
static void set_status_value_directly(grpc_status_code status, void *dest);
static void destroy_call(grpc_exec_ctx *exec_ctx, void *call,
grpc_error *error) {
@@ -406,6 +410,11 @@ static void destroy_call(grpc_exec_ctx *exec_ctx, void *call,
grpc_byte_stream_destroy(exec_ctx, c->receiving_stream);
}
gpr_mu_destroy(&c->mu);
+ for (i = 0; i < STATUS_SOURCE_COUNT; i++) {
+ if (c->status[i].details) {
+ GRPC_MDSTR_UNREF(exec_ctx, c->status[i].details);
+ }
+ }
for (ii = 0; ii < c->send_extra_metadata_count; ii++) {
GRPC_MDELEM_UNREF(exec_ctx, c->send_extra_metadata[ii].md);
}
@@ -419,245 +428,42 @@ static void destroy_call(grpc_exec_ctx *exec_ctx, void *call,
}
grpc_channel *channel = c->channel;
- get_final_status(call, set_status_value_directly, &c->final_info.final_status,
- NULL);
+ get_final_status(call, set_status_value_directly,
+ &c->final_info.final_status);
c->final_info.stats.latency =
gpr_time_sub(gpr_now(GPR_CLOCK_MONOTONIC), c->start_time);
- for (i = 0; i < STATUS_SOURCE_COUNT; i++) {
- GRPC_ERROR_UNREF(c->status[i].error);
- }
-
grpc_call_stack_destroy(exec_ctx, CALL_STACK_FROM_CALL(c), &c->final_info, c);
GRPC_CHANNEL_INTERNAL_UNREF(exec_ctx, channel, "call");
GPR_TIMER_END("destroy_call", 0);
}
-void grpc_call_destroy(grpc_call *c) {
- int cancel;
- grpc_call *parent = c->parent;
- grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-
- GPR_TIMER_BEGIN("grpc_call_destroy", 0);
- GRPC_API_TRACE("grpc_call_destroy(c=%p)", 1, (c));
-
- if (parent) {
- gpr_mu_lock(&parent->mu);
- if (c == parent->first_child) {
- parent->first_child = c->sibling_next;
- if (c == parent->first_child) {
- parent->first_child = NULL;
- }
- c->sibling_prev->sibling_next = c->sibling_next;
- c->sibling_next->sibling_prev = c->sibling_prev;
- }
- gpr_mu_unlock(&parent->mu);
- GRPC_CALL_INTERNAL_UNREF(&exec_ctx, parent, "child");
- }
-
- gpr_mu_lock(&c->mu);
- GPR_ASSERT(!c->destroy_called);
- c->destroy_called = 1;
- cancel = !c->received_final_op;
- gpr_mu_unlock(&c->mu);
- if (cancel) grpc_call_cancel(c, NULL);
- GRPC_CALL_INTERNAL_UNREF(&exec_ctx, c, "destroy");
- grpc_exec_ctx_finish(&exec_ctx);
- GPR_TIMER_END("grpc_call_destroy", 0);
-}
-
-grpc_call_error grpc_call_cancel(grpc_call *call, void *reserved) {
- GRPC_API_TRACE("grpc_call_cancel(call=%p, reserved=%p)", 2, (call, reserved));
- GPR_ASSERT(!reserved);
- return grpc_call_cancel_with_status(call, GRPC_STATUS_CANCELLED, "Cancelled",
- NULL);
-}
-
-static void execute_op(grpc_exec_ctx *exec_ctx, grpc_call *call,
- grpc_transport_stream_op *op) {
- grpc_call_element *elem;
-
- GPR_TIMER_BEGIN("execute_op", 0);
- elem = CALL_ELEM_FROM_CALL(call, 0);
- op->context = call->context;
- elem->filter->start_transport_stream_op(exec_ctx, elem, op);
- GPR_TIMER_END("execute_op", 0);
-}
-
-char *grpc_call_get_peer(grpc_call *call) {
- grpc_call_element *elem = CALL_ELEM_FROM_CALL(call, 0);
- grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
- char *result;
- GRPC_API_TRACE("grpc_call_get_peer(%p)", 1, (call));
- result = elem->filter->get_peer(&exec_ctx, elem);
- if (result == NULL) {
- result = grpc_channel_get_target(call->channel);
- }
- if (result == NULL) {
- result = gpr_strdup("unknown");
- }
- grpc_exec_ctx_finish(&exec_ctx);
- return result;
-}
-
-grpc_call *grpc_call_from_top_element(grpc_call_element *elem) {
- return CALL_FROM_TOP_ELEM(elem);
-}
-
-/*******************************************************************************
- * CANCELLATION
- */
-
-grpc_call_error grpc_call_cancel_with_status(grpc_call *c,
- grpc_status_code status,
- const char *description,
- void *reserved) {
- grpc_call_error r;
- grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
- GRPC_API_TRACE(
- "grpc_call_cancel_with_status("
- "c=%p, status=%d, description=%s, reserved=%p)",
- 4, (c, (int)status, description, reserved));
- GPR_ASSERT(reserved == NULL);
- gpr_mu_lock(&c->mu);
- r = cancel_with_status(&exec_ctx, c, status, description);
- gpr_mu_unlock(&c->mu);
- grpc_exec_ctx_finish(&exec_ctx);
- return r;
-}
-
-typedef struct termination_closure {
- grpc_closure closure;
- grpc_call *call;
- grpc_error *error;
- grpc_transport_stream_op op;
-} termination_closure;
-
-static void done_termination(grpc_exec_ctx *exec_ctx, void *tcp,
- grpc_error *error) {
- termination_closure *tc = tcp;
- GRPC_CALL_INTERNAL_UNREF(exec_ctx, tc->call, "termination");
- gpr_free(tc);
-}
-
-static void send_termination(grpc_exec_ctx *exec_ctx, void *tcp,
- grpc_error *error) {
- termination_closure *tc = tcp;
- memset(&tc->op, 0, sizeof(tc->op));
- tc->op.cancel_error = tc->error;
- /* reuse closure to catch completion */
- grpc_closure_init(&tc->closure, done_termination, tc,
- grpc_schedule_on_exec_ctx);
- tc->op.on_complete = &tc->closure;
- execute_op(exec_ctx, tc->call, &tc->op);
-}
-
-static grpc_call_error terminate_with_status(grpc_exec_ctx *exec_ctx,
- termination_closure *tc) {
- set_status_from_error(exec_ctx, tc->call, STATUS_FROM_API_OVERRIDE,
- GRPC_ERROR_REF(tc->error));
- grpc_closure_init(&tc->closure, send_termination, tc,
- grpc_schedule_on_exec_ctx);
- GRPC_CALL_INTERNAL_REF(tc->call, "termination");
- grpc_closure_sched(exec_ctx, &tc->closure, GRPC_ERROR_NONE);
- return GRPC_CALL_OK;
-}
-
-static grpc_call_error terminate_with_error(grpc_exec_ctx *exec_ctx,
- grpc_call *c, grpc_error *error) {
- termination_closure *tc = gpr_malloc(sizeof(*tc));
- memset(tc, 0, sizeof(*tc));
- tc->call = c;
- tc->error = error;
- return terminate_with_status(exec_ctx, tc);
-}
+static void set_status_code(grpc_call *call, status_source source,
+ uint32_t status) {
+ if (call->status[source].is_set) return;
-static void cancel_with_error(grpc_exec_ctx *exec_ctx, grpc_call *c,
- grpc_error *error) {
- terminate_with_error(exec_ctx, c, error);
+ call->status[source].is_set = 1;
+ call->status[source].code = (grpc_status_code)status;
}
-static grpc_error *error_from_status(grpc_status_code status,
- const char *description) {
- return grpc_error_set_int(
- grpc_error_set_str(GRPC_ERROR_CREATE(description),
- GRPC_ERROR_STR_GRPC_MESSAGE, description),
- GRPC_ERROR_INT_GRPC_STATUS, status);
-}
-
-static grpc_call_error cancel_with_status(grpc_exec_ctx *exec_ctx, grpc_call *c,
- grpc_status_code status,
- const char *description) {
- return terminate_with_error(exec_ctx, c,
- error_from_status(status, description));
-}
-
-/*******************************************************************************
- * FINAL STATUS CODE MANIPULATION
- */
-
-static void get_final_status_from(grpc_call *call, status_source from_source,
- void (*set_value)(grpc_status_code code,
- void *user_data),
- void *set_value_user_data,
- grpc_slice *details) {
- grpc_status_code code;
- const char *msg = NULL;
- grpc_error_get_status(call->status[from_source].error, call->send_deadline,
- &code, &msg, NULL);
-
- set_value(code, set_value_user_data);
- if (details != NULL) {
- *details =
- msg == NULL ? grpc_empty_slice() : grpc_slice_from_copied_string(msg);
- }
-}
-
-static void get_final_status(grpc_call *call,
- void (*set_value)(grpc_status_code code,
- void *user_data),
- void *set_value_user_data, grpc_slice *details) {
- int i;
- /* search for the best status we can present: ideally the error we use has a
- clearly defined grpc-status, and we'll prefer that. */
- for (i = 0; i < STATUS_SOURCE_COUNT; i++) {
- if (call->status[i].is_set &&
- grpc_error_has_clear_grpc_status(call->status[i].error)) {
- get_final_status_from(call, (status_source)i, set_value,
- set_value_user_data, details);
- return;
- }
- }
- /* If no clearly defined status exists, search for 'anything' */
- for (i = 0; i < STATUS_SOURCE_COUNT; i++) {
- if (call->status[i].is_set) {
- get_final_status_from(call, (status_source)i, set_value,
- set_value_user_data, details);
- return;
- }
- }
- /* If nothing exists, set some default */
- if (call->is_client) {
- set_value(GRPC_STATUS_UNKNOWN, set_value_user_data);
+static void set_status_details(grpc_exec_ctx *exec_ctx, grpc_call *call,
+ status_source source, grpc_mdstr *status) {
+ if (call->status[source].details != NULL) {
+ GRPC_MDSTR_UNREF(exec_ctx, status);
} else {
- set_value(GRPC_STATUS_OK, set_value_user_data);
+ call->status[source].details = status;
}
}
static void set_status_from_error(grpc_exec_ctx *exec_ctx, grpc_call *call,
status_source source, grpc_error *error) {
- if (call->status[source].is_set) {
- GRPC_ERROR_UNREF(error);
- return;
- }
- call->status[source].is_set = true;
- call->status[source].error = error;
+ grpc_status_code status;
+ const char *msg;
+ grpc_error_get_status(error, &status, &msg);
+ set_status_code(call, source, (uint32_t)status);
+ set_status_details(exec_ctx, call, source, grpc_mdstr_from_string(msg));
}
-/*******************************************************************************
- * COMPRESSION
- */
-
static void set_incoming_compression_algorithm(
grpc_call *call, grpc_compression_algorithm algo) {
GPR_ASSERT(algo < GRPC_COMPRESS_ALGORITHMS_COUNT);
@@ -690,7 +496,7 @@ uint32_t grpc_call_test_only_get_message_flags(grpc_call *call) {
static void destroy_encodings_accepted_by_peer(void *p) { return; }
static void set_encodings_accepted_by_peer(grpc_exec_ctx *exec_ctx,
- grpc_call *call, grpc_mdelem mdel) {
+ grpc_call *call, grpc_mdelem *mdel) {
size_t i;
grpc_compression_algorithm algorithm;
grpc_slice_buffer accept_encoding_parts;
@@ -705,7 +511,7 @@ static void set_encodings_accepted_by_peer(grpc_exec_ctx *exec_ctx,
return;
}
- accept_encoding_slice = GRPC_MDVALUE(mdel);
+ accept_encoding_slice = mdel->value->slice;
grpc_slice_buffer_init(&accept_encoding_parts);
grpc_slice_split(accept_encoding_slice, ",", &accept_encoding_parts);
@@ -714,13 +520,15 @@ static void set_encodings_accepted_by_peer(grpc_exec_ctx *exec_ctx,
/* Always support no compression */
GPR_BITSET(&call->encodings_accepted_by_peer, GRPC_COMPRESS_NONE);
for (i = 0; i < accept_encoding_parts.count; i++) {
- grpc_slice accept_encoding_entry_slice = accept_encoding_parts.slices[i];
- if (grpc_compression_algorithm_parse(accept_encoding_entry_slice,
- &algorithm)) {
+ const grpc_slice *accept_encoding_entry_slice =
+ &accept_encoding_parts.slices[i];
+ if (grpc_compression_algorithm_parse(
+ (const char *)GRPC_SLICE_START_PTR(*accept_encoding_entry_slice),
+ GRPC_SLICE_LENGTH(*accept_encoding_entry_slice), &algorithm)) {
GPR_BITSET(&call->encodings_accepted_by_peer, algorithm);
} else {
char *accept_encoding_entry_str =
- grpc_slice_to_c_string(accept_encoding_entry_slice);
+ grpc_dump_slice(*accept_encoding_entry_slice, GPR_DUMP_ASCII);
gpr_log(GPR_ERROR,
"Invalid entry in accept encoding metadata: '%s'. Ignoring.",
accept_encoding_entry_str);
@@ -743,6 +551,36 @@ uint32_t grpc_call_test_only_get_encodings_accepted_by_peer(grpc_call *call) {
return encodings_accepted_by_peer;
}
+static void get_final_details(grpc_call *call, char **out_details,
+ size_t *out_details_capacity) {
+ int i;
+ for (i = 0; i < STATUS_SOURCE_COUNT; i++) {
+ if (call->status[i].is_set) {
+ if (call->status[i].details) {
+ grpc_slice details = call->status[i].details->slice;
+ size_t len = GRPC_SLICE_LENGTH(details);
+ if (len + 1 > *out_details_capacity) {
+ *out_details_capacity =
+ GPR_MAX(len + 1, *out_details_capacity * 3 / 2);
+ *out_details = gpr_realloc(*out_details, *out_details_capacity);
+ }
+ memcpy(*out_details, GRPC_SLICE_START_PTR(details), len);
+ (*out_details)[len] = 0;
+ } else {
+ goto no_details;
+ }
+ return;
+ }
+ }
+
+no_details:
+ if (0 == *out_details_capacity) {
+ *out_details_capacity = 8;
+ *out_details = gpr_malloc(*out_details_capacity);
+ }
+ **out_details = 0;
+}
+
static grpc_linked_mdelem *linked_from_md(grpc_metadata *md) {
return (grpc_linked_mdelem *)&md->internal_data;
}
@@ -769,19 +607,24 @@ static int prepare_application_metadata(
get_md_elem(metadata, additional_metadata, i, count);
grpc_linked_mdelem *l = (grpc_linked_mdelem *)&md->internal_data;
GPR_ASSERT(sizeof(grpc_linked_mdelem) == sizeof(md->internal_data));
- if (!GRPC_LOG_IF_ERROR("validate_metadata",
- grpc_validate_header_key_is_legal(md->key))) {
+ l->md = grpc_mdelem_from_string_and_buffer(
+ exec_ctx, md->key, (const uint8_t *)md->value, md->value_length);
+ if (!grpc_header_key_is_legal(grpc_mdstr_as_c_string(l->md->key),
+ GRPC_MDSTR_LENGTH(l->md->key))) {
+ gpr_log(GPR_ERROR, "attempt to send invalid metadata key: %s",
+ grpc_mdstr_as_c_string(l->md->key));
break;
- } else if (!grpc_is_binary_header(md->key) &&
- !GRPC_LOG_IF_ERROR(
- "validate_metadata",
- grpc_validate_header_nonbin_value_is_legal(md->value))) {
+ } else if (!grpc_is_binary_header(grpc_mdstr_as_c_string(l->md->key),
+ GRPC_MDSTR_LENGTH(l->md->key)) &&
+ !grpc_header_nonbin_value_is_legal(
+ grpc_mdstr_as_c_string(l->md->value),
+ GRPC_MDSTR_LENGTH(l->md->value))) {
+ gpr_log(GPR_ERROR, "attempt to send invalid metadata value");
break;
}
- l->md = grpc_mdelem_from_grpc_metadata(exec_ctx, (grpc_metadata *)md);
}
if (i != total_count) {
- for (int j = 0; j < i; j++) {
+ for (int j = 0; j <= i; j++) {
const grpc_metadata *md =
get_md_elem(metadata, additional_metadata, j, count);
grpc_linked_mdelem *l = (grpc_linked_mdelem *)&md->internal_data;
@@ -793,41 +636,278 @@ static int prepare_application_metadata(
if (call->send_extra_metadata_count == 0) {
prepend_extra_metadata = 0;
} else {
- for (i = 0; i < call->send_extra_metadata_count; i++) {
- GRPC_LOG_IF_ERROR("prepare_application_metadata",
- grpc_metadata_batch_link_tail(
- exec_ctx, batch, &call->send_extra_metadata[i]));
+ for (i = 1; i < call->send_extra_metadata_count; i++) {
+ call->send_extra_metadata[i].prev = &call->send_extra_metadata[i - 1];
+ }
+ for (i = 0; i < call->send_extra_metadata_count - 1; i++) {
+ call->send_extra_metadata[i].next = &call->send_extra_metadata[i + 1];
}
}
}
- for (i = 0; i < total_count; i++) {
+ for (i = 1; i < total_count; i++) {
+ grpc_metadata *md = get_md_elem(metadata, additional_metadata, i, count);
+ grpc_metadata *prev_md =
+ get_md_elem(metadata, additional_metadata, i - 1, count);
+ linked_from_md(md)->prev = linked_from_md(prev_md);
+ }
+ for (i = 0; i < total_count - 1; i++) {
grpc_metadata *md = get_md_elem(metadata, additional_metadata, i, count);
- GRPC_LOG_IF_ERROR(
- "prepare_application_metadata",
- grpc_metadata_batch_link_tail(exec_ctx, batch, linked_from_md(md)));
+ grpc_metadata *next_md =
+ get_md_elem(metadata, additional_metadata, i + 1, count);
+ linked_from_md(md)->next = linked_from_md(next_md);
+ }
+
+ switch (prepend_extra_metadata * 2 + (total_count != 0)) {
+ case 0:
+ /* no prepend, no metadata => nothing to do */
+ batch->list.head = batch->list.tail = NULL;
+ break;
+ case 1: {
+ /* metadata, but no prepend */
+ grpc_metadata *first_md =
+ get_md_elem(metadata, additional_metadata, 0, count);
+ grpc_metadata *last_md =
+ get_md_elem(metadata, additional_metadata, total_count - 1, count);
+ batch->list.head = linked_from_md(first_md);
+ batch->list.tail = linked_from_md(last_md);
+ batch->list.head->prev = NULL;
+ batch->list.tail->next = NULL;
+ break;
+ }
+ case 2:
+ /* prepend, but no md */
+ batch->list.head = &call->send_extra_metadata[0];
+ batch->list.tail =
+ &call->send_extra_metadata[call->send_extra_metadata_count - 1];
+ batch->list.head->prev = NULL;
+ batch->list.tail->next = NULL;
+ call->send_extra_metadata_count = 0;
+ break;
+ case 3: {
+ /* prepend AND md */
+ grpc_metadata *first_md =
+ get_md_elem(metadata, additional_metadata, 0, count);
+ grpc_metadata *last_md =
+ get_md_elem(metadata, additional_metadata, total_count - 1, count);
+ batch->list.head = &call->send_extra_metadata[0];
+ call->send_extra_metadata[call->send_extra_metadata_count - 1].next =
+ linked_from_md(first_md);
+ linked_from_md(first_md)->prev =
+ &call->send_extra_metadata[call->send_extra_metadata_count - 1];
+ batch->list.tail = linked_from_md(last_md);
+ batch->list.head->prev = NULL;
+ batch->list.tail->next = NULL;
+ call->send_extra_metadata_count = 0;
+ break;
+ }
+ default:
+ GPR_UNREACHABLE_CODE(return 0);
}
- call->send_extra_metadata_count = 0;
return 1;
}
+void grpc_call_destroy(grpc_call *c) {
+ int cancel;
+ grpc_call *parent = c->parent;
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+
+ GPR_TIMER_BEGIN("grpc_call_destroy", 0);
+ GRPC_API_TRACE("grpc_call_destroy(c=%p)", 1, (c));
+
+ if (parent) {
+ gpr_mu_lock(&parent->mu);
+ if (c == parent->first_child) {
+ parent->first_child = c->sibling_next;
+ if (c == parent->first_child) {
+ parent->first_child = NULL;
+ }
+ c->sibling_prev->sibling_next = c->sibling_next;
+ c->sibling_next->sibling_prev = c->sibling_prev;
+ }
+ gpr_mu_unlock(&parent->mu);
+ GRPC_CALL_INTERNAL_UNREF(&exec_ctx, parent, "child");
+ }
+
+ gpr_mu_lock(&c->mu);
+ GPR_ASSERT(!c->destroy_called);
+ c->destroy_called = 1;
+ cancel = !c->received_final_op;
+ gpr_mu_unlock(&c->mu);
+ if (cancel) grpc_call_cancel(c, NULL);
+ GRPC_CALL_INTERNAL_UNREF(&exec_ctx, c, "destroy");
+ grpc_exec_ctx_finish(&exec_ctx);
+ GPR_TIMER_END("grpc_call_destroy", 0);
+}
+
+grpc_call_error grpc_call_cancel(grpc_call *call, void *reserved) {
+ GRPC_API_TRACE("grpc_call_cancel(call=%p, reserved=%p)", 2, (call, reserved));
+ GPR_ASSERT(!reserved);
+ return grpc_call_cancel_with_status(call, GRPC_STATUS_CANCELLED, "Cancelled",
+ NULL);
+}
+
+grpc_call_error grpc_call_cancel_with_status(grpc_call *c,
+ grpc_status_code status,
+ const char *description,
+ void *reserved) {
+ grpc_call_error r;
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ GRPC_API_TRACE(
+ "grpc_call_cancel_with_status("
+ "c=%p, status=%d, description=%s, reserved=%p)",
+ 4, (c, (int)status, description, reserved));
+ GPR_ASSERT(reserved == NULL);
+ gpr_mu_lock(&c->mu);
+ r = cancel_with_status(&exec_ctx, c, status, description);
+ gpr_mu_unlock(&c->mu);
+ grpc_exec_ctx_finish(&exec_ctx);
+ return r;
+}
+
+typedef struct termination_closure {
+ grpc_closure closure;
+ grpc_call *call;
+ grpc_error *error;
+ enum { TC_CANCEL, TC_CLOSE } type;
+ grpc_transport_stream_op op;
+} termination_closure;
+
+static void done_termination(grpc_exec_ctx *exec_ctx, void *tcp,
+ grpc_error *error) {
+ termination_closure *tc = tcp;
+ switch (tc->type) {
+ case TC_CANCEL:
+ GRPC_CALL_INTERNAL_UNREF(exec_ctx, tc->call, "cancel");
+ break;
+ case TC_CLOSE:
+ GRPC_CALL_INTERNAL_UNREF(exec_ctx, tc->call, "close");
+ break;
+ }
+ GRPC_ERROR_UNREF(tc->error);
+ gpr_free(tc);
+}
+
+static void send_cancel(grpc_exec_ctx *exec_ctx, void *tcp, grpc_error *error) {
+ termination_closure *tc = tcp;
+ memset(&tc->op, 0, sizeof(tc->op));
+ tc->op.cancel_error = tc->error;
+ /* reuse closure to catch completion */
+ grpc_closure_init(&tc->closure, done_termination, tc,
+ grpc_schedule_on_exec_ctx);
+ tc->op.on_complete = &tc->closure;
+ execute_op(exec_ctx, tc->call, &tc->op);
+}
+
+static void send_close(grpc_exec_ctx *exec_ctx, void *tcp, grpc_error *error) {
+ termination_closure *tc = tcp;
+ memset(&tc->op, 0, sizeof(tc->op));
+ tc->op.close_error = tc->error;
+ /* reuse closure to catch completion */
+ grpc_closure_init(&tc->closure, done_termination, tc,
+ grpc_schedule_on_exec_ctx);
+ tc->op.on_complete = &tc->closure;
+ execute_op(exec_ctx, tc->call, &tc->op);
+}
+
+static grpc_call_error terminate_with_status(grpc_exec_ctx *exec_ctx,
+ termination_closure *tc) {
+ set_status_from_error(exec_ctx, tc->call, STATUS_FROM_API_OVERRIDE,
+ tc->error);
+
+ if (tc->type == TC_CANCEL) {
+ grpc_closure_init(&tc->closure, send_cancel, tc, grpc_schedule_on_exec_ctx);
+ GRPC_CALL_INTERNAL_REF(tc->call, "cancel");
+ } else if (tc->type == TC_CLOSE) {
+ grpc_closure_init(&tc->closure, send_close, tc, grpc_schedule_on_exec_ctx);
+ GRPC_CALL_INTERNAL_REF(tc->call, "close");
+ }
+ grpc_closure_sched(exec_ctx, &tc->closure, GRPC_ERROR_NONE);
+ return GRPC_CALL_OK;
+}
+
+static grpc_call_error cancel_with_status(grpc_exec_ctx *exec_ctx, grpc_call *c,
+ grpc_status_code status,
+ const char *description) {
+ GPR_ASSERT(status != GRPC_STATUS_OK);
+ termination_closure *tc = gpr_malloc(sizeof(*tc));
+ memset(tc, 0, sizeof(termination_closure));
+ tc->type = TC_CANCEL;
+ tc->call = c;
+ tc->error = grpc_error_set_int(
+ grpc_error_set_str(GRPC_ERROR_CREATE(description),
+ GRPC_ERROR_STR_GRPC_MESSAGE, description),
+ GRPC_ERROR_INT_GRPC_STATUS, status);
+
+ return terminate_with_status(exec_ctx, tc);
+}
+
+static grpc_call_error close_with_status(grpc_exec_ctx *exec_ctx, grpc_call *c,
+ grpc_status_code status,
+ const char *description) {
+ GPR_ASSERT(status != GRPC_STATUS_OK);
+ termination_closure *tc = gpr_malloc(sizeof(*tc));
+ memset(tc, 0, sizeof(termination_closure));
+ tc->type = TC_CLOSE;
+ tc->call = c;
+ tc->error = grpc_error_set_int(
+ grpc_error_set_str(GRPC_ERROR_CREATE(description),
+ GRPC_ERROR_STR_GRPC_MESSAGE, description),
+ GRPC_ERROR_INT_GRPC_STATUS, status);
+
+ return terminate_with_status(exec_ctx, tc);
+}
+
+static void execute_op(grpc_exec_ctx *exec_ctx, grpc_call *call,
+ grpc_transport_stream_op *op) {
+ grpc_call_element *elem;
+
+ GPR_TIMER_BEGIN("execute_op", 0);
+ elem = CALL_ELEM_FROM_CALL(call, 0);
+ op->context = call->context;
+ elem->filter->start_transport_stream_op(exec_ctx, elem, op);
+ GPR_TIMER_END("execute_op", 0);
+}
+
+char *grpc_call_get_peer(grpc_call *call) {
+ grpc_call_element *elem = CALL_ELEM_FROM_CALL(call, 0);
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ char *result;
+ GRPC_API_TRACE("grpc_call_get_peer(%p)", 1, (call));
+ result = elem->filter->get_peer(&exec_ctx, elem);
+ if (result == NULL) {
+ result = grpc_channel_get_target(call->channel);
+ }
+ if (result == NULL) {
+ result = gpr_strdup("unknown");
+ }
+ grpc_exec_ctx_finish(&exec_ctx);
+ return result;
+}
+
+grpc_call *grpc_call_from_top_element(grpc_call_element *elem) {
+ return CALL_FROM_TOP_ELEM(elem);
+}
+
/* we offset status by a small amount when storing it into transport metadata
as metadata cannot store a 0 value (which is used as OK for grpc_status_codes
*/
#define STATUS_OFFSET 1
static void destroy_status(void *ignored) {}
-static uint32_t decode_status(grpc_mdelem md) {
+static uint32_t decode_status(grpc_mdelem *md) {
uint32_t status;
void *user_data;
- if (grpc_mdelem_eq(md, GRPC_MDELEM_GRPC_STATUS_0)) return 0;
- if (grpc_mdelem_eq(md, GRPC_MDELEM_GRPC_STATUS_1)) return 1;
- if (grpc_mdelem_eq(md, GRPC_MDELEM_GRPC_STATUS_2)) return 2;
+ if (md == GRPC_MDELEM_GRPC_STATUS_0) return 0;
+ if (md == GRPC_MDELEM_GRPC_STATUS_1) return 1;
+ if (md == GRPC_MDELEM_GRPC_STATUS_2) return 2;
user_data = grpc_mdelem_get_user_data(md, destroy_status);
if (user_data != NULL) {
status = ((uint32_t)(intptr_t)user_data) - STATUS_OFFSET;
} else {
- if (!grpc_parse_slice_to_uint32(GRPC_MDVALUE(md), &status)) {
+ if (!gpr_parse_bytes_to_uint32(grpc_mdstr_as_c_string(md->value),
+ GRPC_SLICE_LENGTH(md->value->slice),
+ &status)) {
status = GRPC_STATUS_UNKNOWN; /* could not parse status code */
}
grpc_mdelem_set_user_data(md, destroy_status,
@@ -836,104 +916,93 @@ static uint32_t decode_status(grpc_mdelem md) {
return status;
}
-static grpc_compression_algorithm decode_compression(grpc_mdelem md) {
+static grpc_compression_algorithm decode_compression(grpc_mdelem *md) {
grpc_compression_algorithm algorithm =
- grpc_compression_algorithm_from_slice(GRPC_MDVALUE(md));
+ grpc_compression_algorithm_from_mdstr(md->value);
if (algorithm == GRPC_COMPRESS_ALGORITHMS_COUNT) {
- char *md_c_str = grpc_slice_to_c_string(GRPC_MDVALUE(md));
+ const char *md_c_str = grpc_mdstr_as_c_string(md->value);
gpr_log(GPR_ERROR,
"Invalid incoming compression algorithm: '%s'. Interpreting "
"incoming data as uncompressed.",
md_c_str);
- gpr_free(md_c_str);
return GRPC_COMPRESS_NONE;
}
return algorithm;
}
-static void recv_common_filter(grpc_exec_ctx *exec_ctx, grpc_call *call,
- grpc_metadata_batch *b) {
- if (b->idx.named.grpc_status != NULL) {
- uint32_t status_code = decode_status(b->idx.named.grpc_status->md);
- grpc_error *error =
- status_code == GRPC_STATUS_OK
- ? GRPC_ERROR_NONE
- : grpc_error_set_int(GRPC_ERROR_CREATE("Error received from peer"),
- GRPC_ERROR_INT_GRPC_STATUS,
- (intptr_t)status_code);
-
- if (b->idx.named.grpc_message != NULL) {
- char *msg =
- grpc_slice_to_c_string(GRPC_MDVALUE(b->idx.named.grpc_message->md));
- error = grpc_error_set_str(error, GRPC_ERROR_STR_GRPC_MESSAGE, msg);
- gpr_free(msg);
- grpc_metadata_batch_remove(exec_ctx, b, b->idx.named.grpc_message);
- } else {
- error = grpc_error_set_str(error, GRPC_ERROR_STR_GRPC_MESSAGE, "");
- }
-
- set_status_from_error(exec_ctx, call, STATUS_FROM_WIRE, error);
- grpc_metadata_batch_remove(exec_ctx, b, b->idx.named.grpc_status);
- }
+static grpc_mdelem *recv_common_filter(grpc_exec_ctx *exec_ctx, grpc_call *call,
+ grpc_mdelem *elem) {
+ if (elem->key == GRPC_MDSTR_GRPC_STATUS) {
+ GPR_TIMER_BEGIN("status", 0);
+ set_status_code(call, STATUS_FROM_WIRE, decode_status(elem));
+ GPR_TIMER_END("status", 0);
+ return NULL;
+ } else if (elem->key == GRPC_MDSTR_GRPC_MESSAGE) {
+ GPR_TIMER_BEGIN("status-details", 0);
+ set_status_details(exec_ctx, call, STATUS_FROM_WIRE,
+ GRPC_MDSTR_REF(elem->value));
+ GPR_TIMER_END("status-details", 0);
+ return NULL;
+ }
+ return elem;
}
-static void publish_app_metadata(grpc_call *call, grpc_metadata_batch *b,
- int is_trailing) {
- if (b->list.count == 0) return;
- GPR_TIMER_BEGIN("publish_app_metadata", 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 + b->list.count > dest->capacity) {
- dest->capacity =
- GPR_MAX(dest->capacity + b->list.count, dest->capacity * 3 / 2);
+ 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);
}
- for (grpc_linked_mdelem *l = b->list.head; l != NULL; l = l->next) {
- mdusr = &dest->metadata[dest->count++];
- /* we pass back borrowed slices that are valid whilst the call is valid */
- mdusr->key = GRPC_MDKEY(l->md);
- mdusr->value = GRPC_MDVALUE(l->md);
- }
+ 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 = GRPC_SLICE_LENGTH(elem->value->slice);
GPR_TIMER_END("publish_app_metadata", 0);
+ return elem;
}
-static void recv_initial_filter(grpc_exec_ctx *exec_ctx, grpc_call *call,
- grpc_metadata_batch *b) {
- recv_common_filter(exec_ctx, call, b);
-
- if (b->idx.named.grpc_encoding != NULL) {
+static grpc_mdelem *recv_initial_filter(grpc_exec_ctx *exec_ctx, void *args,
+ grpc_mdelem *elem) {
+ grpc_call *call = args;
+ elem = recv_common_filter(exec_ctx, call, elem);
+ if (elem == NULL) {
+ return NULL;
+ } else if (elem->key == GRPC_MDSTR_GRPC_ENCODING) {
GPR_TIMER_BEGIN("incoming_compression_algorithm", 0);
- set_incoming_compression_algorithm(
- call, decode_compression(b->idx.named.grpc_encoding->md));
+ set_incoming_compression_algorithm(call, decode_compression(elem));
GPR_TIMER_END("incoming_compression_algorithm", 0);
- grpc_metadata_batch_remove(exec_ctx, b, b->idx.named.grpc_encoding);
- }
-
- if (b->idx.named.grpc_accept_encoding != NULL) {
+ return NULL;
+ } else if (elem->key == GRPC_MDSTR_GRPC_ACCEPT_ENCODING) {
GPR_TIMER_BEGIN("encodings_accepted_by_peer", 0);
- set_encodings_accepted_by_peer(exec_ctx, call,
- b->idx.named.grpc_accept_encoding->md);
- grpc_metadata_batch_remove(exec_ctx, b, b->idx.named.grpc_accept_encoding);
+ set_encodings_accepted_by_peer(exec_ctx, call, elem);
GPR_TIMER_END("encodings_accepted_by_peer", 0);
+ return NULL;
+ } else {
+ return publish_app_metadata(call, elem, 0);
}
-
- publish_app_metadata(call, b, false);
}
-static void recv_trailing_filter(grpc_exec_ctx *exec_ctx, void *args,
- grpc_metadata_batch *b) {
+static grpc_mdelem *recv_trailing_filter(grpc_exec_ctx *exec_ctx, void *args,
+ grpc_mdelem *elem) {
grpc_call *call = args;
- recv_common_filter(exec_ctx, call, b);
- publish_app_metadata(call, b, true);
+ elem = recv_common_filter(exec_ctx, call, elem);
+ if (elem == NULL) {
+ return NULL;
+ } else {
+ return publish_app_metadata(call, elem, 1);
+ }
}
grpc_call_stack *grpc_call_get_call_stack(grpc_call *call) {
return CALL_STACK_FROM_CALL(call);
}
-/*******************************************************************************
+/*
* BATCH API IMPLEMENTATION
*/
@@ -984,83 +1053,14 @@ static void finish_batch_completion(grpc_exec_ctx *exec_ctx, void *user_data,
GRPC_CALL_INTERNAL_UNREF(exec_ctx, call, "completion");
}
-static grpc_error *consolidate_batch_errors(batch_control *bctl) {
- size_t n = (size_t)gpr_atm_no_barrier_load(&bctl->num_errors);
- if (n == 0) {
- return GRPC_ERROR_NONE;
- } else if (n == 1) {
- return bctl->errors[0];
- } else {
- grpc_error *error =
- GRPC_ERROR_CREATE_REFERENCING("Call batch failed", bctl->errors, n);
- for (size_t i = 0; i < n; i++) {
- GRPC_ERROR_UNREF(bctl->errors[i]);
- }
- return error;
- }
-}
-
static void post_batch_completion(grpc_exec_ctx *exec_ctx,
batch_control *bctl) {
- grpc_call *child_call;
- grpc_call *next_child_call;
grpc_call *call = bctl->call;
- grpc_error *error = consolidate_batch_errors(bctl);
-
- gpr_mu_lock(&call->mu);
-
- if (error != GRPC_ERROR_NONE) {
- set_status_from_error(exec_ctx, call, STATUS_FROM_CORE,
- GRPC_ERROR_REF(error));
- }
-
- if (bctl->send_initial_metadata) {
- grpc_metadata_batch_destroy(
- exec_ctx,
- &call->metadata_batch[0 /* is_receiving */][0 /* is_trailing */]);
- }
- if (bctl->send_message) {
- call->sending_message = false;
- }
- if (bctl->send_final_op) {
- grpc_metadata_batch_destroy(
- exec_ctx,
- &call->metadata_batch[0 /* is_receiving */][1 /* is_trailing */]);
- }
+ grpc_error *error = bctl->error;
if (bctl->recv_final_op) {
- grpc_metadata_batch *md =
- &call->metadata_batch[1 /* is_receiving */][1 /* is_trailing */];
- recv_trailing_filter(exec_ctx, call, md);
-
- call->received_final_op = true;
- /* propagate cancellation to any interested children */
- child_call = call->first_child;
- if (child_call != NULL) {
- do {
- next_child_call = child_call->sibling_next;
- if (child_call->cancellation_is_inherited) {
- GRPC_CALL_INTERNAL_REF(child_call, "propagate_cancel");
- grpc_call_cancel(child_call, NULL);
- GRPC_CALL_INTERNAL_UNREF(exec_ctx, child_call, "propagate_cancel");
- }
- child_call = next_child_call;
- } while (child_call != call->first_child);
- }
-
- if (call->is_client) {
- get_final_status(call, set_status_value_directly,
- call->final_op.client.status,
- call->final_op.client.status_details);
- } else {
- get_final_status(call, set_cancelled_value,
- call->final_op.server.cancelled, NULL);
- }
-
GRPC_ERROR_UNREF(error);
error = GRPC_ERROR_NONE;
}
- gpr_mu_unlock(&call->mu);
-
if (bctl->is_notify_tag_closure) {
/* unrefs bctl->error */
grpc_closure_run(exec_ctx, bctl->notify_tag, error);
@@ -1077,12 +1077,6 @@ static void post_batch_completion(grpc_exec_ctx *exec_ctx,
}
}
-static void finish_batch_step(grpc_exec_ctx *exec_ctx, batch_control *bctl) {
- if (gpr_unref(&bctl->steps_to_complete)) {
- post_batch_completion(exec_ctx, bctl);
- }
-}
-
static void continue_receiving_slices(grpc_exec_ctx *exec_ctx,
batch_control *bctl) {
grpc_call *call = bctl->call;
@@ -1093,7 +1087,9 @@ static void continue_receiving_slices(grpc_exec_ctx *exec_ctx,
call->receiving_message = 0;
grpc_byte_stream_destroy(exec_ctx, call->receiving_stream);
call->receiving_stream = NULL;
- finish_batch_step(exec_ctx, bctl);
+ if (gpr_unref(&bctl->steps_to_complete)) {
+ post_batch_completion(exec_ctx, bctl);
+ }
return;
}
if (grpc_byte_stream_next(exec_ctx, call->receiving_stream,
@@ -1124,7 +1120,9 @@ static void receiving_slice_ready(grpc_exec_ctx *exec_ctx, void *bctlp,
call->receiving_stream = NULL;
grpc_byte_buffer_destroy(*call->receiving_buffer);
*call->receiving_buffer = NULL;
- finish_batch_step(exec_ctx, bctl);
+ if (gpr_unref(&bctl->steps_to_complete)) {
+ post_batch_completion(exec_ctx, bctl);
+ }
}
}
@@ -1134,7 +1132,9 @@ static void process_data_after_md(grpc_exec_ctx *exec_ctx,
if (call->receiving_stream == NULL) {
*call->receiving_buffer = NULL;
call->receiving_message = 0;
- finish_batch_step(exec_ctx, bctl);
+ if (gpr_unref(&bctl->steps_to_complete)) {
+ post_batch_completion(exec_ctx, bctl);
+ }
} else {
call->test_only_last_message_flags = call->receiving_stream->flags;
if ((call->receiving_stream->flags & GRPC_WRITE_INTERNAL_COMPRESS) &&
@@ -1154,11 +1154,14 @@ static void receiving_stream_ready(grpc_exec_ctx *exec_ctx, void *bctlp,
grpc_error *error) {
batch_control *bctl = bctlp;
grpc_call *call = bctl->call;
- gpr_mu_lock(&bctl->call->mu);
if (error != GRPC_ERROR_NONE) {
- cancel_with_error(exec_ctx, call, GRPC_ERROR_REF(error));
+ grpc_status_code status;
+ const char *msg;
+ grpc_error_get_status(error, &status, &msg);
+ close_with_status(exec_ctx, call, status, msg);
}
- if (call->has_initial_md_been_received || error != GRPC_ERROR_NONE ||
+ gpr_mu_lock(&bctl->call->mu);
+ if (bctl->call->has_initial_md_been_received || error != GRPC_ERROR_NONE ||
call->receiving_stream == NULL) {
gpr_mu_unlock(&bctl->call->mu);
process_data_after_md(exec_ctx, bctlp);
@@ -1183,7 +1186,7 @@ static void validate_filtered_metadata(grpc_exec_ctx *exec_ctx,
gpr_asprintf(&error_msg, "Invalid compression algorithm value '%d'.",
algo);
gpr_log(GPR_ERROR, "%s", error_msg);
- cancel_with_status(exec_ctx, call, GRPC_STATUS_UNIMPLEMENTED, error_msg);
+ close_with_status(exec_ctx, call, GRPC_STATUS_UNIMPLEMENTED, error_msg);
} else if (grpc_compression_options_is_algorithm_enabled(
&compression_options, algo) == 0) {
/* check if algorithm is supported by current channel config */
@@ -1192,7 +1195,7 @@ static void validate_filtered_metadata(grpc_exec_ctx *exec_ctx,
gpr_asprintf(&error_msg, "Compression algorithm '%s' is disabled.",
algo_name);
gpr_log(GPR_ERROR, "%s", error_msg);
- cancel_with_status(exec_ctx, call, GRPC_STATUS_UNIMPLEMENTED, error_msg);
+ close_with_status(exec_ctx, call, GRPC_STATUS_UNIMPLEMENTED, error_msg);
} else {
call->incoming_compression_algorithm = algo;
}
@@ -1218,12 +1221,12 @@ static void validate_filtered_metadata(grpc_exec_ctx *exec_ctx,
}
}
-static void add_batch_error(grpc_exec_ctx *exec_ctx, batch_control *bctl,
- grpc_error *error) {
+static void add_batch_error(batch_control *bctl, grpc_error *error) {
if (error == GRPC_ERROR_NONE) return;
- cancel_with_error(exec_ctx, bctl->call, GRPC_ERROR_REF(error));
- int idx = (int)gpr_atm_no_barrier_fetch_add(&bctl->num_errors, 1);
- bctl->errors[idx] = error;
+ if (bctl->error == GRPC_ERROR_NONE) {
+ bctl->error = GRPC_ERROR_CREATE("Call batch operation failed");
+ }
+ bctl->error = grpc_error_add_child(bctl->error, error);
}
static void receiving_initial_metadata_ready(grpc_exec_ctx *exec_ctx,
@@ -1233,13 +1236,12 @@ static void receiving_initial_metadata_ready(grpc_exec_ctx *exec_ctx,
gpr_mu_lock(&call->mu);
- add_batch_error(exec_ctx, bctl, GRPC_ERROR_REF(error));
+ add_batch_error(bctl, GRPC_ERROR_REF(error));
if (error == GRPC_ERROR_NONE) {
grpc_metadata_batch *md =
&call->metadata_batch[1 /* is_receiving */][0 /* is_trailing */];
- recv_initial_filter(exec_ctx, call, md);
+ grpc_metadata_batch_filter(exec_ctx, md, recv_initial_filter, call);
- /* TODO(ctiller): this could be moved into recv_initial_filter now */
GPR_TIMER_BEGIN("validate_filtered_metadata", 0);
validate_filtered_metadata(exec_ctx, bctl);
GPR_TIMER_END("validate_filtered_metadata", 0);
@@ -1263,15 +1265,85 @@ static void receiving_initial_metadata_ready(grpc_exec_ctx *exec_ctx,
gpr_mu_unlock(&call->mu);
- finish_batch_step(exec_ctx, bctl);
+ if (gpr_unref(&bctl->steps_to_complete)) {
+ post_batch_completion(exec_ctx, bctl);
+ }
}
static void finish_batch(grpc_exec_ctx *exec_ctx, void *bctlp,
grpc_error *error) {
batch_control *bctl = bctlp;
+ grpc_call *call = bctl->call;
+ grpc_call *child_call;
+ grpc_call *next_child_call;
+
+ GRPC_ERROR_REF(error);
+
+ gpr_mu_lock(&call->mu);
+
+ // If the error has an associated status code, set the call's status.
+ intptr_t status;
+ if (error != GRPC_ERROR_NONE &&
+ grpc_error_get_int(error, GRPC_ERROR_INT_GRPC_STATUS, &status)) {
+ set_status_from_error(exec_ctx, call, STATUS_FROM_CORE, error);
+ }
+
+ if (bctl->send_initial_metadata) {
+ if (error != GRPC_ERROR_NONE) {
+ set_status_from_error(exec_ctx, call, STATUS_FROM_CORE, error);
+ }
+ grpc_metadata_batch_destroy(
+ exec_ctx,
+ &call->metadata_batch[0 /* is_receiving */][0 /* is_trailing */]);
+ }
+ if (bctl->send_message) {
+ call->sending_message = 0;
+ }
+ if (bctl->send_final_op) {
+ grpc_metadata_batch_destroy(
+ exec_ctx,
+ &call->metadata_batch[0 /* is_receiving */][1 /* is_trailing */]);
+ }
+ if (bctl->recv_final_op) {
+ grpc_metadata_batch *md =
+ &call->metadata_batch[1 /* is_receiving */][1 /* is_trailing */];
+ grpc_metadata_batch_filter(exec_ctx, md, recv_trailing_filter, call);
- add_batch_error(exec_ctx, bctl, GRPC_ERROR_REF(error));
- finish_batch_step(exec_ctx, bctl);
+ call->received_final_op = true;
+ /* propagate cancellation to any interested children */
+ child_call = call->first_child;
+ if (child_call != NULL) {
+ do {
+ next_child_call = child_call->sibling_next;
+ if (child_call->cancellation_is_inherited) {
+ GRPC_CALL_INTERNAL_REF(child_call, "propagate_cancel");
+ grpc_call_cancel(child_call, NULL);
+ GRPC_CALL_INTERNAL_UNREF(exec_ctx, child_call, "propagate_cancel");
+ }
+ child_call = next_child_call;
+ } while (child_call != call->first_child);
+ }
+
+ if (call->is_client) {
+ get_final_status(call, set_status_value_directly,
+ call->final_op.client.status);
+ get_final_details(call, call->final_op.client.status_details,
+ call->final_op.client.status_details_capacity);
+ } else {
+ get_final_status(call, set_cancelled_value,
+ call->final_op.server.cancelled);
+ }
+
+ GRPC_ERROR_UNREF(error);
+ error = GRPC_ERROR_NONE;
+ }
+ add_batch_error(bctl, GRPC_ERROR_REF(error));
+ gpr_mu_unlock(&call->mu);
+ if (gpr_unref(&bctl->steps_to_complete)) {
+ post_batch_completion(exec_ctx, bctl);
+ }
+
+ GRPC_ERROR_UNREF(error);
}
static grpc_call_error call_start_batch(grpc_exec_ctx *exec_ctx,
@@ -1305,6 +1377,7 @@ static grpc_call_error call_start_batch(grpc_exec_ctx *exec_ctx,
if (nops == 0) {
GRPC_CALL_INTERNAL_REF(call, "completion");
+ bctl->error = GRPC_ERROR_NONE;
if (!is_notify_tag_closure) {
grpc_cq_begin_op(call->cq, notify_tag);
}
@@ -1353,10 +1426,13 @@ static grpc_call_error call_start_batch(grpc_exec_ctx *exec_ctx,
const grpc_compression_algorithm calgo =
compression_algorithm_for_level_locked(
call, effective_compression_level);
+ char *calgo_name = NULL;
+ grpc_compression_algorithm_name(calgo, &calgo_name);
// the following will be picked up by the compress filter and used as
// the call's compression algorithm.
- compression_md.key = GRPC_MDSTR_GRPC_INTERNAL_ENCODING_REQUEST;
- compression_md.value = grpc_compression_algorithm_slice(calgo);
+ compression_md.key = GRPC_COMPRESSION_REQUEST_ALGORITHM_MD_KEY;
+ compression_md.value = calgo_name;
+ compression_md.value_length = strlen(calgo_name);
additional_metadata_count++;
}
@@ -1449,25 +1525,19 @@ static grpc_call_error call_start_batch(grpc_exec_ctx *exec_ctx,
call->send_extra_metadata_count = 1;
call->send_extra_metadata[0].md = grpc_channel_get_reffed_status_elem(
exec_ctx, call->channel, op->data.send_status_from_server.status);
- {
- grpc_error *override_error = GRPC_ERROR_NONE;
- if (op->data.send_status_from_server.status != GRPC_STATUS_OK) {
- override_error = GRPC_ERROR_CREATE("Error from server send status");
- }
- if (op->data.send_status_from_server.status_details != NULL) {
- call->send_extra_metadata[1].md = grpc_mdelem_from_slices(
- exec_ctx, GRPC_MDSTR_GRPC_MESSAGE,
- grpc_slice_ref_internal(
- *op->data.send_status_from_server.status_details));
- call->send_extra_metadata_count++;
- char *msg = grpc_slice_to_c_string(
- GRPC_MDVALUE(call->send_extra_metadata[1].md));
- override_error = grpc_error_set_str(
- override_error, GRPC_ERROR_STR_GRPC_MESSAGE, msg);
- gpr_free(msg);
- }
- set_status_from_error(exec_ctx, call, STATUS_FROM_API_OVERRIDE,
- override_error);
+ if (op->data.send_status_from_server.status_details != NULL) {
+ call->send_extra_metadata[1].md = grpc_mdelem_from_metadata_strings(
+ exec_ctx, GRPC_MDSTR_GRPC_MESSAGE,
+ grpc_mdstr_from_string(
+ op->data.send_status_from_server.status_details));
+ call->send_extra_metadata_count++;
+ set_status_details(
+ exec_ctx, call, STATUS_FROM_API_OVERRIDE,
+ GRPC_MDSTR_REF(call->send_extra_metadata[1].md->value));
+ }
+ if (op->data.send_status_from_server.status != GRPC_STATUS_OK) {
+ set_status_code(call, STATUS_FROM_API_OVERRIDE,
+ (uint32_t)op->data.send_status_from_server.status);
}
if (!prepare_application_metadata(
exec_ctx, call,
@@ -1545,6 +1615,8 @@ static grpc_call_error call_start_batch(grpc_exec_ctx *exec_ctx,
call->final_op.client.status = op->data.recv_status_on_client.status;
call->final_op.client.status_details =
op->data.recv_status_on_client.status_details;
+ call->final_op.client.status_details_capacity =
+ op->data.recv_status_on_client.status_details_capacity;
bctl->recv_final_op = 1;
stream_op->recv_trailing_metadata =
&call->metadata_batch[1 /* is_receiving */][1 /* is_trailing */];
diff --git a/src/core/lib/surface/call.h b/src/core/lib/surface/call.h
index 8c46a83d42..233340c329 100644
--- a/src/core/lib/surface/call.h
+++ b/src/core/lib/surface/call.h
@@ -61,7 +61,7 @@ typedef struct grpc_call_create_args {
const void *server_transport_data;
- grpc_mdelem *add_initial_metadata;
+ grpc_mdelem **add_initial_metadata;
size_t add_initial_metadata_count;
gpr_timespec send_deadline;
diff --git a/src/core/lib/surface/call_details.c b/src/core/lib/surface/call_details.c
index d0f88e1969..fe73da3f55 100644
--- a/src/core/lib/surface/call_details.c
+++ b/src/core/lib/surface/call_details.c
@@ -36,21 +36,15 @@
#include <string.h>
-#include "src/core/lib/iomgr/exec_ctx.h"
-#include "src/core/lib/slice/slice_internal.h"
#include "src/core/lib/surface/api_trace.h"
void grpc_call_details_init(grpc_call_details* cd) {
GRPC_API_TRACE("grpc_call_details_init(cd=%p)", 1, (cd));
memset(cd, 0, sizeof(*cd));
- cd->method = grpc_empty_slice();
- cd->host = grpc_empty_slice();
}
void grpc_call_details_destroy(grpc_call_details* cd) {
GRPC_API_TRACE("grpc_call_details_destroy(cd=%p)", 1, (cd));
- grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
- grpc_slice_unref_internal(&exec_ctx, cd->method);
- grpc_slice_unref_internal(&exec_ctx, cd->host);
- grpc_exec_ctx_finish(&exec_ctx);
+ gpr_free(cd->method);
+ gpr_free(cd->host);
}
diff --git a/src/core/lib/surface/call_log_batch.c b/src/core/lib/surface/call_log_batch.c
index 7fc58e19c2..31c074f15d 100644
--- a/src/core/lib/surface/call_log_batch.c
+++ b/src/core/lib/surface/call_log_batch.c
@@ -35,22 +35,17 @@
#include <grpc/support/alloc.h>
#include <grpc/support/string_util.h>
-#include "src/core/lib/slice/slice_string_helpers.h"
#include "src/core/lib/support/string.h"
static void add_metadata(gpr_strvec *b, const grpc_metadata *md, size_t count) {
size_t i;
- if (md == NULL) {
- gpr_strvec_add(b, gpr_strdup("(nil)"));
- return;
- }
for (i = 0; i < count; i++) {
gpr_strvec_add(b, gpr_strdup("\nkey="));
- gpr_strvec_add(b, grpc_slice_to_c_string(md[i].key));
+ gpr_strvec_add(b, gpr_strdup(md[i].key));
gpr_strvec_add(b, gpr_strdup(" value="));
- gpr_strvec_add(b,
- grpc_dump_slice(md[i].value, GPR_DUMP_HEX | GPR_DUMP_ASCII));
+ gpr_strvec_add(b, gpr_dump(md[i].value, md[i].value_length,
+ GPR_DUMP_HEX | GPR_DUMP_ASCII));
}
}
@@ -75,16 +70,10 @@ char *grpc_op_string(const grpc_op *op) {
gpr_strvec_add(&b, gpr_strdup("SEND_CLOSE_FROM_CLIENT"));
break;
case GRPC_OP_SEND_STATUS_FROM_SERVER:
- gpr_asprintf(&tmp, "SEND_STATUS_FROM_SERVER status=%d details=",
- op->data.send_status_from_server.status);
+ gpr_asprintf(&tmp, "SEND_STATUS_FROM_SERVER status=%d details=%s",
+ op->data.send_status_from_server.status,
+ op->data.send_status_from_server.status_details);
gpr_strvec_add(&b, tmp);
- if (op->data.send_status_from_server.status_details != NULL) {
- gpr_strvec_add(&b, grpc_dump_slice(
- *op->data.send_status_from_server.status_details,
- GPR_DUMP_ASCII));
- } else {
- gpr_strvec_add(&b, gpr_strdup("(null)"));
- }
add_metadata(&b, op->data.send_status_from_server.trailing_metadata,
op->data.send_status_from_server.trailing_metadata_count);
break;
diff --git a/src/core/lib/surface/channel.c b/src/core/lib/surface/channel.c
index 429dbad7c7..b87295786e 100644
--- a/src/core/lib/surface/channel.c
+++ b/src/core/lib/surface/channel.c
@@ -43,7 +43,6 @@
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/iomgr/iomgr.h"
-#include "src/core/lib/slice/slice_internal.h"
#include "src/core/lib/support/string.h"
#include "src/core/lib/surface/api_trace.h"
#include "src/core/lib/surface/call.h"
@@ -58,15 +57,15 @@
#define NUM_CACHED_STATUS_ELEMS 3
typedef struct registered_call {
- grpc_mdelem path;
- grpc_mdelem authority;
+ grpc_mdelem *path;
+ grpc_mdelem *authority;
struct registered_call *next;
} registered_call;
struct grpc_channel {
int is_client;
grpc_compression_options compression_options;
- grpc_mdelem default_authority;
+ grpc_mdelem *default_authority;
gpr_mu registered_call_mu;
registered_call *registered_calls;
@@ -103,8 +102,9 @@ grpc_channel *grpc_channel_create(grpc_exec_ctx *exec_ctx, const char *target,
exec_ctx, builder, sizeof(grpc_channel), 1, destroy_channel, NULL,
(void **)&channel);
if (error != GRPC_ERROR_NONE) {
- gpr_log(GPR_ERROR, "channel stack builder failed: %s",
- grpc_error_string(error));
+ const char *msg = grpc_error_string(error);
+ gpr_log(GPR_ERROR, "channel stack builder failed: %s", msg);
+ grpc_error_free_string(msg);
GRPC_ERROR_UNREF(error);
goto done;
}
@@ -116,19 +116,19 @@ grpc_channel *grpc_channel_create(grpc_exec_ctx *exec_ctx, const char *target,
channel->registered_calls = NULL;
grpc_compression_options_init(&channel->compression_options);
+
for (size_t i = 0; i < args->num_args; i++) {
if (0 == strcmp(args->args[i].key, GRPC_ARG_DEFAULT_AUTHORITY)) {
if (args->args[i].type != GRPC_ARG_STRING) {
gpr_log(GPR_ERROR, "%s ignored: it must be a string",
GRPC_ARG_DEFAULT_AUTHORITY);
} else {
- if (!GRPC_MDISNULL(channel->default_authority)) {
+ if (channel->default_authority) {
/* setting this takes precedence over anything else */
GRPC_MDELEM_UNREF(exec_ctx, channel->default_authority);
}
- channel->default_authority = grpc_mdelem_from_slices(
- exec_ctx, GRPC_MDSTR_AUTHORITY,
- grpc_slice_from_copied_string(args->args[i].value.string));
+ channel->default_authority = grpc_mdelem_from_strings(
+ exec_ctx, ":authority", args->args[i].value.string);
}
} else if (0 ==
strcmp(args->args[i].key, GRPC_SSL_TARGET_NAME_OVERRIDE_ARG)) {
@@ -136,15 +136,14 @@ grpc_channel *grpc_channel_create(grpc_exec_ctx *exec_ctx, const char *target,
gpr_log(GPR_ERROR, "%s ignored: it must be a string",
GRPC_SSL_TARGET_NAME_OVERRIDE_ARG);
} else {
- if (!GRPC_MDISNULL(channel->default_authority)) {
+ if (channel->default_authority) {
/* other ways of setting this (notably ssl) take precedence */
gpr_log(GPR_ERROR,
"%s ignored: default host already set some other way",
GRPC_SSL_TARGET_NAME_OVERRIDE_ARG);
} else {
- channel->default_authority = grpc_mdelem_from_slices(
- exec_ctx, GRPC_MDSTR_AUTHORITY,
- grpc_slice_from_copied_string(args->args[i].value.string));
+ channel->default_authority = grpc_mdelem_from_strings(
+ exec_ctx, ":authority", args->args[i].value.string);
}
}
} else if (0 == strcmp(args->args[i].key,
@@ -192,18 +191,18 @@ void grpc_channel_get_info(grpc_channel *channel,
static grpc_call *grpc_channel_create_call_internal(
grpc_exec_ctx *exec_ctx, grpc_channel *channel, grpc_call *parent_call,
uint32_t propagation_mask, grpc_completion_queue *cq,
- grpc_pollset_set *pollset_set_alternative, grpc_mdelem path_mdelem,
- grpc_mdelem authority_mdelem, gpr_timespec deadline) {
- grpc_mdelem send_metadata[2];
+ grpc_pollset_set *pollset_set_alternative, grpc_mdelem *path_mdelem,
+ grpc_mdelem *authority_mdelem, gpr_timespec deadline) {
+ grpc_mdelem *send_metadata[2];
size_t num_metadata = 0;
GPR_ASSERT(channel->is_client);
GPR_ASSERT(!(cq != NULL && pollset_set_alternative != NULL));
send_metadata[num_metadata++] = path_mdelem;
- if (!GRPC_MDISNULL(authority_mdelem)) {
+ if (authority_mdelem != NULL) {
send_metadata[num_metadata++] = authority_mdelem;
- } else if (!GRPC_MDISNULL(channel->default_authority)) {
+ } else if (channel->default_authority != NULL) {
send_metadata[num_metadata++] = GRPC_MDELEM_REF(channel->default_authority);
}
@@ -228,17 +227,27 @@ grpc_call *grpc_channel_create_call(grpc_channel *channel,
grpc_call *parent_call,
uint32_t propagation_mask,
grpc_completion_queue *cq,
- grpc_slice method, const grpc_slice *host,
+ const char *method, const char *host,
gpr_timespec deadline, void *reserved) {
+ GRPC_API_TRACE(
+ "grpc_channel_create_call("
+ "channel=%p, parent_call=%p, propagation_mask=%x, cq=%p, method=%s, "
+ "host=%s, "
+ "deadline=gpr_timespec { tv_sec: %" PRId64
+ ", tv_nsec: %d, clock_type: %d }, "
+ "reserved=%p)",
+ 10,
+ (channel, parent_call, (unsigned)propagation_mask, cq, method, host,
+ deadline.tv_sec, deadline.tv_nsec, (int)deadline.clock_type, reserved));
GPR_ASSERT(!reserved);
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
grpc_call *call = grpc_channel_create_call_internal(
&exec_ctx, channel, parent_call, propagation_mask, cq, NULL,
- grpc_mdelem_from_slices(&exec_ctx, GRPC_MDSTR_PATH,
- grpc_slice_ref_internal(method)),
- host != NULL ? grpc_mdelem_from_slices(&exec_ctx, GRPC_MDSTR_AUTHORITY,
- grpc_slice_ref_internal(*host))
- : GRPC_MDNULL,
+ grpc_mdelem_from_metadata_strings(&exec_ctx, GRPC_MDSTR_PATH,
+ grpc_mdstr_from_string(method)),
+ host ? grpc_mdelem_from_metadata_strings(&exec_ctx, GRPC_MDSTR_AUTHORITY,
+ grpc_mdstr_from_string(host))
+ : NULL,
deadline);
grpc_exec_ctx_finish(&exec_ctx);
return call;
@@ -246,16 +255,17 @@ grpc_call *grpc_channel_create_call(grpc_channel *channel,
grpc_call *grpc_channel_create_pollset_set_call(
grpc_exec_ctx *exec_ctx, grpc_channel *channel, grpc_call *parent_call,
- uint32_t propagation_mask, grpc_pollset_set *pollset_set, grpc_slice method,
- const grpc_slice *host, gpr_timespec deadline, void *reserved) {
+ uint32_t propagation_mask, grpc_pollset_set *pollset_set,
+ const char *method, const char *host, gpr_timespec deadline,
+ void *reserved) {
GPR_ASSERT(!reserved);
return grpc_channel_create_call_internal(
exec_ctx, channel, parent_call, propagation_mask, NULL, pollset_set,
- grpc_mdelem_from_slices(exec_ctx, GRPC_MDSTR_PATH,
- grpc_slice_ref_internal(method)),
- host != NULL ? grpc_mdelem_from_slices(exec_ctx, GRPC_MDSTR_AUTHORITY,
- grpc_slice_ref_internal(*host))
- : GRPC_MDNULL,
+ grpc_mdelem_from_metadata_strings(exec_ctx, GRPC_MDSTR_PATH,
+ grpc_mdstr_from_string(method)),
+ host ? grpc_mdelem_from_metadata_strings(exec_ctx, GRPC_MDSTR_AUTHORITY,
+ grpc_mdstr_from_string(host))
+ : NULL,
deadline);
}
@@ -267,15 +277,12 @@ void *grpc_channel_register_call(grpc_channel *channel, const char *method,
4, (channel, method, host, reserved));
GPR_ASSERT(!reserved);
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-
- rc->path = grpc_mdelem_from_slices(
- &exec_ctx, GRPC_MDSTR_PATH,
- grpc_slice_intern(grpc_slice_from_static_string(method)));
+ rc->path = grpc_mdelem_from_metadata_strings(&exec_ctx, GRPC_MDSTR_PATH,
+ grpc_mdstr_from_string(method));
rc->authority =
- host ? grpc_mdelem_from_slices(
- &exec_ctx, GRPC_MDSTR_AUTHORITY,
- grpc_slice_intern(grpc_slice_from_static_string(host)))
- : GRPC_MDNULL;
+ host ? grpc_mdelem_from_metadata_strings(&exec_ctx, GRPC_MDSTR_AUTHORITY,
+ grpc_mdstr_from_string(host))
+ : NULL;
gpr_mu_lock(&channel->registered_call_mu);
rc->next = channel->registered_calls;
channel->registered_calls = rc;
@@ -303,7 +310,8 @@ grpc_call *grpc_channel_create_registered_call(
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
grpc_call *call = grpc_channel_create_call_internal(
&exec_ctx, channel, parent_call, propagation_mask, completion_queue, NULL,
- GRPC_MDELEM_REF(rc->path), GRPC_MDELEM_REF(rc->authority), deadline);
+ GRPC_MDELEM_REF(rc->path),
+ rc->authority ? GRPC_MDELEM_REF(rc->authority) : NULL, deadline);
grpc_exec_ctx_finish(&exec_ctx);
return call;
}
@@ -332,10 +340,14 @@ static void destroy_channel(grpc_exec_ctx *exec_ctx, void *arg,
registered_call *rc = channel->registered_calls;
channel->registered_calls = rc->next;
GRPC_MDELEM_UNREF(exec_ctx, rc->path);
- GRPC_MDELEM_UNREF(exec_ctx, rc->authority);
+ if (rc->authority) {
+ GRPC_MDELEM_UNREF(exec_ctx, rc->authority);
+ }
gpr_free(rc);
}
- GRPC_MDELEM_UNREF(exec_ctx, channel->default_authority);
+ if (channel->default_authority != NULL) {
+ GRPC_MDELEM_UNREF(exec_ctx, channel->default_authority);
+ }
gpr_mu_destroy(&channel->registered_call_mu);
gpr_free(channel->target);
gpr_free(channel);
@@ -364,8 +376,8 @@ grpc_compression_options grpc_channel_compression_options(
return channel->compression_options;
}
-grpc_mdelem grpc_channel_get_reffed_status_elem(grpc_exec_ctx *exec_ctx,
- grpc_channel *channel, int i) {
+grpc_mdelem *grpc_channel_get_reffed_status_elem(grpc_exec_ctx *exec_ctx,
+ grpc_channel *channel, int i) {
char tmp[GPR_LTOA_MIN_BUFSIZE];
switch (i) {
case 0:
@@ -376,6 +388,6 @@ grpc_mdelem grpc_channel_get_reffed_status_elem(grpc_exec_ctx *exec_ctx,
return GRPC_MDELEM_GRPC_STATUS_2;
}
gpr_ltoa(i, tmp);
- return grpc_mdelem_from_slices(exec_ctx, GRPC_MDSTR_GRPC_STATUS,
- grpc_slice_from_copied_string(tmp));
+ return grpc_mdelem_from_metadata_strings(exec_ctx, GRPC_MDSTR_GRPC_STATUS,
+ grpc_mdstr_from_string(tmp));
}
diff --git a/src/core/lib/surface/channel.h b/src/core/lib/surface/channel.h
index 3a441d7add..2ebadb7a15 100644
--- a/src/core/lib/surface/channel.h
+++ b/src/core/lib/surface/channel.h
@@ -52,8 +52,9 @@ grpc_channel *grpc_channel_create(grpc_exec_ctx *exec_ctx, const char *target,
value of \a propagation_mask (see propagation_bits.h for possible values) */
grpc_call *grpc_channel_create_pollset_set_call(
grpc_exec_ctx *exec_ctx, grpc_channel *channel, grpc_call *parent_call,
- uint32_t propagation_mask, grpc_pollset_set *pollset_set, grpc_slice method,
- const grpc_slice *host, gpr_timespec deadline, void *reserved);
+ uint32_t propagation_mask, grpc_pollset_set *pollset_set,
+ const char *method, const char *host, gpr_timespec deadline,
+ void *reserved);
/** Get a (borrowed) pointer to this channels underlying channel stack */
grpc_channel_stack *grpc_channel_get_channel_stack(grpc_channel *channel);
@@ -62,9 +63,9 @@ grpc_channel_stack *grpc_channel_get_channel_stack(grpc_channel *channel);
status_code.
The returned elem is owned by the caller. */
-grpc_mdelem grpc_channel_get_reffed_status_elem(grpc_exec_ctx *exec_ctx,
- grpc_channel *channel,
- int status_code);
+grpc_mdelem *grpc_channel_get_reffed_status_elem(grpc_exec_ctx *exec_ctx,
+ grpc_channel *channel,
+ int status_code);
#ifdef GRPC_STREAM_REFCOUNT_DEBUG
void grpc_channel_internal_ref(grpc_channel *channel, const char *reason);
diff --git a/src/core/lib/surface/completion_queue.c b/src/core/lib/surface/completion_queue.c
index 1830842d00..4613c9021e 100644
--- a/src/core/lib/surface/completion_queue.c
+++ b/src/core/lib/surface/completion_queue.c
@@ -253,6 +253,7 @@ void grpc_cq_end_op(grpc_exec_ctx *exec_ctx, grpc_completion_queue *cc,
if (grpc_trace_operation_failures && error != GRPC_ERROR_NONE) {
gpr_log(GPR_ERROR, "Operation failed: tag=%p, error=%s", tag, errmsg);
}
+ grpc_error_free_string(errmsg);
}
storage->tag = tag;
@@ -293,7 +294,7 @@ void grpc_cq_end_op(grpc_exec_ctx *exec_ctx, grpc_completion_queue *cc,
if (kick_error != GRPC_ERROR_NONE) {
const char *msg = grpc_error_string(kick_error);
gpr_log(GPR_ERROR, "Kick failed: %s", msg);
-
+ grpc_error_free_string(msg);
GRPC_ERROR_UNREF(kick_error);
}
} else {
@@ -402,8 +403,8 @@ grpc_event grpc_completion_queue_next(grpc_completion_queue *cc,
.stolen_completion = NULL,
.tag = NULL,
.first_loop = true};
- grpc_exec_ctx exec_ctx =
- GRPC_EXEC_CTX_INITIALIZER(0, cq_is_next_finished, &is_finished_arg);
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT_WITH_FINISH_CHECK(
+ cq_is_next_finished, &is_finished_arg);
for (;;) {
if (is_finished_arg.stolen_completion != NULL) {
gpr_mu_unlock(cc->mu);
@@ -460,7 +461,7 @@ grpc_event grpc_completion_queue_next(grpc_completion_queue *cc,
gpr_mu_unlock(cc->mu);
const char *msg = grpc_error_string(err);
gpr_log(GPR_ERROR, "Completion queue next failed: %s", msg);
-
+ grpc_error_free_string(msg);
GRPC_ERROR_UNREF(err);
memset(&ret, 0, sizeof(ret));
ret.type = GRPC_QUEUE_TIMEOUT;
@@ -571,8 +572,8 @@ grpc_event grpc_completion_queue_pluck(grpc_completion_queue *cc, void *tag,
.stolen_completion = NULL,
.tag = tag,
.first_loop = true};
- grpc_exec_ctx exec_ctx =
- GRPC_EXEC_CTX_INITIALIZER(0, cq_is_pluck_finished, &is_finished_arg);
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT_WITH_FINISH_CHECK(
+ cq_is_pluck_finished, &is_finished_arg);
for (;;) {
if (is_finished_arg.stolen_completion != NULL) {
gpr_mu_unlock(cc->mu);
@@ -646,7 +647,7 @@ grpc_event grpc_completion_queue_pluck(grpc_completion_queue *cc, void *tag,
gpr_mu_unlock(cc->mu);
const char *msg = grpc_error_string(err);
gpr_log(GPR_ERROR, "Completion queue next failed: %s", msg);
-
+ grpc_error_free_string(msg);
GRPC_ERROR_UNREF(err);
memset(&ret, 0, sizeof(ret));
ret.type = GRPC_QUEUE_TIMEOUT;
diff --git a/src/core/lib/surface/init.c b/src/core/lib/surface/init.c
index cfa1882775..f61bf1582e 100644
--- a/src/core/lib/surface/init.c
+++ b/src/core/lib/surface/init.c
@@ -55,7 +55,6 @@
#include "src/core/lib/iomgr/iomgr.h"
#include "src/core/lib/iomgr/resource_quota.h"
#include "src/core/lib/profiling/timers.h"
-#include "src/core/lib/slice/slice_internal.h"
#include "src/core/lib/surface/api_trace.h"
#include "src/core/lib/surface/call.h"
#include "src/core/lib/surface/channel_init.h"
@@ -179,7 +178,6 @@ void grpc_init(void) {
gpr_mu_lock(&g_init_mu);
if (++g_initializations == 1) {
gpr_time_init();
- grpc_slice_intern_init();
grpc_mdctx_global_init();
grpc_channel_init_init();
grpc_register_tracer("api", &grpc_api_trace);
@@ -244,7 +242,6 @@ void grpc_shutdown(void) {
}
grpc_mdctx_global_shutdown(&exec_ctx);
grpc_handshaker_factory_registry_shutdown(&exec_ctx);
- grpc_slice_intern_shutdown();
}
gpr_mu_unlock(&g_init_mu);
grpc_exec_ctx_finish(&exec_ctx);
diff --git a/src/core/lib/surface/lame_client.c b/src/core/lib/surface/lame_client.c
index 48de0e1d5b..ae1eac09a9 100644
--- a/src/core/lib/surface/lame_client.c
+++ b/src/core/lib/surface/lame_client.c
@@ -44,12 +44,10 @@
#include "src/core/lib/surface/api_trace.h"
#include "src/core/lib/surface/call.h"
#include "src/core/lib/surface/channel.h"
-#include "src/core/lib/transport/static_metadata.h"
typedef struct {
grpc_linked_mdelem status;
grpc_linked_mdelem details;
- gpr_atm filled_metadata;
} call_data;
typedef struct {
@@ -60,23 +58,17 @@ typedef struct {
static void fill_metadata(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
grpc_metadata_batch *mdb) {
call_data *calld = elem->call_data;
- if (!gpr_atm_no_barrier_cas(&calld->filled_metadata, 0, 1)) {
- return;
- }
channel_data *chand = elem->channel_data;
char tmp[GPR_LTOA_MIN_BUFSIZE];
gpr_ltoa(chand->error_code, tmp);
- calld->status.md = grpc_mdelem_from_slices(
- exec_ctx, GRPC_MDSTR_GRPC_STATUS, grpc_slice_from_copied_string(tmp));
- calld->details.md = grpc_mdelem_from_slices(
- exec_ctx, GRPC_MDSTR_GRPC_MESSAGE,
- grpc_slice_from_copied_string(chand->error_message));
+ calld->status.md = grpc_mdelem_from_strings(exec_ctx, "grpc-status", tmp);
+ calld->details.md =
+ grpc_mdelem_from_strings(exec_ctx, "grpc-message", chand->error_message);
calld->status.prev = calld->details.next = NULL;
calld->status.next = &calld->details;
calld->details.prev = &calld->status;
mdb->list.head = &calld->status;
mdb->list.tail = &calld->details;
- mdb->list.count = 2;
mdb->deadline = gpr_inf_future(GPR_CLOCK_REALTIME);
}
@@ -123,8 +115,6 @@ static void lame_start_transport_op(grpc_exec_ctx *exec_ctx,
static grpc_error *init_call_elem(grpc_exec_ctx *exec_ctx,
grpc_call_element *elem,
grpc_call_element_args *args) {
- call_data *calld = elem->call_data;
- gpr_atm_no_barrier_store(&calld->filled_metadata, 0);
return GRPC_ERROR_NONE;
}
diff --git a/src/core/lib/surface/server.c b/src/core/lib/surface/server.c
index 3782b49122..addb7c4fbc 100644
--- a/src/core/lib/surface/server.c
+++ b/src/core/lib/surface/server.c
@@ -98,9 +98,8 @@ typedef struct requested_call {
typedef struct channel_registered_method {
registered_method *server_registered_method;
uint32_t flags;
- bool has_host;
- grpc_slice method;
- grpc_slice host;
+ grpc_mdstr *method;
+ grpc_mdstr *host;
} channel_registered_method;
struct channel_data {
@@ -145,10 +144,8 @@ struct call_data {
/** the current state of a call - see call_state */
call_state state;
- bool path_set;
- bool host_set;
- grpc_slice path;
- grpc_slice host;
+ grpc_mdstr *path;
+ grpc_mdstr *host;
gpr_timespec deadline;
grpc_completion_queue *cq_new;
@@ -280,20 +277,18 @@ static void shutdown_cleanup(grpc_exec_ctx *exec_ctx, void *arg,
}
static void send_shutdown(grpc_exec_ctx *exec_ctx, grpc_channel *channel,
- bool send_goaway, grpc_error *send_disconnect) {
+ int send_goaway, grpc_error *send_disconnect) {
struct shutdown_cleanup_args *sc = gpr_malloc(sizeof(*sc));
grpc_closure_init(&sc->closure, shutdown_cleanup, sc,
grpc_schedule_on_exec_ctx);
grpc_transport_op *op = grpc_make_transport_op(&sc->closure);
grpc_channel_element *elem;
- op->goaway_error =
- send_goaway
- ? grpc_error_set_int(GRPC_ERROR_CREATE("Server shutdown"),
- GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_OK)
- : GRPC_ERROR_NONE;
+ op->send_goaway = send_goaway;
op->set_accept_stream = true;
sc->slice = grpc_slice_from_copied_string("Server shutdown");
+ op->goaway_message = &sc->slice;
+ op->goaway_status = GRPC_STATUS_OK;
op->disconnect_with_error = send_disconnect;
elem = grpc_channel_stack_element(grpc_channel_get_channel_stack(channel), 0);
@@ -453,6 +448,7 @@ static void destroy_channel(grpc_exec_ctx *exec_ctx, channel_data *chand,
if (grpc_server_channel_trace && error != GRPC_ERROR_NONE) {
const char *msg = grpc_error_string(error);
gpr_log(GPR_INFO, "Disconnected client: %s", msg);
+ grpc_error_free_string(msg);
}
GRPC_ERROR_UNREF(error);
@@ -465,6 +461,17 @@ static void destroy_channel(grpc_exec_ctx *exec_ctx, channel_data *chand,
op);
}
+static void cpstr(char **dest, size_t *capacity, grpc_mdstr *value) {
+ grpc_slice slice = value->slice;
+ size_t len = GRPC_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);
+}
+
static void done_request_event(grpc_exec_ctx *exec_ctx, void *req,
grpc_cq_completion *c) {
requested_call *rc = req;
@@ -493,10 +500,12 @@ static void publish_call(grpc_exec_ctx *exec_ctx, grpc_server *server,
GPR_SWAP(grpc_metadata_array, *rc->initial_metadata, calld->initial_metadata);
switch (rc->type) {
case BATCH_CALL:
- GPR_ASSERT(calld->host_set);
- GPR_ASSERT(calld->path_set);
- rc->data.batch.details->host = grpc_slice_ref_internal(calld->host);
- rc->data.batch.details->method = grpc_slice_ref_internal(calld->path);
+ GPR_ASSERT(calld->host != NULL);
+ GPR_ASSERT(calld->path != NULL);
+ cpstr(&rc->data.batch.details->host,
+ &rc->data.batch.details->host_capacity, calld->host);
+ cpstr(&rc->data.batch.details->method,
+ &rc->data.batch.details->method_capacity, calld->path);
rc->data.batch.details->deadline = calld->deadline;
rc->data.batch.details->flags =
(calld->recv_idempotent_request
@@ -618,39 +627,35 @@ static void start_new_rpc(grpc_exec_ctx *exec_ctx, grpc_call_element *elem) {
uint32_t hash;
channel_registered_method *rm;
- if (chand->registered_methods && calld->path_set && calld->host_set) {
+ if (chand->registered_methods && calld->path && calld->host) {
/* TODO(ctiller): unify these two searches */
/* check for an exact match with host */
- hash = GRPC_MDSTR_KV_HASH(grpc_slice_hash(calld->host),
- grpc_slice_hash(calld->path));
+ hash = GRPC_MDSTR_KV_HASH(calld->host->hash, calld->path->hash);
for (i = 0; i <= chand->registered_method_max_probes; i++) {
rm = &chand->registered_methods[(hash + i) %
chand->registered_method_slots];
if (!rm) break;
- if (!rm->has_host) continue;
- if (!grpc_slice_eq(rm->host, calld->host)) continue;
- if (!grpc_slice_eq(rm->method, calld->path)) continue;
+ if (rm->host != calld->host) continue;
+ if (rm->method != calld->path) continue;
if ((rm->flags & GRPC_INITIAL_METADATA_IDEMPOTENT_REQUEST) &&
- !calld->recv_idempotent_request) {
+ !calld->recv_idempotent_request)
continue;
- }
finish_start_new_rpc(exec_ctx, server, elem,
&rm->server_registered_method->request_matcher,
rm->server_registered_method->payload_handling);
return;
}
/* check for a wildcard method definition (no host set) */
- hash = GRPC_MDSTR_KV_HASH(0, grpc_slice_hash(calld->path));
+ hash = GRPC_MDSTR_KV_HASH(0, calld->path->hash);
for (i = 0; i <= chand->registered_method_max_probes; i++) {
rm = &chand->registered_methods[(hash + i) %
chand->registered_method_slots];
if (!rm) break;
- if (rm->has_host) continue;
- if (!grpc_slice_eq(rm->method, calld->path)) continue;
+ if (rm->host != NULL) continue;
+ if (rm->method != calld->path) continue;
if ((rm->flags & GRPC_INITIAL_METADATA_IDEMPOTENT_REQUEST) &&
- !calld->recv_idempotent_request) {
+ !calld->recv_idempotent_request)
continue;
- }
finish_start_new_rpc(exec_ctx, server, elem,
&rm->server_registered_method->request_matcher,
rm->server_registered_method->payload_handling);
@@ -739,40 +744,43 @@ static void maybe_finish_shutdown(grpc_exec_ctx *exec_ctx,
}
}
+static grpc_mdelem *server_filter(grpc_exec_ctx *exec_ctx, void *user_data,
+ grpc_mdelem *md) {
+ grpc_call_element *elem = user_data;
+ call_data *calld = elem->call_data;
+ if (md->key == GRPC_MDSTR_PATH) {
+ if (calld->path == NULL) {
+ calld->path = GRPC_MDSTR_REF(md->value);
+ }
+ return NULL;
+ } else if (md->key == GRPC_MDSTR_AUTHORITY) {
+ if (calld->host == NULL) {
+ calld->host = GRPC_MDSTR_REF(md->value);
+ }
+ return NULL;
+ }
+ return md;
+}
+
static void server_on_recv_initial_metadata(grpc_exec_ctx *exec_ctx, void *ptr,
grpc_error *error) {
grpc_call_element *elem = ptr;
call_data *calld = elem->call_data;
gpr_timespec op_deadline;
- if (error == GRPC_ERROR_NONE) {
- GPR_ASSERT(calld->recv_initial_metadata->idx.named.path != NULL);
- GPR_ASSERT(calld->recv_initial_metadata->idx.named.authority != NULL);
- calld->path = grpc_slice_ref_internal(
- GRPC_MDVALUE(calld->recv_initial_metadata->idx.named.path->md));
- calld->host = grpc_slice_ref_internal(
- GRPC_MDVALUE(calld->recv_initial_metadata->idx.named.authority->md));
- calld->path_set = true;
- calld->host_set = true;
- grpc_metadata_batch_remove(exec_ctx, calld->recv_initial_metadata,
- calld->recv_initial_metadata->idx.named.path);
- grpc_metadata_batch_remove(
- exec_ctx, calld->recv_initial_metadata,
- calld->recv_initial_metadata->idx.named.authority);
- } else {
- GRPC_ERROR_REF(error);
- }
+ GRPC_ERROR_REF(error);
+ grpc_metadata_batch_filter(exec_ctx, calld->recv_initial_metadata,
+ server_filter, elem);
op_deadline = calld->recv_initial_metadata->deadline;
if (0 != gpr_time_cmp(op_deadline, gpr_inf_future(op_deadline.clock_type))) {
calld->deadline = op_deadline;
}
- if (calld->host_set && calld->path_set) {
+ if (calld->host && calld->path) {
/* do nothing */
} else {
- grpc_error *src_error = error;
+ GRPC_ERROR_UNREF(error);
error =
GRPC_ERROR_CREATE_REFERENCING("Missing :authority or :path", &error, 1);
- GRPC_ERROR_UNREF(src_error);
}
grpc_closure_run(exec_ctx, calld->on_done_recv_initial_metadata, error);
@@ -902,11 +910,11 @@ static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
GPR_ASSERT(calld->state != PENDING);
- if (calld->host_set) {
- grpc_slice_unref_internal(exec_ctx, calld->host);
+ if (calld->host) {
+ GRPC_MDSTR_UNREF(exec_ctx, calld->host);
}
- if (calld->path_set) {
- grpc_slice_unref_internal(exec_ctx, calld->path);
+ if (calld->path) {
+ GRPC_MDSTR_UNREF(exec_ctx, calld->path);
}
grpc_metadata_array_destroy(&calld->initial_metadata);
@@ -938,9 +946,11 @@ static void destroy_channel_elem(grpc_exec_ctx *exec_ctx,
channel_data *chand = elem->channel_data;
if (chand->registered_methods) {
for (i = 0; i < chand->registered_method_slots; i++) {
- grpc_slice_unref_internal(exec_ctx, chand->registered_methods[i].method);
- if (chand->registered_methods[i].has_host) {
- grpc_slice_unref_internal(exec_ctx, chand->registered_methods[i].host);
+ if (chand->registered_methods[i].method) {
+ GRPC_MDSTR_UNREF(exec_ctx, chand->registered_methods[i].method);
+ }
+ if (chand->registered_methods[i].host) {
+ GRPC_MDSTR_UNREF(exec_ctx, chand->registered_methods[i].host);
}
}
gpr_free(chand->registered_methods);
@@ -1138,6 +1148,8 @@ void grpc_server_setup_transport(grpc_exec_ctx *exec_ctx, grpc_server *s,
channel_registered_method *crm;
grpc_channel *channel;
channel_data *chand;
+ grpc_mdstr *host;
+ grpc_mdstr *method;
uint32_t hash;
size_t slots;
uint32_t probes;
@@ -1176,18 +1188,9 @@ void grpc_server_setup_transport(grpc_exec_ctx *exec_ctx, grpc_server *s,
chand->registered_methods = gpr_malloc(alloc);
memset(chand->registered_methods, 0, alloc);
for (rm = s->registered_methods; rm; rm = rm->next) {
- grpc_slice host;
- bool has_host;
- grpc_slice method;
- if (rm->host != NULL) {
- host = grpc_slice_intern(grpc_slice_from_static_string(rm->host));
- has_host = true;
- } else {
- has_host = false;
- }
- method = grpc_slice_intern(grpc_slice_from_static_string(rm->method));
- hash = GRPC_MDSTR_KV_HASH(has_host ? grpc_slice_hash(host) : 0,
- grpc_slice_hash(method));
+ host = rm->host ? grpc_mdstr_from_string(rm->host) : NULL;
+ method = grpc_mdstr_from_string(rm->method);
+ hash = GRPC_MDSTR_KV_HASH(host ? host->hash : 0, method->hash);
for (probes = 0; chand->registered_methods[(hash + probes) % slots]
.server_registered_method != NULL;
probes++)
@@ -1196,7 +1199,6 @@ void grpc_server_setup_transport(grpc_exec_ctx *exec_ctx, grpc_server *s,
crm = &chand->registered_methods[(hash + probes) % slots];
crm->server_registered_method = rm;
crm->flags = rm->flags;
- crm->has_host = has_host;
crm->host = host;
crm->method = method;
}
diff --git a/src/core/lib/surface/validate_metadata.c b/src/core/lib/surface/validate_metadata.c
index 7ec9137265..f49dd8584b 100644
--- a/src/core/lib/surface/validate_metadata.c
+++ b/src/core/lib/surface/validate_metadata.c
@@ -34,71 +34,40 @@
#include <stdlib.h>
#include <string.h>
-#include <grpc/grpc.h>
-#include <grpc/support/alloc.h>
#include <grpc/support/port_platform.h>
-#include "src/core/lib/iomgr/error.h"
-#include "src/core/lib/slice/slice_string_helpers.h"
-
-static grpc_error *conforms_to(grpc_slice slice, const uint8_t *legal_bits,
- const char *err_desc) {
- const uint8_t *p = GRPC_SLICE_START_PTR(slice);
- const uint8_t *e = GRPC_SLICE_END_PTR(slice);
+static int conforms_to(const char *s, size_t len, const uint8_t *legal_bits) {
+ const char *p = s;
+ const char *e = s + len;
for (; p != e; p++) {
- int idx = *p;
+ int idx = (uint8_t)*p;
int byte = idx / 8;
int bit = idx % 8;
- if ((legal_bits[byte] & (1 << bit)) == 0) {
- char *dump = grpc_dump_slice(slice, GPR_DUMP_HEX | GPR_DUMP_ASCII);
- grpc_error *error = grpc_error_set_str(
- grpc_error_set_int(GRPC_ERROR_CREATE(err_desc), GRPC_ERROR_INT_OFFSET,
- p - GRPC_SLICE_START_PTR(slice)),
- GRPC_ERROR_STR_RAW_BYTES, dump);
- gpr_free(dump);
- return error;
- }
+ if ((legal_bits[byte] & (1 << bit)) == 0) return 0;
}
- return GRPC_ERROR_NONE;
-}
-
-static int error2int(grpc_error *error) {
- int r = (error == GRPC_ERROR_NONE);
- GRPC_ERROR_UNREF(error);
- return r;
+ return 1;
}
-grpc_error *grpc_validate_header_key_is_legal(grpc_slice slice) {
+int grpc_header_key_is_legal(const char *key, size_t length) {
static const uint8_t legal_header_bits[256 / 8] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0xff, 0x03, 0x00, 0x00, 0x00,
0x80, 0xfe, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
- if (GRPC_SLICE_LENGTH(slice) == 0) {
- return GRPC_ERROR_CREATE("Metadata keys cannot be zero length");
- }
- if (GRPC_SLICE_START_PTR(slice)[0] == ':') {
- return GRPC_ERROR_CREATE("Metadata keys cannot start with :");
+ if (length == 0 || key[0] == ':') {
+ return 0;
}
- return conforms_to(slice, legal_header_bits, "Illegal header key");
+ return conforms_to(key, length, legal_header_bits);
}
-int grpc_header_key_is_legal(grpc_slice slice) {
- return error2int(grpc_validate_header_key_is_legal(slice));
-}
-
-grpc_error *grpc_validate_header_nonbin_value_is_legal(grpc_slice slice) {
+int grpc_header_nonbin_value_is_legal(const char *value, size_t length) {
static const uint8_t legal_header_bits[256 / 8] = {
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
- return conforms_to(slice, legal_header_bits, "Illegal header value");
-}
-
-int grpc_header_nonbin_value_is_legal(grpc_slice slice) {
- return error2int(grpc_validate_header_nonbin_value_is_legal(slice));
+ return conforms_to(value, length, legal_header_bits);
}
-int grpc_is_binary_header(grpc_slice slice) {
- if (GRPC_SLICE_LENGTH(slice) < 5) return 0;
- return 0 == memcmp(GRPC_SLICE_END_PTR(slice) - 4, "-bin", 4);
+int grpc_is_binary_header(const char *key, size_t length) {
+ if (length < 5) return 0;
+ return 0 == memcmp(key + length - 4, "-bin", 4);
}
diff --git a/src/core/lib/surface/validate_metadata.h b/src/core/lib/surface/validate_metadata.h
deleted file mode 100644
index 2b800d25a4..0000000000
--- a/src/core/lib/surface/validate_metadata.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- *
- * Copyright 2017, 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_CORE_LIB_SURFACE_VALIDATE_METADATA_H
-#define GRPC_CORE_LIB_SURFACE_VALIDATE_METADATA_H
-
-#include <grpc/slice.h>
-#include "src/core/lib/iomgr/error.h"
-
-grpc_error *grpc_validate_header_key_is_legal(grpc_slice slice);
-grpc_error *grpc_validate_header_nonbin_value_is_legal(grpc_slice slice);
-
-#endif /* GRPC_CORE_LIB_SURFACE_VALIDATE_METADATA_H */