|
|
|
@ -33,7 +33,31 @@ |
|
|
|
|
|
|
|
|
|
namespace grpc_core { |
|
|
|
|
|
|
|
|
|
ServiceConfig::ServiceConfigParserList* ServiceConfig::registered_parsers_; |
|
|
|
|
namespace { |
|
|
|
|
typedef InlinedVector<UniquePtr<ServiceConfigParser>, |
|
|
|
|
ServiceConfig::kNumPreallocatedParsers> |
|
|
|
|
ServiceConfigParserList; |
|
|
|
|
ServiceConfigParserList* registered_parsers; |
|
|
|
|
|
|
|
|
|
// Consumes all the errors in the vector and forms a referencing error from
|
|
|
|
|
// them. If the vector is empty, return GRPC_ERROR_NONE.
|
|
|
|
|
template <size_t N> |
|
|
|
|
grpc_error* CreateErrorFromVector(const char* desc, |
|
|
|
|
InlinedVector<grpc_error*, N>* error_list) { |
|
|
|
|
grpc_error* error = GRPC_ERROR_NONE; |
|
|
|
|
if (error_list->size() != 0) { |
|
|
|
|
error = GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING( |
|
|
|
|
desc, error_list->data(), error_list->size()); |
|
|
|
|
// Remove refs to all errors in error_list.
|
|
|
|
|
for (size_t i = 0; i < error_list->size(); i++) { |
|
|
|
|
GRPC_ERROR_UNREF((*error_list)[i]); |
|
|
|
|
} |
|
|
|
|
error_list->clear(); |
|
|
|
|
} |
|
|
|
|
return error; |
|
|
|
|
} |
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
|
|
RefCountedPtr<ServiceConfig> ServiceConfig::Create(const char* json, |
|
|
|
|
grpc_error** error) { |
|
|
|
|
UniquePtr<char> service_config_json(gpr_strdup(json)); |
|
|
|
@ -62,22 +86,38 @@ ServiceConfig::ServiceConfig(UniquePtr<char> service_config_json, |
|
|
|
|
"Malformed service Config JSON object"); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
*error = ParseGlobalParams(json_tree); |
|
|
|
|
*error = grpc_error_add_child(*error, ParsePerMethodParams(json_tree)); |
|
|
|
|
grpc_error* error_list[2]; |
|
|
|
|
int error_count = 0; |
|
|
|
|
grpc_error* global_error = ParseGlobalParams(json_tree); |
|
|
|
|
grpc_error* local_error = ParsePerMethodParams(json_tree); |
|
|
|
|
if (global_error != GRPC_ERROR_NONE) { |
|
|
|
|
error_list[error_count++] = global_error; |
|
|
|
|
} |
|
|
|
|
if (local_error != GRPC_ERROR_NONE) { |
|
|
|
|
error_list[error_count++] = local_error; |
|
|
|
|
} |
|
|
|
|
if (error_count > 0) { |
|
|
|
|
*error = GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING( |
|
|
|
|
"Service config parsing error", error_list, error_count); |
|
|
|
|
GRPC_ERROR_UNREF(global_error); |
|
|
|
|
GRPC_ERROR_UNREF(local_error); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
grpc_error* ServiceConfig::ParseGlobalParams(const grpc_json* json_tree) { |
|
|
|
|
GPR_DEBUG_ASSERT(json_tree_->type == GRPC_JSON_OBJECT); |
|
|
|
|
GPR_DEBUG_ASSERT(json_tree_->key == nullptr); |
|
|
|
|
grpc_error* error = GRPC_ERROR_NONE; |
|
|
|
|
for (size_t i = 0; i < registered_parsers_->size(); i++) { |
|
|
|
|
InlinedVector<grpc_error*, 4> error_list; |
|
|
|
|
for (size_t i = 0; i < registered_parsers->size(); i++) { |
|
|
|
|
grpc_error* parser_error = GRPC_ERROR_NONE; |
|
|
|
|
auto parsed_obj = |
|
|
|
|
(*registered_parsers_)[i]->ParseGlobalParams(json_tree, &parser_error); |
|
|
|
|
error = grpc_error_add_child(error, parser_error); |
|
|
|
|
(*registered_parsers)[i]->ParseGlobalParams(json_tree, &parser_error); |
|
|
|
|
if (parser_error != GRPC_ERROR_NONE) { |
|
|
|
|
error_list.push_back(parser_error); |
|
|
|
|
} |
|
|
|
|
parsed_global_service_config_objects_.push_back(std::move(parsed_obj)); |
|
|
|
|
} |
|
|
|
|
return error; |
|
|
|
|
return CreateErrorFromVector("Global Params", &error_list); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
grpc_error* ServiceConfig::ParseJsonMethodConfigToServiceConfigObjectsTable( |
|
|
|
@ -85,12 +125,14 @@ grpc_error* ServiceConfig::ParseJsonMethodConfigToServiceConfigObjectsTable( |
|
|
|
|
SliceHashTable<const ServiceConfigObjectsVector*>::Entry* entries, |
|
|
|
|
size_t* idx) { |
|
|
|
|
auto objs_vector = MakeUnique<ServiceConfigObjectsVector>(); |
|
|
|
|
grpc_error* error = GRPC_ERROR_NONE; |
|
|
|
|
for (size_t i = 0; i < registered_parsers_->size(); i++) { |
|
|
|
|
InlinedVector<grpc_error*, 4> error_list; |
|
|
|
|
for (size_t i = 0; i < registered_parsers->size(); i++) { |
|
|
|
|
grpc_error* parser_error = GRPC_ERROR_NONE; |
|
|
|
|
auto parsed_obj = |
|
|
|
|
(*registered_parsers_)[i]->ParsePerMethodParams(json, &error); |
|
|
|
|
error = grpc_error_add_child(error, parser_error); |
|
|
|
|
(*registered_parsers)[i]->ParsePerMethodParams(json, &parser_error); |
|
|
|
|
if (parser_error != GRPC_ERROR_NONE) { |
|
|
|
|
error_list.push_back(parser_error); |
|
|
|
|
} |
|
|
|
|
objs_vector->push_back(std::move(parsed_obj)); |
|
|
|
|
} |
|
|
|
|
const auto* vector_ptr = objs_vector.get(); |
|
|
|
@ -101,16 +143,15 @@ grpc_error* ServiceConfig::ParseJsonMethodConfigToServiceConfigObjectsTable( |
|
|
|
|
if (child->key == nullptr) continue; |
|
|
|
|
if (strcmp(child->key, "name") == 0) { |
|
|
|
|
if (child->type != GRPC_JSON_ARRAY) { |
|
|
|
|
error = grpc_error_add_child(error, |
|
|
|
|
GRPC_ERROR_CREATE_FROM_STATIC_STRING( |
|
|
|
|
"field:name error:not of type Array")); |
|
|
|
|
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( |
|
|
|
|
"field:name error:not of type Array")); |
|
|
|
|
goto wrap_error; |
|
|
|
|
} |
|
|
|
|
for (grpc_json* name = child->child; name != nullptr; name = name->next) { |
|
|
|
|
grpc_error* parse_error = GRPC_ERROR_NONE; |
|
|
|
|
UniquePtr<char> path = ParseJsonMethodName(name, &parse_error); |
|
|
|
|
if (path == nullptr) { |
|
|
|
|
error = grpc_error_add_child(error, parse_error); |
|
|
|
|
error_list.push_back(parse_error); |
|
|
|
|
} else { |
|
|
|
|
GPR_DEBUG_ASSERT(parse_error == GRPC_ERROR_NONE); |
|
|
|
|
} |
|
|
|
@ -119,21 +160,17 @@ grpc_error* ServiceConfig::ParseJsonMethodConfigToServiceConfigObjectsTable( |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
if (paths.size() == 0) { |
|
|
|
|
error = grpc_error_add_child( |
|
|
|
|
error, GRPC_ERROR_CREATE_FROM_STATIC_STRING("No names specified")); |
|
|
|
|
error_list.push_back( |
|
|
|
|
GRPC_ERROR_CREATE_FROM_STATIC_STRING("No names specified")); |
|
|
|
|
} |
|
|
|
|
// Add entry for each path.
|
|
|
|
|
for (size_t i = 0; i < paths.size(); ++i) { |
|
|
|
|
entries[*idx].key = grpc_slice_from_copied_string(paths[i].get()); |
|
|
|
|
entries[*idx].value = vector_ptr; // Takes a new ref.
|
|
|
|
|
entries[*idx].value = vector_ptr; |
|
|
|
|
++*idx; |
|
|
|
|
} |
|
|
|
|
wrap_error: |
|
|
|
|
if (error != GRPC_ERROR_NONE) { |
|
|
|
|
error = grpc_error_add_child( |
|
|
|
|
GRPC_ERROR_CREATE_FROM_STATIC_STRING("field:methodConfig"), error); |
|
|
|
|
} |
|
|
|
|
return error; |
|
|
|
|
return CreateErrorFromVector("methodConfig", &error_list); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
grpc_error* ServiceConfig::ParsePerMethodParams(const grpc_json* json_tree) { |
|
|
|
@ -141,13 +178,12 @@ grpc_error* ServiceConfig::ParsePerMethodParams(const grpc_json* json_tree) { |
|
|
|
|
GPR_DEBUG_ASSERT(json_tree_->key == nullptr); |
|
|
|
|
SliceHashTable<const ServiceConfigObjectsVector*>::Entry* entries = nullptr; |
|
|
|
|
size_t num_entries = 0; |
|
|
|
|
grpc_error* error = GRPC_ERROR_NONE; |
|
|
|
|
InlinedVector<grpc_error*, 4> error_list; |
|
|
|
|
for (grpc_json* field = json_tree->child; field != nullptr; |
|
|
|
|
field = field->next) { |
|
|
|
|
if (field->key == nullptr) { |
|
|
|
|
error = |
|
|
|
|
grpc_error_add_child(error, GRPC_ERROR_CREATE_FROM_STATIC_STRING( |
|
|
|
|
"error:Illegal key value - NULL")); |
|
|
|
|
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( |
|
|
|
|
"error:Illegal key value - NULL")); |
|
|
|
|
continue; |
|
|
|
|
} |
|
|
|
|
if (strcmp(field->key, "methodConfig") == 0) { |
|
|
|
@ -155,17 +191,15 @@ grpc_error* ServiceConfig::ParsePerMethodParams(const grpc_json* json_tree) { |
|
|
|
|
GPR_ASSERT(false); |
|
|
|
|
} |
|
|
|
|
if (field->type != GRPC_JSON_ARRAY) { |
|
|
|
|
return grpc_error_add_child( |
|
|
|
|
error, GRPC_ERROR_CREATE_FROM_STATIC_STRING( |
|
|
|
|
"field:methodConfig error:not of type Array")); |
|
|
|
|
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( |
|
|
|
|
"field:methodConfig error:not of type Array")); |
|
|
|
|
} |
|
|
|
|
for (grpc_json* method = field->child; method != nullptr; |
|
|
|
|
method = method->next) { |
|
|
|
|
int count = CountNamesInMethodConfig(method); |
|
|
|
|
if (count <= 0) { |
|
|
|
|
error = grpc_error_add_child( |
|
|
|
|
error, GRPC_ERROR_CREATE_FROM_STATIC_STRING( |
|
|
|
|
"field:methodConfig error:No names found")); |
|
|
|
|
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( |
|
|
|
|
"field:methodConfig error:No names found")); |
|
|
|
|
} |
|
|
|
|
num_entries += static_cast<size_t>(count); |
|
|
|
|
} |
|
|
|
@ -176,9 +210,11 @@ grpc_error* ServiceConfig::ParsePerMethodParams(const grpc_json* json_tree) { |
|
|
|
|
size_t idx = 0; |
|
|
|
|
for (grpc_json* method = field->child; method != nullptr; |
|
|
|
|
method = method->next) { |
|
|
|
|
error = grpc_error_add_child( |
|
|
|
|
error, ParseJsonMethodConfigToServiceConfigObjectsTable( |
|
|
|
|
method, entries, &idx)); |
|
|
|
|
grpc_error* error = ParseJsonMethodConfigToServiceConfigObjectsTable( |
|
|
|
|
method, entries, &idx); |
|
|
|
|
if (error != GRPC_ERROR_NONE) { |
|
|
|
|
error_list.push_back(error); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
GPR_DEBUG_ASSERT(num_entries == idx); |
|
|
|
|
break; |
|
|
|
@ -190,7 +226,7 @@ grpc_error* ServiceConfig::ParsePerMethodParams(const grpc_json* json_tree) { |
|
|
|
|
num_entries, entries, nullptr); |
|
|
|
|
gpr_free(entries); |
|
|
|
|
} |
|
|
|
|
return error; |
|
|
|
|
return CreateErrorFromVector("Method Params", &error_list); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
ServiceConfig::~ServiceConfig() { grpc_json_destroy(json_tree_); } |
|
|
|
@ -230,50 +266,51 @@ UniquePtr<char> ServiceConfig::ParseJsonMethodName(grpc_json* json, |
|
|
|
|
grpc_error** error) { |
|
|
|
|
if (json->type != GRPC_JSON_OBJECT) { |
|
|
|
|
*error = GRPC_ERROR_CREATE_FROM_STATIC_STRING( |
|
|
|
|
"Field name should be of type object"); |
|
|
|
|
"field:name error:type is not object"); |
|
|
|
|
return nullptr; |
|
|
|
|
} |
|
|
|
|
const char* service_name = nullptr; |
|
|
|
|
const char* method_name = nullptr; |
|
|
|
|
for (grpc_json* child = json->child; child != nullptr; child = child->next) { |
|
|
|
|
if (child->key == nullptr) { |
|
|
|
|
*error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Child entry with no key"); |
|
|
|
|
*error = GRPC_ERROR_CREATE_FROM_STATIC_STRING( |
|
|
|
|
"field:name error:Child entry with no key"); |
|
|
|
|
return nullptr; |
|
|
|
|
} |
|
|
|
|
if (child->type != GRPC_JSON_STRING) { |
|
|
|
|
*error = GRPC_ERROR_CREATE_FROM_STATIC_STRING( |
|
|
|
|
"Child entry should of type string"); |
|
|
|
|
"field:name error:Child entry not of type string"); |
|
|
|
|
return nullptr; |
|
|
|
|
} |
|
|
|
|
if (strcmp(child->key, "service") == 0) { |
|
|
|
|
if (service_name != nullptr) { |
|
|
|
|
*error = GRPC_ERROR_CREATE_FROM_STATIC_STRING( |
|
|
|
|
"field:service error:Multiple entries"); |
|
|
|
|
"field:name error: field:service error:Multiple entries"); |
|
|
|
|
return nullptr; // Duplicate.
|
|
|
|
|
} |
|
|
|
|
if (child->value == nullptr) { |
|
|
|
|
*error = GRPC_ERROR_CREATE_FROM_STATIC_STRING( |
|
|
|
|
"field:service error:empty value"); |
|
|
|
|
"field:name error: field:service error:empty value"); |
|
|
|
|
return nullptr; |
|
|
|
|
} |
|
|
|
|
service_name = child->value; |
|
|
|
|
} else if (strcmp(child->key, "method") == 0) { |
|
|
|
|
if (method_name != nullptr) { |
|
|
|
|
*error = GRPC_ERROR_CREATE_FROM_STATIC_STRING( |
|
|
|
|
"field:method error:multiple entries"); |
|
|
|
|
"field:name error: field:method error:multiple entries"); |
|
|
|
|
return nullptr; // Duplicate.
|
|
|
|
|
} |
|
|
|
|
if (child->value == nullptr) { |
|
|
|
|
*error = GRPC_ERROR_CREATE_FROM_STATIC_STRING( |
|
|
|
|
"field:method error:empty value"); |
|
|
|
|
"field:name error: field:method error:empty value"); |
|
|
|
|
return nullptr; |
|
|
|
|
} |
|
|
|
|
method_name = child->value; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
if (service_name == nullptr) { |
|
|
|
|
*error = |
|
|
|
|
GRPC_ERROR_CREATE_FROM_STATIC_STRING("field:service error:not found"); |
|
|
|
|
*error = GRPC_ERROR_CREATE_FROM_STATIC_STRING( |
|
|
|
|
"field:name error: field:service error:not found"); |
|
|
|
|
return nullptr; // Required field.
|
|
|
|
|
} |
|
|
|
|
char* path; |
|
|
|
@ -305,4 +342,19 @@ ServiceConfig::GetMethodServiceConfigObjectsVector(const grpc_slice& path) { |
|
|
|
|
return value; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
int ServiceConfig::RegisterParser(UniquePtr<ServiceConfigParser> parser) { |
|
|
|
|
registered_parsers->push_back(std::move(parser)); |
|
|
|
|
return registered_parsers->size() - 1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void ServiceConfig::Init() { |
|
|
|
|
GPR_ASSERT(registered_parsers == nullptr); |
|
|
|
|
registered_parsers = New<ServiceConfigParserList>(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void ServiceConfig::Shutdown() { |
|
|
|
|
Delete(registered_parsers); |
|
|
|
|
registered_parsers = nullptr; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} // namespace grpc_core
|
|
|
|
|