|
@@ -37,309 +37,10 @@
|
|
|
#include <grpc/support/alloc.h>
|
|
|
#include <grpc/support/log.h>
|
|
|
#include <grpc/support/string_util.h>
|
|
|
-#include <grpc/support/time.h>
|
|
|
|
|
|
#include "src/core/lib/json/json.h"
|
|
|
#include "src/core/lib/support/string.h"
|
|
|
#include "src/core/lib/transport/mdstr_hash_table.h"
|
|
|
-#include "src/core/lib/transport/metadata.h"
|
|
|
-
|
|
|
-//
|
|
|
-// grpc_method_config
|
|
|
-//
|
|
|
-
|
|
|
-// bool vtable
|
|
|
-
|
|
|
-static void* bool_copy(void* valuep) {
|
|
|
- bool value = *(bool*)valuep;
|
|
|
- bool* new_value = gpr_malloc(sizeof(bool));
|
|
|
- *new_value = value;
|
|
|
- return new_value;
|
|
|
-}
|
|
|
-
|
|
|
-static int bool_cmp(void* v1, void* v2) {
|
|
|
- bool b1 = *(bool*)v1;
|
|
|
- bool b2 = *(bool*)v2;
|
|
|
- if (!b1 && b2) return -1;
|
|
|
- if (b1 && !b2) return 1;
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-static grpc_mdstr_hash_table_vtable bool_vtable = {gpr_free, bool_copy,
|
|
|
- bool_cmp};
|
|
|
-
|
|
|
-// timespec vtable
|
|
|
-
|
|
|
-static void* timespec_copy(void* valuep) {
|
|
|
- gpr_timespec value = *(gpr_timespec*)valuep;
|
|
|
- gpr_timespec* new_value = gpr_malloc(sizeof(gpr_timespec));
|
|
|
- *new_value = value;
|
|
|
- return new_value;
|
|
|
-}
|
|
|
-
|
|
|
-static int timespec_cmp(void* v1, void* v2) {
|
|
|
- return gpr_time_cmp(*(gpr_timespec*)v1, *(gpr_timespec*)v2);
|
|
|
-}
|
|
|
-
|
|
|
-static grpc_mdstr_hash_table_vtable timespec_vtable = {gpr_free, timespec_copy,
|
|
|
- timespec_cmp};
|
|
|
-
|
|
|
-// int32 vtable
|
|
|
-
|
|
|
-static void* int32_copy(void* valuep) {
|
|
|
- int32_t value = *(int32_t*)valuep;
|
|
|
- int32_t* new_value = gpr_malloc(sizeof(int32_t));
|
|
|
- *new_value = value;
|
|
|
- return new_value;
|
|
|
-}
|
|
|
-
|
|
|
-static int int32_cmp(void* v1, void* v2) {
|
|
|
- int32_t i1 = *(int32_t*)v1;
|
|
|
- int32_t i2 = *(int32_t*)v2;
|
|
|
- if (i1 < i2) return -1;
|
|
|
- if (i1 > i2) return 1;
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-static grpc_mdstr_hash_table_vtable int32_vtable = {gpr_free, int32_copy,
|
|
|
- int32_cmp};
|
|
|
-
|
|
|
-// Hash table keys.
|
|
|
-#define GRPC_METHOD_CONFIG_WAIT_FOR_READY "grpc.wait_for_ready" // bool
|
|
|
-#define GRPC_METHOD_CONFIG_TIMEOUT "grpc.timeout" // gpr_timespec
|
|
|
-#define GRPC_METHOD_CONFIG_MAX_REQUEST_MESSAGE_BYTES \
|
|
|
- "grpc.max_request_message_bytes" // int32
|
|
|
-#define GRPC_METHOD_CONFIG_MAX_RESPONSE_MESSAGE_BYTES \
|
|
|
- "grpc.max_response_message_bytes" // int32
|
|
|
-
|
|
|
-struct grpc_method_config {
|
|
|
- grpc_mdstr_hash_table* table;
|
|
|
- grpc_mdstr* wait_for_ready_key;
|
|
|
- grpc_mdstr* timeout_key;
|
|
|
- grpc_mdstr* max_request_message_bytes_key;
|
|
|
- grpc_mdstr* max_response_message_bytes_key;
|
|
|
-};
|
|
|
-
|
|
|
-grpc_method_config* grpc_method_config_create(
|
|
|
- bool* wait_for_ready, gpr_timespec* timeout,
|
|
|
- int32_t* max_request_message_bytes, int32_t* max_response_message_bytes) {
|
|
|
- grpc_method_config* method_config = gpr_malloc(sizeof(grpc_method_config));
|
|
|
- memset(method_config, 0, sizeof(grpc_method_config));
|
|
|
- method_config->wait_for_ready_key =
|
|
|
- grpc_mdstr_from_string(GRPC_METHOD_CONFIG_WAIT_FOR_READY);
|
|
|
- method_config->timeout_key =
|
|
|
- grpc_mdstr_from_string(GRPC_METHOD_CONFIG_TIMEOUT);
|
|
|
- method_config->max_request_message_bytes_key =
|
|
|
- grpc_mdstr_from_string(GRPC_METHOD_CONFIG_MAX_REQUEST_MESSAGE_BYTES);
|
|
|
- method_config->max_response_message_bytes_key =
|
|
|
- grpc_mdstr_from_string(GRPC_METHOD_CONFIG_MAX_RESPONSE_MESSAGE_BYTES);
|
|
|
- grpc_mdstr_hash_table_entry entries[4];
|
|
|
- size_t num_entries = 0;
|
|
|
- if (wait_for_ready != NULL) {
|
|
|
- entries[num_entries].key = method_config->wait_for_ready_key;
|
|
|
- entries[num_entries].value = wait_for_ready;
|
|
|
- entries[num_entries].vtable = &bool_vtable;
|
|
|
- ++num_entries;
|
|
|
- }
|
|
|
- if (timeout != NULL) {
|
|
|
- entries[num_entries].key = method_config->timeout_key;
|
|
|
- entries[num_entries].value = timeout;
|
|
|
- entries[num_entries].vtable = ×pec_vtable;
|
|
|
- ++num_entries;
|
|
|
- }
|
|
|
- if (max_request_message_bytes != NULL) {
|
|
|
- entries[num_entries].key = method_config->max_request_message_bytes_key;
|
|
|
- entries[num_entries].value = max_request_message_bytes;
|
|
|
- entries[num_entries].vtable = &int32_vtable;
|
|
|
- ++num_entries;
|
|
|
- }
|
|
|
- if (max_response_message_bytes != NULL) {
|
|
|
- entries[num_entries].key = method_config->max_response_message_bytes_key;
|
|
|
- entries[num_entries].value = max_response_message_bytes;
|
|
|
- entries[num_entries].vtable = &int32_vtable;
|
|
|
- ++num_entries;
|
|
|
- }
|
|
|
- method_config->table = grpc_mdstr_hash_table_create(num_entries, entries);
|
|
|
- return method_config;
|
|
|
-}
|
|
|
-
|
|
|
-grpc_method_config* grpc_method_config_ref(grpc_method_config* method_config) {
|
|
|
- grpc_mdstr_hash_table_ref(method_config->table);
|
|
|
- return method_config;
|
|
|
-}
|
|
|
-
|
|
|
-void grpc_method_config_unref(grpc_method_config* method_config) {
|
|
|
- if (grpc_mdstr_hash_table_unref(method_config->table)) {
|
|
|
- GRPC_MDSTR_UNREF(method_config->wait_for_ready_key);
|
|
|
- GRPC_MDSTR_UNREF(method_config->timeout_key);
|
|
|
- GRPC_MDSTR_UNREF(method_config->max_request_message_bytes_key);
|
|
|
- GRPC_MDSTR_UNREF(method_config->max_response_message_bytes_key);
|
|
|
- gpr_free(method_config);
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-int grpc_method_config_cmp(const grpc_method_config* method_config1,
|
|
|
- const grpc_method_config* method_config2) {
|
|
|
- return grpc_mdstr_hash_table_cmp(method_config1->table,
|
|
|
- method_config2->table);
|
|
|
-}
|
|
|
-
|
|
|
-const bool* grpc_method_config_get_wait_for_ready(
|
|
|
- const grpc_method_config* method_config) {
|
|
|
- return grpc_mdstr_hash_table_get(method_config->table,
|
|
|
- method_config->wait_for_ready_key);
|
|
|
-}
|
|
|
-
|
|
|
-const gpr_timespec* grpc_method_config_get_timeout(
|
|
|
- const grpc_method_config* method_config) {
|
|
|
- return grpc_mdstr_hash_table_get(method_config->table,
|
|
|
- method_config->timeout_key);
|
|
|
-}
|
|
|
-
|
|
|
-const int32_t* grpc_method_config_get_max_request_message_bytes(
|
|
|
- const grpc_method_config* method_config) {
|
|
|
- return grpc_mdstr_hash_table_get(
|
|
|
- method_config->table, method_config->max_request_message_bytes_key);
|
|
|
-}
|
|
|
-
|
|
|
-const int32_t* grpc_method_config_get_max_response_message_bytes(
|
|
|
- const grpc_method_config* method_config) {
|
|
|
- return grpc_mdstr_hash_table_get(
|
|
|
- method_config->table, method_config->max_response_message_bytes_key);
|
|
|
-}
|
|
|
-
|
|
|
-//
|
|
|
-// grpc_method_config_table
|
|
|
-//
|
|
|
-
|
|
|
-static void method_config_unref(void* valuep) {
|
|
|
- grpc_method_config_unref(valuep);
|
|
|
-}
|
|
|
-
|
|
|
-static void* method_config_ref(void* valuep) {
|
|
|
- return grpc_method_config_ref(valuep);
|
|
|
-}
|
|
|
-
|
|
|
-static int method_config_cmp(void* valuep1, void* valuep2) {
|
|
|
- return grpc_method_config_cmp(valuep1, valuep2);
|
|
|
-}
|
|
|
-
|
|
|
-static const grpc_mdstr_hash_table_vtable method_config_table_vtable = {
|
|
|
- method_config_unref, method_config_ref, method_config_cmp};
|
|
|
-
|
|
|
-grpc_method_config_table* grpc_method_config_table_create(
|
|
|
- size_t num_entries, grpc_method_config_table_entry* entries) {
|
|
|
- grpc_mdstr_hash_table_entry* hash_table_entries =
|
|
|
- gpr_malloc(sizeof(grpc_mdstr_hash_table_entry) * num_entries);
|
|
|
- for (size_t i = 0; i < num_entries; ++i) {
|
|
|
- hash_table_entries[i].key = entries[i].method_name;
|
|
|
- hash_table_entries[i].value = entries[i].method_config;
|
|
|
- hash_table_entries[i].vtable = &method_config_table_vtable;
|
|
|
- }
|
|
|
- grpc_method_config_table* method_config_table =
|
|
|
- grpc_mdstr_hash_table_create(num_entries, hash_table_entries);
|
|
|
- gpr_free(hash_table_entries);
|
|
|
- return method_config_table;
|
|
|
-}
|
|
|
-
|
|
|
-grpc_method_config_table* grpc_method_config_table_ref(
|
|
|
- grpc_method_config_table* table) {
|
|
|
- return grpc_mdstr_hash_table_ref(table);
|
|
|
-}
|
|
|
-
|
|
|
-void grpc_method_config_table_unref(grpc_method_config_table* table) {
|
|
|
- grpc_mdstr_hash_table_unref(table);
|
|
|
-}
|
|
|
-
|
|
|
-int grpc_method_config_table_cmp(const grpc_method_config_table* table1,
|
|
|
- const grpc_method_config_table* table2) {
|
|
|
- return grpc_mdstr_hash_table_cmp(table1, table2);
|
|
|
-}
|
|
|
-
|
|
|
-void* grpc_method_config_table_get(const grpc_mdstr_hash_table* table,
|
|
|
- const grpc_mdstr* path) {
|
|
|
- void* value = grpc_mdstr_hash_table_get(table, path);
|
|
|
- // If we didn't find a match for the path, try looking for a wildcard
|
|
|
- // entry (i.e., change "/service/method" to "/service/*").
|
|
|
- if (value == NULL) {
|
|
|
- const char* path_str = grpc_mdstr_as_c_string(path);
|
|
|
- const char* sep = strrchr(path_str, '/') + 1;
|
|
|
- const size_t len = (size_t)(sep - path_str);
|
|
|
- char* buf = gpr_malloc(len + 2); // '*' and NUL
|
|
|
- memcpy(buf, path_str, len);
|
|
|
- buf[len] = '*';
|
|
|
- buf[len + 1] = '\0';
|
|
|
- grpc_mdstr* wildcard_path = grpc_mdstr_from_string(buf);
|
|
|
- gpr_free(buf);
|
|
|
- value = grpc_mdstr_hash_table_get(table, wildcard_path);
|
|
|
- GRPC_MDSTR_UNREF(wildcard_path);
|
|
|
- }
|
|
|
- return value;
|
|
|
-}
|
|
|
-
|
|
|
-static void* copy_arg(void* p) { return grpc_method_config_table_ref(p); }
|
|
|
-
|
|
|
-static void destroy_arg(void* p) { grpc_method_config_table_unref(p); }
|
|
|
-
|
|
|
-static int cmp_arg(void* p1, void* p2) {
|
|
|
- return grpc_method_config_table_cmp(p1, p2);
|
|
|
-}
|
|
|
-
|
|
|
-static grpc_arg_pointer_vtable arg_vtable = {copy_arg, destroy_arg, cmp_arg};
|
|
|
-
|
|
|
-grpc_arg grpc_method_config_table_create_channel_arg(
|
|
|
- grpc_method_config_table* table) {
|
|
|
- grpc_arg arg;
|
|
|
- arg.type = GRPC_ARG_POINTER;
|
|
|
- arg.key = GRPC_ARG_SERVICE_CONFIG;
|
|
|
- arg.value.pointer.p = table;
|
|
|
- arg.value.pointer.vtable = &arg_vtable;
|
|
|
- return arg;
|
|
|
-}
|
|
|
-
|
|
|
-// State used by convert_entry() below.
|
|
|
-typedef struct conversion_state {
|
|
|
- void* (*convert_value)(const grpc_method_config* method_config);
|
|
|
- const grpc_mdstr_hash_table_vtable* vtable;
|
|
|
- size_t num_entries;
|
|
|
- grpc_mdstr_hash_table_entry* entries;
|
|
|
-} conversion_state;
|
|
|
-
|
|
|
-// A function to be passed to grpc_mdstr_hash_table_iterate() to create
|
|
|
-// a copy of the entries.
|
|
|
-static void convert_entry(const grpc_mdstr_hash_table_entry* entry,
|
|
|
- void* user_data) {
|
|
|
- conversion_state* state = user_data;
|
|
|
- state->entries[state->num_entries].key = GRPC_MDSTR_REF(entry->key);
|
|
|
- state->entries[state->num_entries].value = state->convert_value(entry->value);
|
|
|
- state->entries[state->num_entries].vtable = state->vtable;
|
|
|
- ++state->num_entries;
|
|
|
-}
|
|
|
-
|
|
|
-grpc_mdstr_hash_table* grpc_method_config_table_convert(
|
|
|
- const grpc_method_config_table* table,
|
|
|
- void* (*convert_value)(const grpc_method_config* method_config),
|
|
|
- const grpc_mdstr_hash_table_vtable* vtable) {
|
|
|
- // Create an array of the entries in the table with converted values.
|
|
|
- conversion_state state;
|
|
|
- state.convert_value = convert_value;
|
|
|
- state.vtable = vtable;
|
|
|
- state.num_entries = 0;
|
|
|
- state.entries = gpr_malloc(sizeof(grpc_mdstr_hash_table_entry) *
|
|
|
- grpc_mdstr_hash_table_num_entries(table));
|
|
|
- grpc_mdstr_hash_table_iterate(table, convert_entry, &state);
|
|
|
- // Create a new table based on the array we just constructed.
|
|
|
- grpc_mdstr_hash_table* new_table =
|
|
|
- grpc_mdstr_hash_table_create(state.num_entries, state.entries);
|
|
|
- // Clean up the array.
|
|
|
- for (size_t i = 0; i < state.num_entries; ++i) {
|
|
|
- GRPC_MDSTR_UNREF(state.entries[i].key);
|
|
|
- vtable->destroy_value(state.entries[i].value);
|
|
|
- }
|
|
|
- gpr_free(state.entries);
|
|
|
- // Return the new table.
|
|
|
- return new_table;
|
|
|
-}
|
|
|
|
|
|
// Returns the number of names specified in the method config \a json.
|
|
|
static size_t count_names_in_method_config_json(grpc_json* json) {
|
|
@@ -435,7 +136,7 @@ grpc_mdstr_hash_table* grpc_method_config_table_create_from_json(
|
|
|
}
|
|
|
// Populate method config table entries.
|
|
|
entries =
|
|
|
- gpr_malloc(num_entries * sizeof(grpc_method_config_table_entry));
|
|
|
+ gpr_malloc(num_entries * sizeof(grpc_mdstr_hash_table_entry));
|
|
|
size_t idx = 0;
|
|
|
for (grpc_json* method = field->child; method != NULL;
|
|
|
method = method->next) {
|
|
@@ -461,6 +162,27 @@ grpc_mdstr_hash_table* grpc_method_config_table_create_from_json(
|
|
|
return method_config_table;
|
|
|
}
|
|
|
|
|
|
+void* grpc_method_config_table_get(const grpc_mdstr_hash_table* table,
|
|
|
+ const grpc_mdstr* path) {
|
|
|
+ void* value = grpc_mdstr_hash_table_get(table, path);
|
|
|
+ // If we didn't find a match for the path, try looking for a wildcard
|
|
|
+ // entry (i.e., change "/service/method" to "/service/*").
|
|
|
+ if (value == NULL) {
|
|
|
+ const char* path_str = grpc_mdstr_as_c_string(path);
|
|
|
+ const char* sep = strrchr(path_str, '/') + 1;
|
|
|
+ const size_t len = (size_t)(sep - path_str);
|
|
|
+ char* buf = gpr_malloc(len + 2); // '*' and NUL
|
|
|
+ memcpy(buf, path_str, len);
|
|
|
+ buf[len] = '*';
|
|
|
+ buf[len + 1] = '\0';
|
|
|
+ grpc_mdstr* wildcard_path = grpc_mdstr_from_string(buf);
|
|
|
+ gpr_free(buf);
|
|
|
+ value = grpc_mdstr_hash_table_get(table, wildcard_path);
|
|
|
+ GRPC_MDSTR_UNREF(wildcard_path);
|
|
|
+ }
|
|
|
+ return value;
|
|
|
+}
|
|
|
+
|
|
|
static void* copy_json_tree(void* t) { return grpc_json_tree_ref(t); }
|
|
|
|
|
|
static void destroy_json_tree(void* t) { grpc_json_tree_unref(t); }
|