mirror of https://github.com/grpc/grpc.git
commit
4b064060f7
194 changed files with 8638 additions and 1489 deletions
@ -1,340 +0,0 @@ |
|||||||
//
|
|
||||||
// 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/method_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 <grpc/support/time.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; |
|
||||||
} |
|
@ -1,136 +0,0 @@ |
|||||||
//
|
|
||||||
// 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_METHOD_CONFIG_H |
|
||||||
#define GRPC_CORE_LIB_TRANSPORT_METHOD_CONFIG_H |
|
||||||
|
|
||||||
#include <stdbool.h> |
|
||||||
|
|
||||||
#include <grpc/impl/codegen/gpr_types.h> |
|
||||||
#include <grpc/impl/codegen/grpc_types.h> |
|
||||||
|
|
||||||
#include "src/core/lib/transport/mdstr_hash_table.h" |
|
||||||
#include "src/core/lib/transport/metadata.h" |
|
||||||
|
|
||||||
/// Per-method configuration.
|
|
||||||
typedef struct grpc_method_config grpc_method_config; |
|
||||||
|
|
||||||
/// Creates a grpc_method_config with the specified parameters.
|
|
||||||
/// Any parameter may be NULL to indicate that the value is unset.
|
|
||||||
///
|
|
||||||
/// \a wait_for_ready indicates whether the client should wait until the
|
|
||||||
/// request deadline for the channel to become ready, even if there is a
|
|
||||||
/// temporary failure before the deadline while attempting to connect.
|
|
||||||
///
|
|
||||||
/// \a timeout indicates the timeout for calls.
|
|
||||||
///
|
|
||||||
/// \a max_request_message_bytes and \a max_response_message_bytes
|
|
||||||
/// indicate the maximum sizes of the request (checked when sending) and
|
|
||||||
/// response (checked when receiving) messages.
|
|
||||||
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* grpc_method_config_ref(grpc_method_config* method_config); |
|
||||||
void grpc_method_config_unref(grpc_method_config* method_config); |
|
||||||
|
|
||||||
/// Compares two grpc_method_configs.
|
|
||||||
/// The sort order is stable but undefined.
|
|
||||||
int grpc_method_config_cmp(const grpc_method_config* method_config1, |
|
||||||
const grpc_method_config* method_config2); |
|
||||||
|
|
||||||
/// These methods return NULL if the requested field is unset.
|
|
||||||
/// The caller does NOT take ownership of the result.
|
|
||||||
const bool* grpc_method_config_get_wait_for_ready( |
|
||||||
const grpc_method_config* method_config); |
|
||||||
const gpr_timespec* grpc_method_config_get_timeout( |
|
||||||
const grpc_method_config* method_config); |
|
||||||
const int32_t* grpc_method_config_get_max_request_message_bytes( |
|
||||||
const grpc_method_config* method_config); |
|
||||||
const int32_t* grpc_method_config_get_max_response_message_bytes( |
|
||||||
const grpc_method_config* method_config); |
|
||||||
|
|
||||||
/// A table of method configs.
|
|
||||||
typedef grpc_mdstr_hash_table grpc_method_config_table; |
|
||||||
|
|
||||||
typedef struct grpc_method_config_table_entry { |
|
||||||
/// The name is of one of the following forms:
|
|
||||||
/// service/method -- specifies exact service and method name
|
|
||||||
/// service/* -- matches all methods for the specified service
|
|
||||||
grpc_mdstr* method_name; |
|
||||||
grpc_method_config* method_config; |
|
||||||
} grpc_method_config_table_entry; |
|
||||||
|
|
||||||
/// Takes new references to all keys and values in \a entries.
|
|
||||||
grpc_method_config_table* grpc_method_config_table_create( |
|
||||||
size_t num_entries, grpc_method_config_table_entry* entries); |
|
||||||
|
|
||||||
grpc_method_config_table* grpc_method_config_table_ref( |
|
||||||
grpc_method_config_table* table); |
|
||||||
void grpc_method_config_table_unref(grpc_method_config_table* table); |
|
||||||
|
|
||||||
/// Compares two grpc_method_config_tables.
|
|
||||||
/// The sort order is stable but undefined.
|
|
||||||
int grpc_method_config_table_cmp(const grpc_method_config_table* table1, |
|
||||||
const grpc_method_config_table* table2); |
|
||||||
|
|
||||||
/// 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.
|
|
||||||
///
|
|
||||||
/// Note: This returns a void* instead of a grpc_method_config* so that
|
|
||||||
/// it can also be used for tables constructed via
|
|
||||||
/// grpc_method_config_table_convert().
|
|
||||||
void* grpc_method_config_table_get(const grpc_mdstr_hash_table* table, |
|
||||||
const grpc_mdstr* path); |
|
||||||
|
|
||||||
/// Returns a channel arg containing \a table.
|
|
||||||
grpc_arg grpc_method_config_table_create_channel_arg( |
|
||||||
grpc_method_config_table* table); |
|
||||||
|
|
||||||
/// Generates a new table from \a table whose values are converted to a
|
|
||||||
/// new form via the \a convert_value function. The new table will use
|
|
||||||
/// \a vtable for its values.
|
|
||||||
///
|
|
||||||
/// This is generally used to convert the table's value type from
|
|
||||||
/// grpc_method_config to a simple struct containing only the parameters
|
|
||||||
/// relevant to a particular filter, thus avoiding the need for a hash
|
|
||||||
/// table lookup on the fast path. In that scenario, \a convert_value
|
|
||||||
/// will return a new instance of the struct containing the values from
|
|
||||||
/// the grpc_method_config, and \a vtable provides the methods for
|
|
||||||
/// operating on the struct type.
|
|
||||||
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); |
|
||||||
|
|
||||||
#endif /* GRPC_CORE_LIB_TRANSPORT_METHOD_CONFIG_H */ |
|
@ -0,0 +1,249 @@ |
|||||||
|
//
|
||||||
|
// 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/support/string.h" |
||||||
|
#include "src/core/lib/transport/mdstr_hash_table.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_json* json, void* (*create_value)(const grpc_json* method_config_json), |
||||||
|
const grpc_mdstr_hash_table_vtable* vtable, |
||||||
|
grpc_mdstr_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_mdstr_from_string(paths.strs[i]); |
||||||
|
entries[*idx].value = vtable->copy_value(method_config); |
||||||
|
entries[*idx].vtable = vtable; |
||||||
|
++*idx; |
||||||
|
} |
||||||
|
success = true; |
||||||
|
done: |
||||||
|
vtable->destroy_value(method_config); |
||||||
|
gpr_strvec_destroy(&paths); |
||||||
|
return success; |
||||||
|
} |
||||||
|
|
||||||
|
grpc_mdstr_hash_table* grpc_service_config_create_method_config_table( |
||||||
|
const grpc_service_config* service_config, |
||||||
|
void* (*create_value)(const grpc_json* method_config_json), |
||||||
|
const grpc_mdstr_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_mdstr_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_mdstr_hash_table_entry)); |
||||||
|
size_t idx = 0; |
||||||
|
for (grpc_json* method = field->child; method != NULL; |
||||||
|
method = method->next) { |
||||||
|
if (!parse_json_method_config(method, create_value, vtable, entries, |
||||||
|
&idx)) { |
||||||
|
return NULL; |
||||||
|
} |
||||||
|
} |
||||||
|
GPR_ASSERT(idx == num_entries); |
||||||
|
} |
||||||
|
} |
||||||
|
// Instantiate method config table.
|
||||||
|
grpc_mdstr_hash_table* method_config_table = NULL; |
||||||
|
if (entries != NULL) { |
||||||
|
method_config_table = grpc_mdstr_hash_table_create(num_entries, entries); |
||||||
|
// Clean up.
|
||||||
|
for (size_t i = 0; i < num_entries; ++i) { |
||||||
|
GRPC_MDSTR_UNREF(entries[i].key); |
||||||
|
vtable->destroy_value(entries[i].value); |
||||||
|
} |
||||||
|
gpr_free(entries); |
||||||
|
} |
||||||
|
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; |
||||||
|
} |
@ -0,0 +1,70 @@ |
|||||||
|
//
|
||||||
|
// 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/transport/mdstr_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_mdstr_hash_table* grpc_service_config_create_method_config_table( |
||||||
|
const grpc_service_config* service_config, |
||||||
|
void* (*create_value)(const grpc_json* method_config_json), |
||||||
|
const grpc_mdstr_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(const grpc_mdstr_hash_table* table, |
||||||
|
const grpc_mdstr* path); |
||||||
|
|
||||||
|
#endif /* GRPC_CORE_LIB_TRANSPORT_SERVICE_CONFIG_H */ |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue