diff --git a/src/core/ext/filters/client_channel/service_config.cc b/src/core/ext/filters/client_channel/service_config.cc index 49b45b0e27f..e01eb11fe98 100644 --- a/src/core/ext/filters/client_channel/service_config.cc +++ b/src/core/ext/filters/client_channel/service_config.cc @@ -35,7 +35,7 @@ namespace grpc_core { int ServiceConfig::registered_parsers_count = 0; UniquePtr - ServiceConfig::registered_parsers[ServiceConfig::kMaxParsers]; + ServiceConfig::registered_parsers[ServiceConfigParser::kMaxParsers]; RefCountedPtr ServiceConfig::Create(const char* json) { UniquePtr service_config_json(gpr_strdup(json)); @@ -45,15 +45,155 @@ RefCountedPtr ServiceConfig::Create(const char* json) { gpr_log(GPR_INFO, "failed to parse JSON for service config"); return nullptr; } - return MakeRefCounted(std::move(service_config_json), - std::move(json_string), json_tree); + bool success; + auto return_value = MakeRefCounted( + std::move(service_config_json), std::move(json_string), json_tree, + &success); + + // return return_value; + return success ? return_value : nullptr; } ServiceConfig::ServiceConfig(UniquePtr service_config_json, - UniquePtr json_string, grpc_json* json_tree) + UniquePtr json_string, grpc_json* json_tree, + bool* success) : service_config_json_(std::move(service_config_json)), json_string_(std::move(json_string)), - json_tree_(json_tree) {} + json_tree_(json_tree) { + GPR_DEBUG_ASSERT(success != nullptr); + if (json_tree->type != GRPC_JSON_OBJECT || json_tree->key != nullptr) { + gpr_log(GPR_ERROR, "error"); + *success = false; + return; + } + ParseGlobalParams(json_tree, success); + if (!*success) { + gpr_log(GPR_ERROR, "global error"); + return; + } + ParsePerMethodParams(json_tree, success); + if (!*success) { + gpr_log(GPR_ERROR, "local error"); + return; + } +} + +void ServiceConfig::ParseGlobalParams(const grpc_json* json_tree, + bool* success) { + GPR_DEBUG_ASSERT(success != nullptr); + GPR_DEBUG_ASSERT(json_tree_->type == GRPC_JSON_OBJECT); + GPR_DEBUG_ASSERT(json_tree_->key == nullptr); + for (auto i = 0; i < registered_parsers_count; i++) { + auto parsed_obj = + registered_parsers[i]->ParseGlobalParams(json_tree, success); + if (!*success) { + return; + } + parsed_global_service_config_objects.push_back(parsed_obj); + } + *success = true; +} + +bool ServiceConfig::ParseJsonMethodConfigToServiceConfigObjectsTable( + const grpc_json* json, + SliceHashTable>::Entry* entries, + size_t* idx) { + auto objs_vector = MakeRefCounted(); + for (auto i = 0; i < registered_parsers_count; i++) { + bool success; + auto parsed_obj = + registered_parsers[i]->ParsePerMethodParams(json, &success); + if (!success) { + return false; + } + objs_vector->vector.push_back(parsed_obj); + } + // Construct list of paths. + InlinedVector, 10> paths; + for (grpc_json* child = json->child; child != nullptr; child = child->next) { + if (child->key == nullptr) continue; + if (strcmp(child->key, "name") == 0) { + if (child->type != GRPC_JSON_ARRAY) return false; + for (grpc_json* name = child->child; name != nullptr; name = name->next) { + UniquePtr path = ParseJsonMethodName(name); + if (path == nullptr) return false; + paths.push_back(std::move(path)); + } + } + } + if (paths.size() == 0) return false; // 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 = objs_vector; // Takes a new ref. + ++*idx; + } + return true; +} + +void ServiceConfig::ParsePerMethodParams(const grpc_json* json_tree, + bool* success) { + GPR_DEBUG_ASSERT(success != nullptr); + GPR_DEBUG_ASSERT(json_tree_->type == GRPC_JSON_OBJECT); + GPR_DEBUG_ASSERT(json_tree_->key == nullptr); + SliceHashTable>::Entry* entries = + nullptr; + size_t num_entries = 0; + for (grpc_json* field = json_tree->child; field != nullptr; + field = field->next) { + if (field->key == nullptr) { + *success = false; + return; + } + if (strcmp(field->key, "methodConfig") == 0) { + if (entries != nullptr) { + GPR_ASSERT(false); + } + if (field->type != GRPC_JSON_ARRAY) { + *success = false; + return; + } + for (grpc_json* method = field->child; method != nullptr; + method = method->next) { + int count = CountNamesInMethodConfig(method); + if (count <= 0) { + *success = false; + return; + } + num_entries += static_cast(count); + } + entries = static_cast< + SliceHashTable>::Entry*>( + gpr_zalloc( + num_entries * + sizeof(SliceHashTable< + RefCountedPtr>::Entry))); + size_t idx = 0; + for (grpc_json* method = field->child; method != nullptr; + method = method->next) { + if (!ParseJsonMethodConfigToServiceConfigObjectsTable(method, entries, + &idx)) { + for (size_t i = 0; i < idx; ++i) { + grpc_slice_unref_internal(entries[i].key); + entries[i].value.reset(); + } + gpr_free(entries); + *success = false; + return; + } + } + GPR_DEBUG_ASSERT(idx == num_entries); + break; + } + } + if (entries != nullptr) { + parsed_method_service_config_objects_table = + SliceHashTable>::Create( + num_entries, entries, nullptr); + gpr_free(entries); + } + *success = true; +} ServiceConfig::~ServiceConfig() { grpc_json_destroy(json_tree_); } diff --git a/src/core/ext/filters/client_channel/service_config.h b/src/core/ext/filters/client_channel/service_config.h index 5caf420ff9d..acf618b3432 100644 --- a/src/core/ext/filters/client_channel/service_config.h +++ b/src/core/ext/filters/client_channel/service_config.h @@ -56,7 +56,7 @@ namespace grpc_core { /// This is the base class that all service config parsers MUST use to store /// parsed service config data. -class ServiceConfigParsedObject { +class ServiceConfigParsedObject : public RefCounted { public: virtual ~ServiceConfigParsedObject() = default; @@ -68,19 +68,35 @@ class ServiceConfigParser { public: virtual ~ServiceConfigParser() = default; - virtual UniquePtr ParseGlobalParams( - const grpc_json* json) { + virtual RefCountedPtr ParseGlobalParams( + const grpc_json* json, bool* success) { + if (success != nullptr) { + *success = true; + } return nullptr; } - virtual UniquePtr ParsePerMethodParams( - const grpc_json* json) { + virtual RefCountedPtr ParsePerMethodParams( + const grpc_json* json, bool* success) { + if (success != nullptr) { + *success = true; + } return nullptr; } + static constexpr int kMaxParsers = 32; + GRPC_ABSTRACT_BASE_CLASS; }; +class ServiceConfigObjectsVector + : public RefCounted { + public: + grpc_core::InlinedVector, + ServiceConfigParser::kMaxParsers> + vector; +}; + class ServiceConfig : public RefCounted { public: /// Creates a new service config from parsing \a json_string. @@ -129,12 +145,9 @@ class ServiceConfig : public RefCounted { return parsed_global_service_config_objects[index].get(); } - static constexpr int kMaxParsers = 32; - /// Retrieves the vector of method service config objects for a given path \a /// path. - const grpc_core::InlinedVector, - kMaxParsers>* + const RefCountedPtr* GetMethodServiceConfigObjectsVector(const grpc_slice& path) { const auto* value = parsed_method_service_config_objects_table->Get(path); // If we didn't find a match for the path, try looking for a wildcard @@ -169,7 +182,7 @@ class ServiceConfig : public RefCounted { } static void ResetServiceConfigParsers() { - for (auto i = 0; i < kMaxParsers; i++) { + for (auto i = 0; i < ServiceConfigParser::kMaxParsers; i++) { registered_parsers[i].reset(nullptr); } registered_parsers_count = 0; @@ -182,7 +195,11 @@ class ServiceConfig : public RefCounted { // Takes ownership of \a json_tree. ServiceConfig(UniquePtr service_config_json, - UniquePtr json_string, grpc_json* json_tree); + UniquePtr json_string, grpc_json* json_tree, + bool* success); + + void ParseGlobalParams(const grpc_json* json_tree, bool* success); + void ParsePerMethodParams(const grpc_json* json_tree, bool* success); // Returns the number of names specified in the method config \a json. static int CountNamesInMethodConfig(grpc_json* json); @@ -199,17 +216,23 @@ class ServiceConfig : public RefCounted { grpc_json* json, CreateValue create_value, typename SliceHashTable>::Entry* entries, size_t* idx); + static bool ParseJsonMethodConfigToServiceConfigObjectsTable( + const grpc_json* json, + SliceHashTable>::Entry* entries, + size_t* idx); + static int registered_parsers_count; - static UniquePtr registered_parsers[kMaxParsers]; + static UniquePtr + registered_parsers[ServiceConfigParser::kMaxParsers]; UniquePtr service_config_json_; UniquePtr json_string_; // Underlying storage for json_tree. grpc_json* json_tree_; - InlinedVector, kMaxParsers> + InlinedVector, + ServiceConfigParser::kMaxParsers> parsed_global_service_config_objects; - RefCountedPtr, kMaxParsers>>> + RefCountedPtr>> parsed_method_service_config_objects_table; };