aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core
diff options
context:
space:
mode:
Diffstat (limited to 'src/core')
-rw-r--r--src/core/ext/client_channel/client_channel.c122
-rw-r--r--src/core/ext/client_channel/lb_policy_registry.c8
-rw-r--r--src/core/ext/lb_policy/grpclb/grpclb.c43
-rw-r--r--src/core/ext/load_reporting/load_reporting_filter.c16
-rw-r--r--src/core/ext/transport/chttp2/transport/chttp2_transport.c4
-rw-r--r--src/core/ext/transport/chttp2/transport/hpack_encoder.c65
-rw-r--r--src/core/ext/transport/chttp2/transport/hpack_parser.c42
-rw-r--r--src/core/ext/transport/chttp2/transport/hpack_table.c20
-rw-r--r--src/core/ext/transport/chttp2/transport/parsing.c26
-rw-r--r--src/core/lib/channel/message_size_filter.c60
-rw-r--r--src/core/lib/json/json.c6
-rw-r--r--src/core/lib/json/json.h22
-rw-r--r--src/core/lib/security/transport/client_auth_filter.c8
-rw-r--r--src/core/lib/security/transport/server_auth_filter.c10
-rw-r--r--src/core/lib/slice/slice_hash_table.c44
-rw-r--r--src/core/lib/slice/slice_hash_table.h19
-rw-r--r--src/core/lib/support/string.c9
-rw-r--r--src/core/lib/support/string.h3
-rw-r--r--src/core/lib/transport/service_config.c254
-rw-r--r--src/core/lib/transport/service_config.h71
-rw-r--r--src/core/lib/transport/transport_op_string.c6
21 files changed, 606 insertions, 252 deletions
diff --git a/src/core/ext/client_channel/client_channel.c b/src/core/ext/client_channel/client_channel.c
index 5faad33a1d..8929e8c48a 100644
--- a/src/core/ext/client_channel/client_channel.c
+++ b/src/core/ext/client_channel/client_channel.c
@@ -57,7 +57,7 @@
#include "src/core/lib/transport/connectivity_state.h"
#include "src/core/lib/transport/metadata.h"
#include "src/core/lib/transport/metadata_batch.h"
-#include "src/core/lib/transport/method_config.h"
+#include "src/core/lib/transport/service_config.h"
#include "src/core/lib/transport/static_metadata.h"
/* Client channel implementation */
@@ -83,34 +83,65 @@ static void *method_parameters_copy(void *value) {
return new_value;
}
-static int method_parameters_cmp(void *value1, void *value2) {
- const method_parameters *v1 = value1;
- const method_parameters *v2 = value2;
- const int retval = gpr_time_cmp(v1->timeout, v2->timeout);
- if (retval != 0) return retval;
- if (v1->wait_for_ready > v2->wait_for_ready) return 1;
- if (v1->wait_for_ready < v2->wait_for_ready) return -1;
- return 0;
-}
-
-static void method_parameters_del(grpc_exec_ctx *exec_ctx, void *p) {
+static void method_parameters_free(grpc_exec_ctx *exec_ctx, void *p) {
gpr_free(p);
}
static const grpc_slice_hash_table_vtable method_parameters_vtable = {
- method_parameters_del, method_parameters_copy, method_parameters_cmp};
-
-static void *method_config_convert_value(
- const grpc_method_config *method_config) {
+ method_parameters_free, method_parameters_copy};
+
+static void *method_parameters_create_from_json(const grpc_json *json) {
+ wait_for_ready_value wait_for_ready = WAIT_FOR_READY_UNSET;
+ gpr_timespec timeout = {0, 0, GPR_TIMESPAN};
+ for (grpc_json *field = json->child; field != NULL; field = field->next) {
+ if (field->key == NULL) continue;
+ if (strcmp(field->key, "waitForReady") == 0) {
+ if (wait_for_ready != WAIT_FOR_READY_UNSET) return NULL; // Duplicate.
+ if (field->type != GRPC_JSON_TRUE && field->type != GRPC_JSON_FALSE) {
+ return NULL;
+ }
+ wait_for_ready = field->type == GRPC_JSON_TRUE ? WAIT_FOR_READY_TRUE
+ : WAIT_FOR_READY_FALSE;
+ } else if (strcmp(field->key, "timeout") == 0) {
+ if (timeout.tv_sec > 0 || timeout.tv_nsec > 0) return NULL; // Duplicate.
+ if (field->type != GRPC_JSON_STRING) return NULL;
+ size_t len = strlen(field->value);
+ if (field->value[len - 1] != 's') return NULL;
+ char *buf = gpr_strdup(field->value);
+ buf[len - 1] = '\0'; // Remove trailing 's'.
+ char *decimal_point = strchr(buf, '.');
+ if (decimal_point != NULL) {
+ *decimal_point = '\0';
+ timeout.tv_nsec = gpr_parse_nonnegative_int(decimal_point + 1);
+ if (timeout.tv_nsec == -1) {
+ gpr_free(buf);
+ return NULL;
+ }
+ // There should always be exactly 3, 6, or 9 fractional digits.
+ int multiplier = 1;
+ switch (strlen(decimal_point + 1)) {
+ case 9:
+ break;
+ case 6:
+ multiplier *= 1000;
+ break;
+ case 3:
+ multiplier *= 1000000;
+ break;
+ default: // Unsupported number of digits.
+ gpr_free(buf);
+ return NULL;
+ }
+ timeout.tv_nsec *= multiplier;
+ }
+ timeout.tv_sec = gpr_parse_nonnegative_int(buf);
+ if (timeout.tv_sec == -1) return NULL;
+ gpr_free(buf);
+ }
+ }
method_parameters *value = gpr_malloc(sizeof(method_parameters));
- const gpr_timespec *timeout = grpc_method_config_get_timeout(method_config);
- value->timeout = timeout != NULL ? *timeout : gpr_time_0(GPR_TIMESPAN);
- const bool *wait_for_ready =
- grpc_method_config_get_wait_for_ready(method_config);
- value->wait_for_ready =
- wait_for_ready == NULL
- ? WAIT_FOR_READY_UNSET
- : (wait_for_ready ? WAIT_FOR_READY_TRUE : WAIT_FOR_READY_FALSE);
+ value->timeout = timeout;
+ value->wait_for_ready = wait_for_ready;
return value;
}
@@ -131,6 +162,8 @@ typedef struct client_channel_channel_data {
/** currently active load balancer */
char *lb_policy_name;
grpc_lb_policy *lb_policy;
+ /** service config in JSON form */
+ char *service_config_json;
/** maps method names to method_parameters structs */
grpc_slice_hash_table *method_params_table;
/** incoming resolver result - set by resolver.next() */
@@ -237,15 +270,12 @@ static void on_resolver_result_changed(grpc_exec_ctx *exec_ctx, void *arg,
grpc_connectivity_state state = GRPC_CHANNEL_TRANSIENT_FAILURE;
bool exit_idle = false;
grpc_error *state_error = GRPC_ERROR_CREATE("No load balancing policy");
+ char *service_config_json = NULL;
if (chand->resolver_result != NULL) {
- grpc_lb_policy_args lb_policy_args;
- lb_policy_args.args = chand->resolver_result;
- lb_policy_args.client_channel_factory = chand->client_channel_factory;
-
// Find LB policy name.
const grpc_arg *channel_arg =
- grpc_channel_args_find(lb_policy_args.args, GRPC_ARG_LB_POLICY_NAME);
+ grpc_channel_args_find(chand->resolver_result, GRPC_ARG_LB_POLICY_NAME);
if (channel_arg != NULL) {
GPR_ASSERT(channel_arg->type == GRPC_ARG_STRING);
lb_policy_name = channel_arg->value.string;
@@ -254,7 +284,7 @@ static void on_resolver_result_changed(grpc_exec_ctx *exec_ctx, void *arg,
// assume that we should use the grpclb policy, regardless of what the
// resolver actually specified.
channel_arg =
- grpc_channel_args_find(lb_policy_args.args, GRPC_ARG_LB_ADDRESSES);
+ grpc_channel_args_find(chand->resolver_result, GRPC_ARG_LB_ADDRESSES);
if (channel_arg != NULL) {
GPR_ASSERT(channel_arg->type == GRPC_ARG_POINTER);
grpc_lb_addresses *addresses = channel_arg->value.pointer.p;
@@ -279,7 +309,10 @@ static void on_resolver_result_changed(grpc_exec_ctx *exec_ctx, void *arg,
// Use pick_first if nothing was specified and we didn't select grpclb
// above.
if (lb_policy_name == NULL) lb_policy_name = "pick_first";
-
+ // Instantiate LB policy.
+ grpc_lb_policy_args lb_policy_args;
+ lb_policy_args.args = chand->resolver_result;
+ lb_policy_args.client_channel_factory = chand->client_channel_factory;
lb_policy =
grpc_lb_policy_create(exec_ctx, lb_policy_name, &lb_policy_args);
if (lb_policy != NULL) {
@@ -288,13 +321,20 @@ static void on_resolver_result_changed(grpc_exec_ctx *exec_ctx, void *arg,
state =
grpc_lb_policy_check_connectivity(exec_ctx, lb_policy, &state_error);
}
+ // Find service config.
channel_arg =
- grpc_channel_args_find(lb_policy_args.args, GRPC_ARG_SERVICE_CONFIG);
+ grpc_channel_args_find(chand->resolver_result, GRPC_ARG_SERVICE_CONFIG);
if (channel_arg != NULL) {
- GPR_ASSERT(channel_arg->type == GRPC_ARG_POINTER);
- method_params_table = grpc_method_config_table_convert(
- exec_ctx, (grpc_method_config_table *)channel_arg->value.pointer.p,
- method_config_convert_value, &method_parameters_vtable);
+ GPR_ASSERT(channel_arg->type == GRPC_ARG_STRING);
+ service_config_json = gpr_strdup(channel_arg->value.string);
+ grpc_service_config *service_config =
+ grpc_service_config_create(service_config_json);
+ if (service_config != NULL) {
+ method_params_table = grpc_service_config_create_method_config_table(
+ exec_ctx, service_config, method_parameters_create_from_json,
+ &method_parameters_vtable);
+ grpc_service_config_destroy(service_config);
+ }
}
// Before we clean up, save a copy of lb_policy_name, since it might
// be pointing to data inside chand->resolver_result.
@@ -316,6 +356,10 @@ static void on_resolver_result_changed(grpc_exec_ctx *exec_ctx, void *arg,
}
old_lb_policy = chand->lb_policy;
chand->lb_policy = lb_policy;
+ if (service_config_json != NULL) {
+ gpr_free(chand->service_config_json);
+ chand->service_config_json = service_config_json;
+ }
if (chand->method_params_table != NULL) {
grpc_slice_hash_table_unref(exec_ctx, chand->method_params_table);
}
@@ -451,6 +495,11 @@ static void cc_get_channel_info(grpc_exec_ctx *exec_ctx,
? NULL
: gpr_strdup(chand->lb_policy_name);
}
+ if (info->service_config_json != NULL) {
+ *info->service_config_json = chand->service_config_json == NULL
+ ? NULL
+ : gpr_strdup(chand->service_config_json);
+ }
gpr_mu_unlock(&chand->mu);
}
@@ -494,6 +543,7 @@ static void cc_destroy_channel_elem(grpc_exec_ctx *exec_ctx,
GRPC_LB_POLICY_UNREF(exec_ctx, chand->lb_policy, "channel");
}
gpr_free(chand->lb_policy_name);
+ gpr_free(chand->service_config_json);
if (chand->method_params_table != NULL) {
grpc_slice_hash_table_unref(exec_ctx, chand->method_params_table);
}
diff --git a/src/core/ext/client_channel/lb_policy_registry.c b/src/core/ext/client_channel/lb_policy_registry.c
index f46a721f9d..90c149d947 100644
--- a/src/core/ext/client_channel/lb_policy_registry.c
+++ b/src/core/ext/client_channel/lb_policy_registry.c
@@ -35,6 +35,8 @@
#include <string.h>
+#include "src/core/lib/support/string.h"
+
#define MAX_POLICIES 10
static grpc_lb_policy_factory *g_all_of_the_lb_policies[MAX_POLICIES];
@@ -52,8 +54,8 @@ void grpc_lb_policy_registry_shutdown(void) {
void grpc_register_lb_policy(grpc_lb_policy_factory *factory) {
int i;
for (i = 0; i < g_number_of_lb_policies; i++) {
- GPR_ASSERT(0 != strcmp(factory->vtable->name,
- g_all_of_the_lb_policies[i]->vtable->name));
+ GPR_ASSERT(0 != gpr_stricmp(factory->vtable->name,
+ g_all_of_the_lb_policies[i]->vtable->name));
}
GPR_ASSERT(g_number_of_lb_policies != MAX_POLICIES);
grpc_lb_policy_factory_ref(factory);
@@ -66,7 +68,7 @@ static grpc_lb_policy_factory *lookup_factory(const char *name) {
if (name == NULL) return NULL;
for (i = 0; i < g_number_of_lb_policies; i++) {
- if (0 == strcmp(name, g_all_of_the_lb_policies[i]->vtable->name)) {
+ if (0 == gpr_stricmp(name, g_all_of_the_lb_policies[i]->vtable->name)) {
return g_all_of_the_lb_policies[i];
}
}
diff --git a/src/core/ext/lb_policy/grpclb/grpclb.c b/src/core/ext/lb_policy/grpclb/grpclb.c
index 7bc9804e63..b10b980331 100644
--- a/src/core/ext/lb_policy/grpclb/grpclb.c
+++ b/src/core/ext/lb_policy/grpclb/grpclb.c
@@ -137,7 +137,7 @@ static void initial_metadata_add_lb_token(
grpc_metadata_batch *initial_metadata,
grpc_linked_mdelem *lb_token_mdelem_storage, grpc_mdelem lb_token) {
GPR_ASSERT(lb_token_mdelem_storage != NULL);
- GPR_ASSERT(lb_token != NULL);
+ GPR_ASSERT(!GRPC_MDISNULL(lb_token));
grpc_metadata_batch_add_tail(initial_metadata, lb_token_mdelem_storage,
lb_token);
}
@@ -187,14 +187,20 @@ static void wrapped_rr_closure(grpc_exec_ctx *exec_ctx, void *arg,
* addresses failed to connect). There won't be any user_data/token
* available */
if (wc_arg->target != NULL) {
- GPR_ASSERT(wc_arg->lb_token != NULL);
- initial_metadata_add_lb_token(wc_arg->initial_metadata,
- wc_arg->lb_token_mdelem_storage,
- GRPC_MDELEM_REF(wc_arg->lb_token));
+ if (!GRPC_MDISNULL(wc_arg->lb_token)) {
+ initial_metadata_add_lb_token(wc_arg->initial_metadata,
+ wc_arg->lb_token_mdelem_storage,
+ GRPC_MDELEM_REF(wc_arg->lb_token));
+ } else {
+ gpr_log(GPR_ERROR,
+ "No LB token for connected subchannel pick %p (from RR "
+ "instance %p).",
+ (void *)*wc_arg->target, (void *)wc_arg->rr_policy);
+ abort();
+ }
}
if (grpc_lb_glb_trace) {
- gpr_log(GPR_INFO, "Unreffing RR (0x%" PRIxPTR ")",
- (intptr_t)wc_arg->rr_policy);
+ gpr_log(GPR_INFO, "Unreffing RR %p", (void *)wc_arg->rr_policy);
}
GRPC_LB_POLICY_UNREF(exec_ctx, wc_arg->rr_policy, "wrapped_rr_closure");
}
@@ -375,10 +381,10 @@ static bool is_server_valid(const grpc_grpclb_server *server, size_t idx,
/* vtable for LB tokens in grpc_lb_addresses. */
static void *lb_token_copy(void *token) {
- return token == NULL ? NULL : GRPC_MDELEM_REF(token);
+ return token == NULL ? NULL : GRPC_MDELEM_REF((grpc_mdelem){token}).payload;
}
static void lb_token_destroy(grpc_exec_ctx *exec_ctx, void *token) {
- if (token != NULL) GRPC_MDELEM_UNREF(exec_ctx, token);
+ if (token != NULL) GRPC_MDELEM_UNREF(exec_ctx, (grpc_mdelem){token});
}
static int lb_token_cmp(void *token1, void *token2) {
if (token1 > token2) return 1;
@@ -411,7 +417,7 @@ static void parse_server(const grpc_grpclb_server *server,
}
/* Returns addresses extracted from \a serverlist. */
-static grpc_lb_addresses *process_serverlist(
+static grpc_lb_addresses *process_serverlist_locked(
grpc_exec_ctx *exec_ctx, const grpc_grpclb_serverlist *serverlist) {
size_t num_valid = 0;
/* first pass: count how many are valid in order to allocate the necessary
@@ -448,14 +454,17 @@ static grpc_lb_addresses *process_serverlist(
strnlen(server->load_balance_token, lb_token_max_length);
grpc_slice lb_token_mdstr = grpc_slice_from_copied_buffer(
server->load_balance_token, lb_token_length);
- user_data = grpc_mdelem_from_slices(exec_ctx, GRPC_MDSTR_LB_TOKEN,
- lb_token_mdstr);
+ user_data =
+ grpc_mdelem_from_slices(exec_ctx, GRPC_MDSTR_LB_TOKEN, lb_token_mdstr)
+ .payload;
} else {
- gpr_log(GPR_ERROR,
+ char *uri = grpc_sockaddr_to_uri(&addr);
+ gpr_log(GPR_INFO,
"Missing LB token for backend address '%s'. The empty token will "
"be used instead",
- grpc_sockaddr_to_uri(&addr));
- user_data = GRPC_MDELEM_LB_TOKEN_EMPTY;
+ uri);
+ gpr_free(uri);
+ user_data = GRPC_MDELEM_LB_TOKEN_EMPTY.payload;
}
grpc_lb_addresses_set_address(lb_addresses, addr_idx, &addr.addr, addr.len,
@@ -508,7 +517,8 @@ static grpc_lb_policy *create_rr_locked(
grpc_lb_policy_args args;
memset(&args, 0, sizeof(args));
args.client_channel_factory = glb_policy->cc_factory;
- grpc_lb_addresses *addresses = process_serverlist(exec_ctx, serverlist);
+ grpc_lb_addresses *addresses =
+ process_serverlist_locked(exec_ctx, serverlist);
// Replace the LB addresses in the channel args that we pass down to
// the subchannel.
@@ -768,7 +778,6 @@ static void glb_shutdown(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) {
* while holding glb_policy->mu: lb_on_server_status_received, invoked due to
* the cancel, needs to acquire that same lock */
grpc_call *lb_call = glb_policy->lb_call;
- glb_policy->lb_call = NULL;
gpr_mu_unlock(&glb_policy->mu);
/* glb_policy->lb_call and this local lb_call must be consistent at this point
diff --git a/src/core/ext/load_reporting/load_reporting_filter.c b/src/core/ext/load_reporting/load_reporting_filter.c
index 1187810e26..5d3b4c4207 100644
--- a/src/core/ext/load_reporting/load_reporting_filter.c
+++ b/src/core/ext/load_reporting/load_reporting_filter.c
@@ -78,13 +78,13 @@ static grpc_mdelem recv_md_filter(grpc_exec_ctx *exec_ctx, void *user_data,
grpc_call_element *elem = a->elem;
call_data *calld = elem->call_data;
- if (grpc_slice_cmp(md->key, GRPC_MDSTR_PATH) == 0) {
- calld->service_method = grpc_slice_ref_internal(md->value);
+ if (grpc_slice_cmp(GRPC_MDKEY(md), GRPC_MDSTR_PATH) == 0) {
+ calld->service_method = grpc_slice_ref_internal(GRPC_MDVALUE(md));
calld->have_service_method = true;
- } else if (grpc_slice_cmp(md->key, GRPC_MDSTR_LB_TOKEN) == 0) {
- calld->initial_md_string = grpc_slice_ref_internal(md->value);
+ } else if (grpc_slice_cmp(GRPC_MDKEY(md), GRPC_MDSTR_LB_TOKEN) == 0) {
+ calld->initial_md_string = grpc_slice_ref_internal(GRPC_MDVALUE(md));
calld->have_initial_md_string = true;
- return NULL;
+ return GRPC_MDNULL;
}
return md;
@@ -201,10 +201,10 @@ static grpc_mdelem lr_trailing_md_filter(grpc_exec_ctx *exec_ctx,
grpc_call_element *elem = user_data;
call_data *calld = elem->call_data;
- if (grpc_slice_cmp(md->key, GRPC_MDSTR_LB_COST_BIN) == 0) {
- calld->trailing_md_string = grpc_slice_ref_internal(md->value);
+ if (grpc_slice_cmp(GRPC_MDKEY(md), GRPC_MDSTR_LB_COST_BIN) == 0) {
+ calld->trailing_md_string = grpc_slice_ref_internal(GRPC_MDVALUE(md));
calld->have_trailing_md_string = true;
- return NULL;
+ return GRPC_MDNULL;
}
return md;
diff --git a/src/core/ext/transport/chttp2/transport/chttp2_transport.c b/src/core/ext/transport/chttp2/transport/chttp2_transport.c
index fac9a08584..91861829e3 100644
--- a/src/core/ext/transport/chttp2/transport/chttp2_transport.c
+++ b/src/core/ext/transport/chttp2/transport/chttp2_transport.c
@@ -876,8 +876,8 @@ void grpc_chttp2_complete_closure_step(grpc_exec_ctx *exec_ctx,
static bool contains_non_ok_status(grpc_metadata_batch *batch) {
grpc_linked_mdelem *l;
for (l = batch->list.head; l; l = l->next) {
- if (grpc_slice_cmp(l->md->key, GRPC_MDSTR_GRPC_STATUS) == 0 &&
- l->md != GRPC_MDELEM_GRPC_STATUS_0) {
+ if (grpc_slice_cmp(GRPC_MDKEY(l->md), GRPC_MDSTR_GRPC_STATUS) == 0 &&
+ !grpc_mdelem_eq(l->md, GRPC_MDELEM_GRPC_STATUS_0)) {
return true;
}
}
diff --git a/src/core/ext/transport/chttp2/transport/hpack_encoder.c b/src/core/ext/transport/chttp2/transport/hpack_encoder.c
index 9a0173b7b7..8e2264a602 100644
--- a/src/core/ext/transport/chttp2/transport/hpack_encoder.c
+++ b/src/core/ext/transport/chttp2/transport/hpack_encoder.c
@@ -190,8 +190,8 @@ static void evict_entry(grpc_chttp2_hpack_compressor *c) {
/* add an element to the decoder table */
static void add_elem(grpc_exec_ctx *exec_ctx, grpc_chttp2_hpack_compressor *c,
grpc_mdelem elem) {
- uint32_t key_hash = grpc_slice_hash(elem->key);
- uint32_t value_hash = grpc_slice_hash(elem->value);
+ uint32_t key_hash = grpc_slice_hash(GRPC_MDKEY(elem));
+ uint32_t value_hash = grpc_slice_hash(GRPC_MDVALUE(elem));
uint32_t elem_hash = GRPC_MDSTR_KV_HASH(key_hash, value_hash);
uint32_t new_index = c->tail_remote_index + c->table_elems + 1;
size_t elem_size = grpc_mdelem_get_size_in_hpack_table(elem);
@@ -217,17 +217,18 @@ static void add_elem(grpc_exec_ctx *exec_ctx, grpc_chttp2_hpack_compressor *c,
c->table_elems++;
/* Store this element into {entries,indices}_elem */
- if (c->entries_elems[HASH_FRAGMENT_2(elem_hash)] == elem) {
+ if (grpc_mdelem_eq(c->entries_elems[HASH_FRAGMENT_2(elem_hash)], elem)) {
/* already there: update with new index */
c->indices_elems[HASH_FRAGMENT_2(elem_hash)] = new_index;
- } else if (c->entries_elems[HASH_FRAGMENT_3(elem_hash)] == elem) {
+ } else if (grpc_mdelem_eq(c->entries_elems[HASH_FRAGMENT_3(elem_hash)],
+ elem)) {
/* already there (cuckoo): update with new index */
c->indices_elems[HASH_FRAGMENT_3(elem_hash)] = new_index;
- } else if (c->entries_elems[HASH_FRAGMENT_2(elem_hash)] == NULL) {
+ } else if (GRPC_MDISNULL(c->entries_elems[HASH_FRAGMENT_2(elem_hash)])) {
/* not there, but a free element: add */
c->entries_elems[HASH_FRAGMENT_2(elem_hash)] = GRPC_MDELEM_REF(elem);
c->indices_elems[HASH_FRAGMENT_2(elem_hash)] = new_index;
- } else if (c->entries_elems[HASH_FRAGMENT_3(elem_hash)] == NULL) {
+ } else if (GRPC_MDISNULL(c->entries_elems[HASH_FRAGMENT_3(elem_hash)])) {
/* not there (cuckoo), but a free element: add */
c->entries_elems[HASH_FRAGMENT_3(elem_hash)] = GRPC_MDELEM_REF(elem);
c->indices_elems[HASH_FRAGMENT_3(elem_hash)] = new_index;
@@ -246,34 +247,34 @@ static void add_elem(grpc_exec_ctx *exec_ctx, grpc_chttp2_hpack_compressor *c,
/* do exactly the same for the key (so we can find by that again too) */
- if (grpc_slice_cmp(c->entries_keys[HASH_FRAGMENT_2(key_hash)], elem->key) ==
- 0) {
+ if (grpc_slice_cmp(c->entries_keys[HASH_FRAGMENT_2(key_hash)],
+ GRPC_MDKEY(elem)) == 0) {
c->indices_keys[HASH_FRAGMENT_2(key_hash)] = new_index;
} else if (grpc_slice_cmp(c->entries_keys[HASH_FRAGMENT_3(key_hash)],
- elem->key) == 0) {
+ GRPC_MDKEY(elem)) == 0) {
c->indices_keys[HASH_FRAGMENT_3(key_hash)] = new_index;
} else if (c->entries_keys[HASH_FRAGMENT_2(key_hash)].refcount ==
&terminal_slice_refcount) {
c->entries_keys[HASH_FRAGMENT_2(key_hash)] =
- grpc_slice_ref_internal(elem->key);
+ grpc_slice_ref_internal(GRPC_MDKEY(elem));
c->indices_keys[HASH_FRAGMENT_2(key_hash)] = new_index;
} else if (c->entries_keys[HASH_FRAGMENT_3(key_hash)].refcount ==
&terminal_slice_refcount) {
c->entries_keys[HASH_FRAGMENT_3(key_hash)] =
- grpc_slice_ref_internal(elem->key);
+ grpc_slice_ref_internal(GRPC_MDKEY(elem));
c->indices_keys[HASH_FRAGMENT_3(key_hash)] = new_index;
} else if (c->indices_keys[HASH_FRAGMENT_2(key_hash)] <
c->indices_keys[HASH_FRAGMENT_3(key_hash)]) {
grpc_slice_unref_internal(exec_ctx,
c->entries_keys[HASH_FRAGMENT_2(key_hash)]);
c->entries_keys[HASH_FRAGMENT_2(key_hash)] =
- grpc_slice_ref_internal(elem->key);
+ grpc_slice_ref_internal(GRPC_MDKEY(elem));
c->indices_keys[HASH_FRAGMENT_2(key_hash)] = new_index;
} else {
grpc_slice_unref_internal(exec_ctx,
c->entries_keys[HASH_FRAGMENT_3(key_hash)]);
c->entries_keys[HASH_FRAGMENT_3(key_hash)] =
- grpc_slice_ref_internal(elem->key);
+ grpc_slice_ref_internal(GRPC_MDKEY(elem));
c->indices_keys[HASH_FRAGMENT_3(key_hash)] = new_index;
}
}
@@ -286,13 +287,13 @@ static void emit_indexed(grpc_chttp2_hpack_compressor *c, uint32_t elem_index,
}
static grpc_slice get_wire_value(grpc_mdelem elem, uint8_t *huffman_prefix) {
- if (grpc_is_binary_header(elem->key)) {
+ if (grpc_is_binary_header(GRPC_MDKEY(elem))) {
*huffman_prefix = 0x80;
- return grpc_chttp2_base64_encode_and_huffman_compress(elem->value);
+ return grpc_chttp2_base64_encode_and_huffman_compress(GRPC_MDVALUE(elem));
}
/* TODO(ctiller): opportunistically compress non-binary headers */
*huffman_prefix = 0x00;
- return grpc_slice_ref(elem->value);
+ return grpc_slice_ref(GRPC_MDVALUE(elem));
}
static void emit_lithdr_incidx(grpc_chttp2_hpack_compressor *c,
@@ -331,7 +332,7 @@ static void emit_lithdr_noidx(grpc_chttp2_hpack_compressor *c,
static void emit_lithdr_incidx_v(grpc_chttp2_hpack_compressor *c,
grpc_mdelem elem, framer_state *st) {
- uint32_t len_key = (uint32_t)GRPC_SLICE_LENGTH(elem->key);
+ uint32_t len_key = (uint32_t)GRPC_SLICE_LENGTH(GRPC_MDKEY(elem));
uint8_t huffman_prefix;
grpc_slice value_slice = get_wire_value(elem, &huffman_prefix);
uint32_t len_val = (uint32_t)GRPC_SLICE_LENGTH(value_slice);
@@ -342,7 +343,7 @@ static void emit_lithdr_incidx_v(grpc_chttp2_hpack_compressor *c,
*add_tiny_header_data(st, 1) = 0x40;
GRPC_CHTTP2_WRITE_VARINT(len_key, 1, 0x00,
add_tiny_header_data(st, len_key_len), len_key_len);
- add_header_data(st, grpc_slice_ref_internal(elem->key));
+ add_header_data(st, grpc_slice_ref_internal(GRPC_MDKEY(elem)));
GRPC_CHTTP2_WRITE_VARINT(len_val, 1, huffman_prefix,
add_tiny_header_data(st, len_val_len), len_val_len);
add_header_data(st, value_slice);
@@ -350,7 +351,7 @@ static void emit_lithdr_incidx_v(grpc_chttp2_hpack_compressor *c,
static void emit_lithdr_noidx_v(grpc_chttp2_hpack_compressor *c,
grpc_mdelem elem, framer_state *st) {
- uint32_t len_key = (uint32_t)GRPC_SLICE_LENGTH(elem->key);
+ uint32_t len_key = (uint32_t)GRPC_SLICE_LENGTH(GRPC_MDKEY(elem));
uint8_t huffman_prefix;
grpc_slice value_slice = get_wire_value(elem, &huffman_prefix);
uint32_t len_val = (uint32_t)GRPC_SLICE_LENGTH(value_slice);
@@ -361,7 +362,7 @@ static void emit_lithdr_noidx_v(grpc_chttp2_hpack_compressor *c,
*add_tiny_header_data(st, 1) = 0x00;
GRPC_CHTTP2_WRITE_VARINT(len_key, 1, 0x00,
add_tiny_header_data(st, len_key_len), len_key_len);
- add_header_data(st, grpc_slice_ref_internal(elem->key));
+ add_header_data(st, grpc_slice_ref_internal(GRPC_MDKEY(elem)));
GRPC_CHTTP2_WRITE_VARINT(len_val, 1, huffman_prefix,
add_tiny_header_data(st, len_val_len), len_val_len);
add_header_data(st, value_slice);
@@ -383,15 +384,15 @@ static uint32_t dynidx(grpc_chttp2_hpack_compressor *c, uint32_t elem_index) {
/* encode an mdelem */
static void hpack_enc(grpc_exec_ctx *exec_ctx, grpc_chttp2_hpack_compressor *c,
grpc_mdelem elem, framer_state *st) {
- uint32_t key_hash = grpc_slice_hash(elem->key);
- uint32_t value_hash = grpc_slice_hash(elem->value);
+ uint32_t key_hash = grpc_slice_hash(GRPC_MDKEY(elem));
+ uint32_t value_hash = grpc_slice_hash(GRPC_MDVALUE(elem));
uint32_t elem_hash = GRPC_MDSTR_KV_HASH(key_hash, value_hash);
size_t decoder_space_usage;
uint32_t indices_key;
int should_add_elem;
- GPR_ASSERT(GRPC_SLICE_LENGTH(elem->key) > 0);
- if (GRPC_SLICE_START_PTR(elem->key)[0] != ':') { /* regular header */
+ GPR_ASSERT(GRPC_SLICE_LENGTH(GRPC_MDKEY(elem)) > 0);
+ if (GRPC_SLICE_START_PTR(GRPC_MDKEY(elem))[0] != ':') { /* regular header */
st->seen_regular_header = 1;
} else {
GPR_ASSERT(
@@ -403,7 +404,7 @@ static void hpack_enc(grpc_exec_ctx *exec_ctx, grpc_chttp2_hpack_compressor *c,
/* is this elem currently in the decoders table? */
- if (c->entries_elems[HASH_FRAGMENT_2(elem_hash)] == elem &&
+ if (grpc_mdelem_eq(c->entries_elems[HASH_FRAGMENT_2(elem_hash)], elem) &&
c->indices_elems[HASH_FRAGMENT_2(elem_hash)] > c->tail_remote_index) {
/* HIT: complete element (first cuckoo hash) */
emit_indexed(c, dynidx(c, c->indices_elems[HASH_FRAGMENT_2(elem_hash)]),
@@ -411,7 +412,7 @@ static void hpack_enc(grpc_exec_ctx *exec_ctx, grpc_chttp2_hpack_compressor *c,
return;
}
- if (c->entries_elems[HASH_FRAGMENT_3(elem_hash)] == elem &&
+ if (grpc_mdelem_eq(c->entries_elems[HASH_FRAGMENT_3(elem_hash)], elem) &&
c->indices_elems[HASH_FRAGMENT_3(elem_hash)] > c->tail_remote_index) {
/* HIT: complete element (second cuckoo hash) */
emit_indexed(c, dynidx(c, c->indices_elems[HASH_FRAGMENT_3(elem_hash)]),
@@ -428,8 +429,8 @@ static void hpack_enc(grpc_exec_ctx *exec_ctx, grpc_chttp2_hpack_compressor *c,
/* no hits for the elem... maybe there's a key? */
indices_key = c->indices_keys[HASH_FRAGMENT_2(key_hash)];
- if (grpc_slice_cmp(c->entries_keys[HASH_FRAGMENT_2(key_hash)], elem->key) ==
- 0 &&
+ if (grpc_slice_cmp(c->entries_keys[HASH_FRAGMENT_2(key_hash)],
+ GRPC_MDKEY(elem)) == 0 &&
indices_key > c->tail_remote_index) {
/* HIT: key (first cuckoo hash) */
if (should_add_elem) {
@@ -444,8 +445,8 @@ static void hpack_enc(grpc_exec_ctx *exec_ctx, grpc_chttp2_hpack_compressor *c,
}
indices_key = c->indices_keys[HASH_FRAGMENT_3(key_hash)];
- if (grpc_slice_cmp(c->entries_keys[HASH_FRAGMENT_3(key_hash)], elem->key) ==
- 0 &&
+ if (grpc_slice_cmp(c->entries_keys[HASH_FRAGMENT_3(key_hash)],
+ GRPC_MDKEY(elem)) == 0 &&
indices_key > c->tail_remote_index) {
/* HIT: key (first cuckoo hash) */
if (should_add_elem) {
@@ -512,9 +513,7 @@ void grpc_chttp2_hpack_compressor_destroy(grpc_exec_ctx *exec_ctx,
if (c->entries_keys[i].refcount != &terminal_slice_refcount) {
grpc_slice_unref_internal(exec_ctx, c->entries_keys[i]);
}
- if (c->entries_elems[i]) {
- GRPC_MDELEM_UNREF(exec_ctx, c->entries_elems[i]);
- }
+ GRPC_MDELEM_UNREF(exec_ctx, c->entries_elems[i]);
}
gpr_free(c->table_elem_size);
}
diff --git a/src/core/ext/transport/chttp2/transport/hpack_parser.c b/src/core/ext/transport/chttp2/transport/hpack_parser.c
index d3114f5e07..91bedcf7f0 100644
--- a/src/core/ext/transport/chttp2/transport/hpack_parser.c
+++ b/src/core/ext/transport/chttp2/transport/hpack_parser.c
@@ -773,7 +773,7 @@ static grpc_error *finish_indexed_field(grpc_exec_ctx *exec_ctx,
const uint8_t *cur,
const uint8_t *end) {
grpc_mdelem md = grpc_chttp2_hptbl_lookup(&p->table, p->index);
- if (md == NULL) {
+ if (GRPC_MDISNULL(md)) {
return grpc_error_set_int(
grpc_error_set_int(GRPC_ERROR_CREATE("Invalid HPACK index received"),
GRPC_ERROR_INT_INDEX, (intptr_t)p->index),
@@ -815,12 +815,12 @@ static grpc_error *finish_lithdr_incidx(grpc_exec_ctx *exec_ctx,
const uint8_t *cur,
const uint8_t *end) {
grpc_mdelem md = grpc_chttp2_hptbl_lookup(&p->table, p->index);
- GPR_ASSERT(md != NULL); /* handled in string parsing */
- grpc_error *err =
- on_hdr(exec_ctx, p,
- grpc_mdelem_from_slices(exec_ctx, grpc_slice_ref_internal(md->key),
- take_string(p, &p->value)),
- 1);
+ GPR_ASSERT(!GRPC_MDISNULL(md)); /* handled in string parsing */
+ grpc_error *err = on_hdr(
+ exec_ctx, p,
+ grpc_mdelem_from_slices(exec_ctx, grpc_slice_ref_internal(GRPC_MDKEY(md)),
+ take_string(p, &p->value)),
+ 1);
if (err != GRPC_ERROR_NONE) return parse_error(exec_ctx, p, cur, end, err);
return parse_begin(exec_ctx, p, cur, end);
}
@@ -884,12 +884,12 @@ static grpc_error *finish_lithdr_notidx(grpc_exec_ctx *exec_ctx,
const uint8_t *cur,
const uint8_t *end) {
grpc_mdelem md = grpc_chttp2_hptbl_lookup(&p->table, p->index);
- GPR_ASSERT(md != NULL); /* handled in string parsing */
- grpc_error *err =
- on_hdr(exec_ctx, p,
- grpc_mdelem_from_slices(exec_ctx, grpc_slice_ref_internal(md->key),
- take_string(p, &p->value)),
- 0);
+ GPR_ASSERT(!GRPC_MDISNULL(md)); /* handled in string parsing */
+ grpc_error *err = on_hdr(
+ exec_ctx, p,
+ grpc_mdelem_from_slices(exec_ctx, grpc_slice_ref_internal(GRPC_MDKEY(md)),
+ take_string(p, &p->value)),
+ 0);
if (err != GRPC_ERROR_NONE) return parse_error(exec_ctx, p, cur, end, err);
return parse_begin(exec_ctx, p, cur, end);
}
@@ -953,12 +953,12 @@ static grpc_error *finish_lithdr_nvridx(grpc_exec_ctx *exec_ctx,
const uint8_t *cur,
const uint8_t *end) {
grpc_mdelem md = grpc_chttp2_hptbl_lookup(&p->table, p->index);
- GPR_ASSERT(md != NULL); /* handled in string parsing */
- grpc_error *err =
- on_hdr(exec_ctx, p,
- grpc_mdelem_from_slices(exec_ctx, grpc_slice_ref_internal(md->key),
- take_string(p, &p->value)),
- 0);
+ GPR_ASSERT(!GRPC_MDISNULL(md)); /* handled in string parsing */
+ grpc_error *err = on_hdr(
+ exec_ctx, p,
+ grpc_mdelem_from_slices(exec_ctx, grpc_slice_ref_internal(GRPC_MDKEY(md)),
+ take_string(p, &p->value)),
+ 0);
if (err != GRPC_ERROR_NONE) return parse_error(exec_ctx, p, cur, end, err);
return parse_begin(exec_ctx, p, cur, end);
}
@@ -1501,13 +1501,13 @@ static bool is_binary_literal_header(grpc_chttp2_hpack_parser *p) {
static grpc_error *is_binary_indexed_header(grpc_chttp2_hpack_parser *p,
bool *is) {
grpc_mdelem elem = grpc_chttp2_hptbl_lookup(&p->table, p->index);
- if (!elem) {
+ if (GRPC_MDISNULL(elem)) {
return grpc_error_set_int(
grpc_error_set_int(GRPC_ERROR_CREATE("Invalid HPACK index received"),
GRPC_ERROR_INT_INDEX, (intptr_t)p->index),
GRPC_ERROR_INT_SIZE, (intptr_t)p->table.num_ents);
}
- *is = grpc_is_binary_header(elem->key);
+ *is = grpc_is_binary_header(GRPC_MDKEY(elem));
return GRPC_ERROR_NONE;
}
diff --git a/src/core/ext/transport/chttp2/transport/hpack_table.c b/src/core/ext/transport/chttp2/transport/hpack_table.c
index 2be0406015..2cb816fe53 100644
--- a/src/core/ext/transport/chttp2/transport/hpack_table.c
+++ b/src/core/ext/transport/chttp2/transport/hpack_table.c
@@ -212,7 +212,7 @@ void grpc_chttp2_hptbl_destroy(grpc_exec_ctx *exec_ctx,
}
grpc_mdelem grpc_chttp2_hptbl_lookup(const grpc_chttp2_hptbl *tbl,
- uint32_t tbl_index) {
+ uint32_t tbl_index) {
/* Static table comes first, just return an entry from it */
if (tbl_index <= GRPC_CHTTP2_LAST_STATIC_ENTRY) {
return tbl->static_ents[tbl_index - 1];
@@ -225,14 +225,14 @@ grpc_mdelem grpc_chttp2_hptbl_lookup(const grpc_chttp2_hptbl *tbl,
return tbl->ents[offset];
}
/* Invalid entry: return error */
- return NULL;
+ return GRPC_MDNULL;
}
/* Evict one element from the table */
static void evict1(grpc_exec_ctx *exec_ctx, grpc_chttp2_hptbl *tbl) {
grpc_mdelem first_ent = tbl->ents[tbl->first_ent];
- size_t elem_bytes = GRPC_SLICE_LENGTH(first_ent->key) +
- GRPC_SLICE_LENGTH(first_ent->value) +
+ size_t elem_bytes = GRPC_SLICE_LENGTH(GRPC_MDKEY(first_ent)) +
+ GRPC_SLICE_LENGTH(GRPC_MDVALUE(first_ent)) +
GRPC_CHTTP2_HPACK_ENTRY_OVERHEAD;
GPR_ASSERT(elem_bytes <= tbl->mem_used);
tbl->mem_used -= (uint32_t)elem_bytes;
@@ -306,8 +306,8 @@ grpc_error *grpc_chttp2_hptbl_set_current_table_size(grpc_exec_ctx *exec_ctx,
grpc_error *grpc_chttp2_hptbl_add(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hptbl *tbl, grpc_mdelem md) {
/* determine how many bytes of buffer this entry represents */
- size_t elem_bytes = GRPC_SLICE_LENGTH(md->key) +
- GRPC_SLICE_LENGTH(md->value) +
+ size_t elem_bytes = GRPC_SLICE_LENGTH(GRPC_MDKEY(md)) +
+ GRPC_SLICE_LENGTH(GRPC_MDVALUE(md)) +
GRPC_CHTTP2_HPACK_ENTRY_OVERHEAD;
if (tbl->current_table_bytes > tbl->max_bytes) {
@@ -362,9 +362,9 @@ grpc_chttp2_hptbl_find_result grpc_chttp2_hptbl_find(
/* See if the string is in the static table */
for (i = 0; i < GRPC_CHTTP2_LAST_STATIC_ENTRY; i++) {
grpc_mdelem ent = tbl->static_ents[i];
- if (grpc_slice_cmp(md->key, ent->key) != 0) continue;
+ if (grpc_slice_cmp(GRPC_MDKEY(md), GRPC_MDKEY(ent)) != 0) continue;
r.index = i + 1u;
- r.has_value = grpc_slice_cmp(md->value, ent->value) == 0;
+ r.has_value = grpc_slice_cmp(GRPC_MDVALUE(md), GRPC_MDVALUE(ent)) == 0;
if (r.has_value) return r;
}
@@ -373,9 +373,9 @@ grpc_chttp2_hptbl_find_result grpc_chttp2_hptbl_find(
uint32_t idx =
(uint32_t)(tbl->num_ents - i + GRPC_CHTTP2_LAST_STATIC_ENTRY);
grpc_mdelem ent = tbl->ents[(tbl->first_ent + i) % tbl->cap_entries];
- if (grpc_slice_cmp(md->key, ent->key) != 0) continue;
+ if (grpc_slice_cmp(GRPC_MDKEY(md), GRPC_MDKEY(ent)) != 0) continue;
r.index = idx;
- r.has_value = grpc_slice_cmp(md->value, ent->value) == 0;
+ r.has_value = grpc_slice_cmp(GRPC_MDVALUE(md), GRPC_MDVALUE(ent)) == 0;
if (r.has_value) return r;
}
diff --git a/src/core/ext/transport/chttp2/transport/parsing.c b/src/core/ext/transport/chttp2/transport/parsing.c
index 5cb460f3e2..670ce51b72 100644
--- a/src/core/ext/transport/chttp2/transport/parsing.c
+++ b/src/core/ext/transport/chttp2/transport/parsing.c
@@ -453,29 +453,30 @@ static void on_initial_header(grpc_exec_ctx *exec_ctx, void *tp,
GPR_ASSERT(s != NULL);
if (grpc_http_trace) {
- char *key = grpc_dump_slice(md->key, GPR_DUMP_ASCII);
- char *value = grpc_dump_slice(md->value, GPR_DUMP_HEX | GPR_DUMP_ASCII);
+ char *key = grpc_dump_slice(GRPC_MDKEY(md), GPR_DUMP_ASCII);
+ char *value =
+ grpc_dump_slice(GRPC_MDVALUE(md), GPR_DUMP_HEX | GPR_DUMP_ASCII);
gpr_log(GPR_INFO, "HTTP:%d:HDR:%s: %s: %s", s->id,
t->is_client ? "CLI" : "SVR", key, value);
gpr_free(key);
gpr_free(value);
}
- if (grpc_slice_cmp(md->key, GRPC_MDSTR_GRPC_STATUS) == 0 &&
- md != GRPC_MDELEM_GRPC_STATUS_0) {
+ if (grpc_slice_cmp(GRPC_MDKEY(md), GRPC_MDSTR_GRPC_STATUS) == 0 &&
+ !grpc_mdelem_eq(md, GRPC_MDELEM_GRPC_STATUS_0)) {
/* TODO(ctiller): check for a status like " 0" */
s->seen_error = true;
}
- if (grpc_slice_cmp(md->key, GRPC_MDSTR_GRPC_TIMEOUT) == 0) {
+ if (grpc_slice_cmp(GRPC_MDKEY(md), GRPC_MDSTR_GRPC_TIMEOUT) == 0) {
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_SLICE_START_PTR(md->value),
- GRPC_SLICE_LENGTH(md->value),
+ if (!grpc_http2_decode_timeout(GRPC_SLICE_START_PTR(GRPC_MDVALUE(md)),
+ GRPC_SLICE_LENGTH(GRPC_MDVALUE(md)),
cached_timeout)) {
- char *val = grpc_dump_slice(md->value, GPR_DUMP_ASCII);
+ char *val = grpc_dump_slice(GRPC_MDVALUE(md), GPR_DUMP_ASCII);
gpr_log(GPR_ERROR, "Ignoring bad timeout value '%s'", val);
gpr_free(val);
*cached_timeout = gpr_inf_future(GPR_TIMESPAN);
@@ -523,16 +524,17 @@ static void on_trailing_header(grpc_exec_ctx *exec_ctx, void *tp,
GPR_ASSERT(s != NULL);
if (grpc_http_trace) {
- char *key = grpc_dump_slice(md->key, GPR_DUMP_ASCII);
- char *value = grpc_dump_slice(md->value, GPR_DUMP_HEX | GPR_DUMP_ASCII);
+ char *key = grpc_dump_slice(GRPC_MDKEY(md), GPR_DUMP_ASCII);
+ char *value =
+ grpc_dump_slice(GRPC_MDVALUE(md), GPR_DUMP_HEX | GPR_DUMP_ASCII);
gpr_log(GPR_INFO, "HTTP:%d:TRL:%s: %s: %s", s->id,
t->is_client ? "CLI" : "SVR", key, value);
gpr_free(key);
gpr_free(value);
}
- if (grpc_slice_cmp(md->key, GRPC_MDSTR_GRPC_STATUS) == 0 &&
- md != GRPC_MDELEM_GRPC_STATUS_0) {
+ if (grpc_slice_cmp(GRPC_MDKEY(md), GRPC_MDSTR_GRPC_STATUS) == 0 &&
+ !grpc_mdelem_eq(md, GRPC_MDELEM_GRPC_STATUS_0)) {
/* TODO(ctiller): check for a status like " 0" */
s->seen_error = true;
}
diff --git a/src/core/lib/channel/message_size_filter.c b/src/core/lib/channel/message_size_filter.c
index 4f61da825e..bddfba4770 100644
--- a/src/core/lib/channel/message_size_filter.c
+++ b/src/core/lib/channel/message_size_filter.c
@@ -39,7 +39,8 @@
#include <grpc/support/string_util.h>
#include "src/core/lib/channel/channel_args.h"
-#include "src/core/lib/transport/method_config.h"
+#include "src/core/lib/support/string.h"
+#include "src/core/lib/transport/service_config.h"
#define DEFAULT_MAX_SEND_MESSAGE_LENGTH -1 // Unlimited.
// The protobuf library will (by default) start warning at 100 megs.
@@ -56,32 +57,33 @@ static void* message_size_limits_copy(void* value) {
return new_value;
}
-static int message_size_limits_cmp(void* value1, void* value2) {
- const message_size_limits* v1 = value1;
- const message_size_limits* v2 = value2;
- if (v1->max_send_size > v2->max_send_size) return 1;
- if (v1->max_send_size < v2->max_send_size) return -1;
- if (v1->max_recv_size > v2->max_recv_size) return 1;
- if (v1->max_recv_size < v2->max_recv_size) return -1;
- return 0;
+static void message_size_limits_free(grpc_exec_ctx* exec_ctx, void* value) {
+ gpr_free(value);
}
-static void free_mem(grpc_exec_ctx* exec_ctx, void* p) { gpr_free(p); }
-
static const grpc_slice_hash_table_vtable message_size_limits_vtable = {
- free_mem, message_size_limits_copy, message_size_limits_cmp};
+ message_size_limits_free, message_size_limits_copy};
-static void* method_config_convert_value(
- const grpc_method_config* method_config) {
+static void* message_size_limits_create_from_json(const grpc_json* json) {
+ int max_request_message_bytes = -1;
+ int max_response_message_bytes = -1;
+ for (grpc_json* field = json->child; field != NULL; field = field->next) {
+ if (field->key == NULL) continue;
+ if (strcmp(field->key, "maxRequestMessageBytes") == 0) {
+ if (max_request_message_bytes >= 0) return NULL; // Duplicate.
+ if (field->type != GRPC_JSON_STRING) return NULL;
+ max_request_message_bytes = gpr_parse_nonnegative_int(field->value);
+ if (max_request_message_bytes == -1) return NULL;
+ } else if (strcmp(field->key, "maxResponseMessageBytes") == 0) {
+ if (max_response_message_bytes >= 0) return NULL; // Duplicate.
+ if (field->type != GRPC_JSON_STRING) return NULL;
+ max_response_message_bytes = gpr_parse_nonnegative_int(field->value);
+ if (max_response_message_bytes == -1) return NULL;
+ }
+ }
message_size_limits* value = gpr_malloc(sizeof(message_size_limits));
- const int32_t* max_request_message_bytes =
- grpc_method_config_get_max_request_message_bytes(method_config);
- value->max_send_size =
- max_request_message_bytes != NULL ? *max_request_message_bytes : -1;
- const int32_t* max_response_message_bytes =
- grpc_method_config_get_max_response_message_bytes(method_config);
- value->max_recv_size =
- max_response_message_bytes != NULL ? *max_response_message_bytes : -1;
+ value->max_send_size = max_request_message_bytes;
+ value->max_recv_size = max_response_message_bytes;
return value;
}
@@ -225,10 +227,16 @@ static void init_channel_elem(grpc_exec_ctx* exec_ctx,
const grpc_arg* channel_arg =
grpc_channel_args_find(args->channel_args, GRPC_ARG_SERVICE_CONFIG);
if (channel_arg != NULL) {
- GPR_ASSERT(channel_arg->type == GRPC_ARG_POINTER);
- chand->method_limit_table = grpc_method_config_table_convert(
- exec_ctx, (grpc_method_config_table*)channel_arg->value.pointer.p,
- method_config_convert_value, &message_size_limits_vtable);
+ GPR_ASSERT(channel_arg->type == GRPC_ARG_STRING);
+ grpc_service_config* service_config =
+ grpc_service_config_create(channel_arg->value.string);
+ if (service_config != NULL) {
+ chand->method_limit_table =
+ grpc_service_config_create_method_config_table(
+ exec_ctx, service_config, message_size_limits_create_from_json,
+ &message_size_limits_vtable);
+ grpc_service_config_destroy(service_config);
+ }
}
}
diff --git a/src/core/lib/json/json.c b/src/core/lib/json/json.c
index 5b583a1f2e..48b13686d7 100644
--- a/src/core/lib/json/json.c
+++ b/src/core/lib/json/json.c
@@ -37,15 +37,15 @@
#include "src/core/lib/json/json.h"
-grpc_json *grpc_json_create(grpc_json_type type) {
- grpc_json *json = gpr_malloc(sizeof(*json));
+grpc_json* grpc_json_create(grpc_json_type type) {
+ grpc_json* json = gpr_malloc(sizeof(*json));
memset(json, 0, sizeof(*json));
json->type = type;
return json;
}
-void grpc_json_destroy(grpc_json *json) {
+void grpc_json_destroy(grpc_json* json) {
while (json->child) {
grpc_json_destroy(json->child);
}
diff --git a/src/core/lib/json/json.h b/src/core/lib/json/json.h
index 681df4bb77..7111db0b52 100644
--- a/src/core/lib/json/json.h
+++ b/src/core/lib/json/json.h
@@ -42,14 +42,14 @@
* are not owned by it.
*/
typedef struct grpc_json {
- struct grpc_json *next;
- struct grpc_json *prev;
- struct grpc_json *child;
- struct grpc_json *parent;
+ struct grpc_json* next;
+ struct grpc_json* prev;
+ struct grpc_json* child;
+ struct grpc_json* parent;
grpc_json_type type;
- const char *key;
- const char *value;
+ const char* key;
+ const char* value;
} grpc_json;
/* The next two functions are going to parse the input string, and
@@ -65,8 +65,8 @@ typedef struct grpc_json {
*
* Delete the allocated tree afterward using grpc_json_destroy().
*/
-grpc_json *grpc_json_parse_string_with_len(char *input, size_t size);
-grpc_json *grpc_json_parse_string(char *input);
+grpc_json* grpc_json_parse_string_with_len(char* input, size_t size);
+grpc_json* grpc_json_parse_string(char* input);
/* This function will create a new string using gpr_realloc, and will
* deserialize the grpc_json tree into it. It'll be zero-terminated,
@@ -76,13 +76,13 @@ grpc_json *grpc_json_parse_string(char *input);
* If indent is 0, then newlines will be suppressed as well, and the
* output will be condensed at its maximum.
*/
-char *grpc_json_dump_to_string(grpc_json *json, int indent);
+char* grpc_json_dump_to_string(grpc_json* json, int indent);
/* Use these to create or delete a grpc_json object.
* Deletion is recursive. We will not attempt to free any of the strings
* in any of the objects of that tree.
*/
-grpc_json *grpc_json_create(grpc_json_type type);
-void grpc_json_destroy(grpc_json *json);
+grpc_json* grpc_json_create(grpc_json_type type);
+void grpc_json_destroy(grpc_json* json);
#endif /* GRPC_CORE_LIB_JSON_JSON_H */
diff --git a/src/core/lib/security/transport/client_auth_filter.c b/src/core/lib/security/transport/client_auth_filter.c
index e2e4a09e62..d680c1ef13 100644
--- a/src/core/lib/security/transport/client_auth_filter.c
+++ b/src/core/lib/security/transport/client_auth_filter.c
@@ -256,17 +256,17 @@ static void auth_start_transport_op(grpc_exec_ctx *exec_ctx,
grpc_mdelem md = l->md;
/* Pointer comparison is OK for md_elems created from the same context.
*/
- if (grpc_slice_cmp(md->key, GRPC_MDSTR_AUTHORITY) == 0) {
+ if (grpc_slice_cmp(GRPC_MDKEY(md), GRPC_MDSTR_AUTHORITY) == 0) {
if (calld->have_host) {
grpc_slice_unref_internal(exec_ctx, calld->host);
}
- calld->host = grpc_slice_ref_internal(md->value);
+ calld->host = grpc_slice_ref_internal(GRPC_MDVALUE(md));
calld->have_host = true;
- } else if (grpc_slice_cmp(md->key, GRPC_MDSTR_PATH) == 0) {
+ } else if (grpc_slice_cmp(GRPC_MDKEY(md), GRPC_MDSTR_PATH) == 0) {
if (calld->have_method) {
grpc_slice_unref_internal(exec_ctx, calld->method);
}
- calld->method = grpc_slice_ref_internal(md->value);
+ calld->method = grpc_slice_ref_internal(GRPC_MDVALUE(md));
calld->have_method = true;
}
}
diff --git a/src/core/lib/security/transport/server_auth_filter.c b/src/core/lib/security/transport/server_auth_filter.c
index e7c0f1a079..1c4843fc14 100644
--- a/src/core/lib/security/transport/server_auth_filter.c
+++ b/src/core/lib/security/transport/server_auth_filter.c
@@ -69,8 +69,8 @@ static grpc_metadata_array metadata_batch_to_md_array(
for (l = batch->list.head; l != NULL; l = l->next) {
grpc_metadata *usr_md = NULL;
grpc_mdelem md = l->md;
- grpc_slice key = md->key;
- grpc_slice value = md->value;
+ grpc_slice key = GRPC_MDKEY(md);
+ grpc_slice value = GRPC_MDVALUE(md);
if (result.count == result.capacity) {
result.capacity = GPR_MAX(result.capacity + 8, result.capacity * 2);
result.metadata =
@@ -90,9 +90,9 @@ static grpc_mdelem remove_consumed_md(grpc_exec_ctx *exec_ctx, void *user_data,
size_t i;
for (i = 0; i < calld->num_consumed_md; i++) {
const grpc_metadata *consumed_md = &calld->consumed_md[i];
- if (grpc_slice_cmp(md->key, consumed_md->key) == 0 &&
- grpc_slice_cmp(md->value, consumed_md->value) == 0)
- return NULL;
+ if (grpc_slice_cmp(GRPC_MDKEY(md), consumed_md->key) == 0 &&
+ grpc_slice_cmp(GRPC_MDKEY(md), consumed_md->value) == 0)
+ return GRPC_MDNULL;
}
return md;
}
diff --git a/src/core/lib/slice/slice_hash_table.c b/src/core/lib/slice/slice_hash_table.c
index 10b41343ea..55f20155f3 100644
--- a/src/core/lib/slice/slice_hash_table.c
+++ b/src/core/lib/slice/slice_hash_table.c
@@ -46,7 +46,6 @@ static const grpc_slice terminal_slice = {&terminal_slice_refcount,
struct grpc_slice_hash_table {
gpr_refcount refs;
- size_t num_entries;
size_t size;
grpc_slice_hash_table_entry* entries;
};
@@ -90,7 +89,6 @@ grpc_slice_hash_table* grpc_slice_hash_table_create(
grpc_slice_hash_table* table = gpr_malloc(sizeof(*table));
memset(table, 0, sizeof(*table));
gpr_ref_init(&table->refs, 1);
- table->num_entries = num_entries;
// Quadratic probing gets best performance when the table is no more
// than half full.
table->size = num_entries * 2;
@@ -112,8 +110,8 @@ grpc_slice_hash_table* grpc_slice_hash_table_ref(grpc_slice_hash_table* table) {
return table;
}
-int grpc_slice_hash_table_unref(grpc_exec_ctx* exec_ctx,
- grpc_slice_hash_table* table) {
+void grpc_slice_hash_table_unref(grpc_exec_ctx* exec_ctx,
+ grpc_slice_hash_table* table) {
if (table != NULL && gpr_unref(&table->refs)) {
for (size_t i = 0; i < table->size; ++i) {
grpc_slice_hash_table_entry* entry = &table->entries[i];
@@ -124,13 +122,7 @@ int grpc_slice_hash_table_unref(grpc_exec_ctx* exec_ctx,
}
gpr_free(table->entries);
gpr_free(table);
- return 1;
}
- return 0;
-}
-
-size_t grpc_slice_hash_table_num_entries(const grpc_slice_hash_table* table) {
- return table->num_entries;
}
void* grpc_slice_hash_table_get(const grpc_slice_hash_table* table,
@@ -140,35 +132,3 @@ void* grpc_slice_hash_table_get(const grpc_slice_hash_table* table,
if (idx == table->size) return NULL; // Not found.
return table->entries[idx].value;
}
-
-int grpc_slice_hash_table_cmp(const grpc_slice_hash_table* table1,
- const grpc_slice_hash_table* table2) {
- // Compare by num_entries.
- if (table1->num_entries < table2->num_entries) return -1;
- if (table1->num_entries > table2->num_entries) return 1;
- for (size_t i = 0; i < table1->num_entries; ++i) {
- grpc_slice_hash_table_entry* e1 = &table1->entries[i];
- grpc_slice_hash_table_entry* e2 = &table2->entries[i];
- // Compare keys by hash value.
- int cmp = grpc_slice_cmp(e1->key, e2->key);
- if (cmp != 0) return cmp;
- // Compare by vtable (pointer equality).
- if (e1->vtable < e2->vtable) return -1;
- if (e1->vtable > e2->vtable) return 1;
- // Compare values via vtable.
- const int value_result = e1->vtable->compare_value(e1->value, e2->value);
- if (value_result != 0) return value_result;
- }
- return 0;
-}
-
-void grpc_slice_hash_table_iterate(
- const grpc_slice_hash_table* table,
- void (*func)(const grpc_slice_hash_table_entry* entry, void* user_data),
- void* user_data) {
- for (size_t i = 0; i < table->size; ++i) {
- if (!is_terminal(table->entries[i].key)) {
- func(&table->entries[i], user_data);
- }
- }
-}
diff --git a/src/core/lib/slice/slice_hash_table.h b/src/core/lib/slice/slice_hash_table.h
index ac04950cc6..f760836a48 100644
--- a/src/core/lib/slice/slice_hash_table.h
+++ b/src/core/lib/slice/slice_hash_table.h
@@ -51,7 +51,6 @@ typedef struct grpc_slice_hash_table grpc_slice_hash_table;
typedef struct grpc_slice_hash_table_vtable {
void (*destroy_value)(grpc_exec_ctx *exec_ctx, void *value);
void *(*copy_value)(void *value);
- int (*compare_value)(void *value1, void *value2);
} grpc_slice_hash_table_vtable;
typedef struct grpc_slice_hash_table_entry {
@@ -68,26 +67,12 @@ grpc_slice_hash_table *grpc_slice_hash_table_create(
grpc_slice_hash_table *grpc_slice_hash_table_ref(grpc_slice_hash_table *table);
/** Returns 1 when \a table is destroyed. */
-int grpc_slice_hash_table_unref(grpc_exec_ctx *exec_ctx,
- grpc_slice_hash_table *table);
-
-/** Returns the number of entries in \a table. */
-size_t grpc_slice_hash_table_num_entries(const grpc_slice_hash_table *table);
+void grpc_slice_hash_table_unref(grpc_exec_ctx *exec_ctx,
+ grpc_slice_hash_table *table);
/** Returns the value from \a table associated with \a key.
Returns NULL if \a key is not found. */
void *grpc_slice_hash_table_get(const grpc_slice_hash_table *table,
const grpc_slice key);
-/** Compares two hash tables.
- The sort order is stable but undefined. */
-int grpc_slice_hash_table_cmp(const grpc_slice_hash_table *table1,
- const grpc_slice_hash_table *table2);
-
-/** Iterates over the entries in \a table, calling \a func for each entry. */
-void grpc_slice_hash_table_iterate(
- const grpc_slice_hash_table *table,
- void (*func)(const grpc_slice_hash_table_entry *entry, void *user_data),
- void *user_data);
-
#endif /* GRPC_CORE_LIB_TRANSPORT_MDSTR_HASH_TABLE_H */
diff --git a/src/core/lib/support/string.c b/src/core/lib/support/string.c
index 85b915f118..0dc55c2ca3 100644
--- a/src/core/lib/support/string.c
+++ b/src/core/lib/support/string.c
@@ -34,7 +34,9 @@
#include "src/core/lib/support/string.h"
#include <ctype.h>
+#include <limits.h>
#include <stddef.h>
+#include <stdlib.h>
#include <string.h>
#include <grpc/support/alloc.h>
@@ -189,6 +191,13 @@ int int64_ttoa(int64_t value, char *string) {
return i;
}
+int gpr_parse_nonnegative_int(const char *value) {
+ char *end;
+ long result = strtol(value, &end, 0);
+ if (*end != '\0' || result < 0 || result > INT_MAX) return -1;
+ return (int)result;
+}
+
char *gpr_leftpad(const char *str, char flag, size_t length) {
const size_t str_length = strlen(str);
const size_t out_length = str_length > length ? str_length : length;
diff --git a/src/core/lib/support/string.h b/src/core/lib/support/string.h
index 81a12ae476..43ab4dc1be 100644
--- a/src/core/lib/support/string.h
+++ b/src/core/lib/support/string.h
@@ -77,6 +77,9 @@ NOTE: This function ensures sufficient bit width even on Win x64,
where long is 32bit is size.*/
int int64_ttoa(int64_t value, char *output);
+// Parses a non-negative number from a value string. Returns -1 on error.
+int gpr_parse_nonnegative_int(const char *value);
+
/* Reverse a run of bytes */
void gpr_reverse_bytes(char *str, int len);
diff --git a/src/core/lib/transport/service_config.c b/src/core/lib/transport/service_config.c
new file mode 100644
index 0000000000..8073a46105
--- /dev/null
+++ b/src/core/lib/transport/service_config.c
@@ -0,0 +1,254 @@
+//
+// Copyright 2015, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+
+#include "src/core/lib/transport/service_config.h"
+
+#include <string.h>
+
+#include <grpc/impl/codegen/grpc_types.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
+
+#include "src/core/lib/json/json.h"
+#include "src/core/lib/slice/slice_hash_table.h"
+#include "src/core/lib/slice/slice_internal.h"
+#include "src/core/lib/slice/slice_string_helpers.h"
+#include "src/core/lib/support/string.h"
+
+// The main purpose of the code here is to parse the service config in
+// JSON form, which will look like this:
+//
+// {
+// "loadBalancingPolicy": "string", // optional
+// "methodConfig": [ // array of one or more method_config objects
+// {
+// "name": [ // array of one or more name objects
+// {
+// "service": "string", // required
+// "method": "string", // optional
+// }
+// ],
+// // remaining fields are optional.
+// // see https://developers.google.com/protocol-buffers/docs/proto3#json
+// // for format details.
+// "waitForReady": bool,
+// "timeout": "duration_string",
+// "maxRequestMessageBytes": "int64_string",
+// "maxResponseMessageBytes": "int64_string",
+// }
+// ]
+// }
+
+struct grpc_service_config {
+ char* json_string; // Underlying storage for json_tree.
+ grpc_json* json_tree;
+};
+
+grpc_service_config* grpc_service_config_create(const char* json_string) {
+ grpc_service_config* service_config = gpr_malloc(sizeof(*service_config));
+ service_config->json_string = gpr_strdup(json_string);
+ service_config->json_tree =
+ grpc_json_parse_string(service_config->json_string);
+ if (service_config->json_tree == NULL) {
+ gpr_log(GPR_INFO, "failed to parse JSON for service config");
+ gpr_free(service_config->json_string);
+ gpr_free(service_config);
+ return NULL;
+ }
+ return service_config;
+}
+
+void grpc_service_config_destroy(grpc_service_config* service_config) {
+ grpc_json_destroy(service_config->json_tree);
+ gpr_free(service_config->json_string);
+ gpr_free(service_config);
+}
+
+const char* grpc_service_config_get_lb_policy_name(
+ const grpc_service_config* service_config) {
+ const grpc_json* json = service_config->json_tree;
+ if (json->type != GRPC_JSON_OBJECT || json->key != NULL) return NULL;
+ const char* lb_policy_name = NULL;
+ for (grpc_json* field = json->child; field != NULL; field = field->next) {
+ if (field->key == NULL) return NULL;
+ if (strcmp(field->key, "loadBalancingPolicy") == 0) {
+ if (lb_policy_name != NULL) return NULL; // Duplicate.
+ if (field->type != GRPC_JSON_STRING) return NULL;
+ lb_policy_name = field->value;
+ }
+ }
+ return lb_policy_name;
+}
+
+// Returns the number of names specified in the method config \a json.
+static size_t count_names_in_method_config_json(grpc_json* json) {
+ size_t num_names = 0;
+ for (grpc_json* field = json->child; field != NULL; field = field->next) {
+ if (field->key != NULL && strcmp(field->key, "name") == 0) ++num_names;
+ }
+ return num_names;
+}
+
+// Returns a path string for the JSON name object specified by \a json.
+// Returns NULL on error. Caller takes ownership of result.
+static char* parse_json_method_name(grpc_json* json) {
+ if (json->type != GRPC_JSON_OBJECT) return NULL;
+ const char* service_name = NULL;
+ const char* method_name = NULL;
+ for (grpc_json* child = json->child; child != NULL; child = child->next) {
+ if (child->key == NULL) return NULL;
+ if (child->type != GRPC_JSON_STRING) return NULL;
+ if (strcmp(child->key, "service") == 0) {
+ if (service_name != NULL) return NULL; // Duplicate.
+ if (child->value == NULL) return NULL;
+ service_name = child->value;
+ } else if (strcmp(child->key, "method") == 0) {
+ if (method_name != NULL) return NULL; // Duplicate.
+ if (child->value == NULL) return NULL;
+ method_name = child->value;
+ }
+ }
+ if (service_name == NULL) return NULL; // Required field.
+ char* path;
+ gpr_asprintf(&path, "/%s/%s", service_name,
+ method_name == NULL ? "*" : method_name);
+ return path;
+}
+
+// Parses the method config from \a json. Adds an entry to \a entries for
+// each name found, incrementing \a idx for each entry added.
+// Returns false on error.
+static bool parse_json_method_config(
+ grpc_exec_ctx* exec_ctx, grpc_json* json,
+ void* (*create_value)(const grpc_json* method_config_json),
+ const grpc_slice_hash_table_vtable* vtable,
+ grpc_slice_hash_table_entry* entries, size_t* idx) {
+ // Construct value.
+ void* method_config = create_value(json);
+ if (method_config == NULL) return false;
+ // Construct list of paths.
+ bool success = false;
+ gpr_strvec paths;
+ gpr_strvec_init(&paths);
+ for (grpc_json* child = json->child; child != NULL; child = child->next) {
+ if (child->key == NULL) continue;
+ if (strcmp(child->key, "name") == 0) {
+ if (child->type != GRPC_JSON_ARRAY) goto done;
+ for (grpc_json* name = child->child; name != NULL; name = name->next) {
+ char* path = parse_json_method_name(name);
+ gpr_strvec_add(&paths, path);
+ }
+ }
+ }
+ if (paths.count == 0) goto done; // No names specified.
+ // Add entry for each path.
+ for (size_t i = 0; i < paths.count; ++i) {
+ entries[*idx].key = grpc_slice_from_copied_string(paths.strs[i]);
+ entries[*idx].value = vtable->copy_value(method_config);
+ entries[*idx].vtable = vtable;
+ ++*idx;
+ }
+ success = true;
+done:
+ vtable->destroy_value(exec_ctx, method_config);
+ gpr_strvec_destroy(&paths);
+ return success;
+}
+
+grpc_slice_hash_table* grpc_service_config_create_method_config_table(
+ grpc_exec_ctx* exec_ctx, const grpc_service_config* service_config,
+ void* (*create_value)(const grpc_json* method_config_json),
+ const grpc_slice_hash_table_vtable* vtable) {
+ const grpc_json* json = service_config->json_tree;
+ // Traverse parsed JSON tree.
+ if (json->type != GRPC_JSON_OBJECT || json->key != NULL) return NULL;
+ size_t num_entries = 0;
+ grpc_slice_hash_table_entry* entries = NULL;
+ for (grpc_json* field = json->child; field != NULL; field = field->next) {
+ if (field->key == NULL) return NULL;
+ if (strcmp(field->key, "methodConfig") == 0) {
+ if (entries != NULL) return NULL; // Duplicate.
+ if (field->type != GRPC_JSON_ARRAY) return NULL;
+ // Find number of entries.
+ for (grpc_json* method = field->child; method != NULL;
+ method = method->next) {
+ num_entries += count_names_in_method_config_json(method);
+ }
+ // Populate method config table entries.
+ entries = gpr_malloc(num_entries * sizeof(grpc_slice_hash_table_entry));
+ size_t idx = 0;
+ for (grpc_json* method = field->child; method != NULL;
+ method = method->next) {
+ if (!parse_json_method_config(exec_ctx, method, create_value, vtable,
+ entries, &idx)) {
+ return NULL;
+ }
+ }
+ GPR_ASSERT(idx == num_entries);
+ }
+ }
+ // Instantiate method config table.
+ grpc_slice_hash_table* method_config_table = NULL;
+ if (entries != NULL) {
+ method_config_table = grpc_slice_hash_table_create(num_entries, entries);
+ // Clean up.
+ for (size_t i = 0; i < num_entries; ++i) {
+ grpc_slice_unref_internal(exec_ctx, entries[i].key);
+ vtable->destroy_value(exec_ctx, entries[i].value);
+ }
+ gpr_free(entries);
+ }
+ return method_config_table;
+}
+
+void* grpc_method_config_table_get(grpc_exec_ctx* exec_ctx,
+ const grpc_slice_hash_table* table,
+ grpc_slice path) {
+ void* value = grpc_slice_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) {
+ char* path_str = grpc_dump_slice(path, GPR_DUMP_ASCII);
+ 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_slice wildcard_path = grpc_slice_from_copied_string(buf);
+ gpr_free(buf);
+ value = grpc_slice_hash_table_get(table, wildcard_path);
+ grpc_slice_unref_internal(exec_ctx, wildcard_path);
+ gpr_free(path_str);
+ }
+ return value;
+}
diff --git a/src/core/lib/transport/service_config.h b/src/core/lib/transport/service_config.h
new file mode 100644
index 0000000000..ab964b3bae
--- /dev/null
+++ b/src/core/lib/transport/service_config.h
@@ -0,0 +1,71 @@
+//
+// Copyright 2016, 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_TRANSPORT_SERVICE_CONFIG_H
+#define GRPC_CORE_LIB_TRANSPORT_SERVICE_CONFIG_H
+
+#include <grpc/impl/codegen/grpc_types.h>
+
+#include "src/core/lib/json/json.h"
+#include "src/core/lib/slice/slice_hash_table.h"
+
+typedef struct grpc_service_config grpc_service_config;
+
+grpc_service_config* grpc_service_config_create(const char* json_string);
+void grpc_service_config_destroy(grpc_service_config* service_config);
+
+/// Gets the LB policy name from \a service_config.
+/// Returns NULL if no LB policy name was specified.
+/// Caller does NOT take ownership.
+const char* grpc_service_config_get_lb_policy_name(
+ const grpc_service_config* service_config);
+
+/// Creates a method config table based on the data in \a json.
+/// The table's keys are request paths. The table's value type is
+/// returned by \a create_value(), based on data parsed from the JSON tree.
+/// \a vtable provides methods used to manage the values.
+/// Returns NULL on error.
+grpc_slice_hash_table* grpc_service_config_create_method_config_table(
+ grpc_exec_ctx* exec_ctx, const grpc_service_config* service_config,
+ void* (*create_value)(const grpc_json* method_config_json),
+ const grpc_slice_hash_table_vtable* vtable);
+
+/// A helper function for looking up values in the table returned by
+/// \a grpc_service_config_create_method_config_table().
+/// Gets the method config for the specified \a path, which should be of
+/// the form "/service/method".
+/// Returns NULL if the method has no config.
+/// Caller does NOT own a reference to the result.
+void* grpc_method_config_table_get(grpc_exec_ctx* exec_ctx,
+ const grpc_slice_hash_table* table,
+ const grpc_slice path);
+
+#endif /* GRPC_CORE_LIB_TRANSPORT_SERVICE_CONFIG_H */
diff --git a/src/core/lib/transport/transport_op_string.c b/src/core/lib/transport/transport_op_string.c
index 0259fa23eb..b36e4f22d0 100644
--- a/src/core/lib/transport/transport_op_string.c
+++ b/src/core/lib/transport/transport_op_string.c
@@ -49,10 +49,12 @@
static void put_metadata(gpr_strvec *b, grpc_mdelem md) {
gpr_strvec_add(b, gpr_strdup("key="));
- gpr_strvec_add(b, grpc_dump_slice(md->key, GPR_DUMP_HEX | GPR_DUMP_ASCII));
+ gpr_strvec_add(
+ b, grpc_dump_slice(GRPC_MDKEY(md), GPR_DUMP_HEX | GPR_DUMP_ASCII));
gpr_strvec_add(b, gpr_strdup(" value="));
- gpr_strvec_add(b, grpc_dump_slice(md->value, GPR_DUMP_HEX | GPR_DUMP_ASCII));
+ gpr_strvec_add(
+ b, grpc_dump_slice(GRPC_MDVALUE(md), GPR_DUMP_HEX | GPR_DUMP_ASCII));
}
static void put_metadata_list(gpr_strvec *b, grpc_metadata_batch md) {