2 // Copyright 2015 gRPC authors.
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
8 // http://www.apache.org/licenses/LICENSE-2.0
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
17 #include <grpc/support/port_platform.h>
19 #include "src/core/ext/filters/client_channel/service_config.h"
23 #include <grpc/impl/codegen/grpc_types.h>
24 #include <grpc/support/alloc.h>
25 #include <grpc/support/log.h>
26 #include <grpc/support/string_util.h>
28 #include "src/core/lib/gpr/string.h"
29 #include "src/core/lib/json/json.h"
30 #include "src/core/lib/slice/slice_hash_table.h"
31 #include "src/core/lib/slice/slice_internal.h"
32 #include "src/core/lib/slice/slice_string_helpers.h"
37 typedef InlinedVector<UniquePtr<ServiceConfig::Parser>,
38 ServiceConfig::kNumPreallocatedParsers>
39 ServiceConfigParserList;
40 ServiceConfigParserList* g_registered_parsers;
43 RefCountedPtr<ServiceConfig> ServiceConfig::Create(const char* json,
45 UniquePtr<char> service_config_json(gpr_strdup(json));
46 UniquePtr<char> json_string(gpr_strdup(json));
47 GPR_DEBUG_ASSERT(error != nullptr);
48 grpc_json* json_tree = grpc_json_parse_string(json_string.get());
49 if (json_tree == nullptr) {
50 *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
51 "failed to parse JSON for service config");
54 return MakeRefCounted<ServiceConfig>(
55 std::move(service_config_json), std::move(json_string), json_tree, error);
58 ServiceConfig::ServiceConfig(UniquePtr<char> service_config_json,
59 UniquePtr<char> json_string, grpc_json* json_tree,
61 : service_config_json_(std::move(service_config_json)),
62 json_string_(std::move(json_string)),
63 json_tree_(json_tree) {
64 GPR_DEBUG_ASSERT(error != nullptr);
65 if (json_tree->type != GRPC_JSON_OBJECT || json_tree->key != nullptr) {
66 *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
67 "Malformed service Config JSON object");
70 grpc_error* error_list[2];
72 grpc_error* global_error = ParseGlobalParams(json_tree);
73 grpc_error* local_error = ParsePerMethodParams(json_tree);
74 if (global_error != GRPC_ERROR_NONE) {
75 error_list[error_count++] = global_error;
77 if (local_error != GRPC_ERROR_NONE) {
78 error_list[error_count++] = local_error;
80 if (error_count > 0) {
81 *error = GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
82 "Service config parsing error", error_list, error_count);
83 GRPC_ERROR_UNREF(global_error);
84 GRPC_ERROR_UNREF(local_error);
88 grpc_error* ServiceConfig::ParseGlobalParams(const grpc_json* json_tree) {
89 GPR_DEBUG_ASSERT(json_tree_->type == GRPC_JSON_OBJECT);
90 GPR_DEBUG_ASSERT(json_tree_->key == nullptr);
91 InlinedVector<grpc_error*, 4> error_list;
92 for (size_t i = 0; i < g_registered_parsers->size(); i++) {
93 grpc_error* parser_error = GRPC_ERROR_NONE;
95 (*g_registered_parsers)[i]->ParseGlobalParams(json_tree, &parser_error);
96 if (parser_error != GRPC_ERROR_NONE) {
97 error_list.push_back(parser_error);
99 parsed_global_configs_.push_back(std::move(parsed_obj));
101 return GRPC_ERROR_CREATE_FROM_VECTOR("Global Params", &error_list);
104 grpc_error* ServiceConfig::ParseJsonMethodConfigToServiceConfigVectorTable(
105 const grpc_json* json,
106 SliceHashTable<const ParsedConfigVector*>::Entry* entries, size_t* idx) {
107 auto objs_vector = MakeUnique<ParsedConfigVector>();
108 InlinedVector<grpc_error*, 4> error_list;
109 for (size_t i = 0; i < g_registered_parsers->size(); i++) {
110 grpc_error* parser_error = GRPC_ERROR_NONE;
112 (*g_registered_parsers)[i]->ParsePerMethodParams(json, &parser_error);
113 if (parser_error != GRPC_ERROR_NONE) {
114 error_list.push_back(parser_error);
116 objs_vector->push_back(std::move(parsed_obj));
118 parsed_method_config_vectors_storage_.push_back(std::move(objs_vector));
119 const auto* vector_ptr =
120 parsed_method_config_vectors_storage_
121 [parsed_method_config_vectors_storage_.size() - 1]
123 // Construct list of paths.
124 InlinedVector<UniquePtr<char>, 10> paths;
125 for (grpc_json* child = json->child; child != nullptr; child = child->next) {
126 if (child->key == nullptr) continue;
127 if (strcmp(child->key, "name") == 0) {
128 if (child->type != GRPC_JSON_ARRAY) {
129 error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
130 "field:name error:not of type Array"));
133 for (grpc_json* name = child->child; name != nullptr; name = name->next) {
134 grpc_error* parse_error = GRPC_ERROR_NONE;
135 UniquePtr<char> path = ParseJsonMethodName(name, &parse_error);
136 if (path == nullptr) {
137 error_list.push_back(parse_error);
139 GPR_DEBUG_ASSERT(parse_error == GRPC_ERROR_NONE);
140 paths.push_back(std::move(path));
145 if (paths.size() == 0) {
146 error_list.push_back(
147 GRPC_ERROR_CREATE_FROM_STATIC_STRING("No names specified"));
149 // Add entry for each path.
150 for (size_t i = 0; i < paths.size(); ++i) {
151 entries[*idx].key = grpc_slice_from_copied_string(paths[i].get());
152 entries[*idx].value = vector_ptr;
156 return GRPC_ERROR_CREATE_FROM_VECTOR("methodConfig", &error_list);
159 grpc_error* ServiceConfig::ParsePerMethodParams(const grpc_json* json_tree) {
160 GPR_DEBUG_ASSERT(json_tree_->type == GRPC_JSON_OBJECT);
161 GPR_DEBUG_ASSERT(json_tree_->key == nullptr);
162 SliceHashTable<const ParsedConfigVector*>::Entry* entries = nullptr;
163 size_t num_entries = 0;
164 InlinedVector<grpc_error*, 4> error_list;
165 for (grpc_json* field = json_tree->child; field != nullptr;
166 field = field->next) {
167 if (field->key == nullptr) {
168 error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
169 "error:Illegal key value - NULL"));
172 if (strcmp(field->key, "methodConfig") == 0) {
173 if (entries != nullptr) {
176 if (field->type != GRPC_JSON_ARRAY) {
177 error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
178 "field:methodConfig error:not of type Array"));
180 for (grpc_json* method = field->child; method != nullptr;
181 method = method->next) {
182 int count = CountNamesInMethodConfig(method);
184 error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
185 "field:methodConfig error:No names found"));
187 num_entries += static_cast<size_t>(count);
189 entries = static_cast<SliceHashTable<const ParsedConfigVector*>::Entry*>(
190 gpr_zalloc(num_entries *
191 sizeof(SliceHashTable<const ParsedConfigVector*>::Entry)));
193 for (grpc_json* method = field->child; method != nullptr;
194 method = method->next) {
195 grpc_error* error = ParseJsonMethodConfigToServiceConfigVectorTable(
196 method, entries, &idx);
197 if (error != GRPC_ERROR_NONE) {
198 error_list.push_back(error);
201 // idx might not be equal to num_entries due to parsing errors
206 if (entries != nullptr) {
207 parsed_method_configs_table_ =
208 SliceHashTable<const ParsedConfigVector*>::Create(num_entries, entries,
212 return GRPC_ERROR_CREATE_FROM_VECTOR("Method Params", &error_list);
215 ServiceConfig::~ServiceConfig() { grpc_json_destroy(json_tree_); }
217 int ServiceConfig::CountNamesInMethodConfig(grpc_json* json) {
219 for (grpc_json* field = json->child; field != nullptr; field = field->next) {
220 if (field->key != nullptr && strcmp(field->key, "name") == 0) {
221 if (field->type != GRPC_JSON_ARRAY) return -1;
222 for (grpc_json* name = field->child; name != nullptr; name = name->next) {
223 if (name->type != GRPC_JSON_OBJECT) return -1;
231 UniquePtr<char> ServiceConfig::ParseJsonMethodName(grpc_json* json,
232 grpc_error** error) {
233 if (json->type != GRPC_JSON_OBJECT) {
234 *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
235 "field:name error:type is not object");
238 const char* service_name = nullptr;
239 const char* method_name = nullptr;
240 for (grpc_json* child = json->child; child != nullptr; child = child->next) {
241 if (child->key == nullptr) {
242 *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
243 "field:name error:Child entry with no key");
246 if (child->type != GRPC_JSON_STRING) {
247 *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
248 "field:name error:Child entry not of type string");
251 if (strcmp(child->key, "service") == 0) {
252 if (service_name != nullptr) {
253 *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
254 "field:name error: field:service error:Multiple entries");
255 return nullptr; // Duplicate.
257 if (child->value == nullptr) {
258 *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
259 "field:name error: field:service error:empty value");
262 service_name = child->value;
263 } else if (strcmp(child->key, "method") == 0) {
264 if (method_name != nullptr) {
265 *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
266 "field:name error: field:method error:multiple entries");
267 return nullptr; // Duplicate.
269 if (child->value == nullptr) {
270 *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
271 "field:name error: field:method error:empty value");
274 method_name = child->value;
277 if (service_name == nullptr) {
278 *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
279 "field:name error: field:service error:not found");
280 return nullptr; // Required field.
283 gpr_asprintf(&path, "/%s/%s", service_name,
284 method_name == nullptr ? "*" : method_name);
285 return UniquePtr<char>(path);
288 const ServiceConfig::ParsedConfigVector*
289 ServiceConfig::GetMethodParsedConfigVector(const grpc_slice& path) {
290 if (parsed_method_configs_table_.get() == nullptr) {
293 const auto* value = parsed_method_configs_table_->Get(path);
294 // If we didn't find a match for the path, try looking for a wildcard
295 // entry (i.e., change "/service/method" to "/service/*").
296 if (value == nullptr) {
297 char* path_str = grpc_slice_to_c_string(path);
298 const char* sep = strrchr(path_str, '/') + 1;
299 const size_t len = (size_t)(sep - path_str);
300 char* buf = (char*)gpr_malloc(len + 2); // '*' and NUL
301 memcpy(buf, path_str, len);
304 grpc_slice wildcard_path = grpc_slice_from_copied_string(buf);
306 value = parsed_method_configs_table_->Get(wildcard_path);
307 grpc_slice_unref_internal(wildcard_path);
309 if (value == nullptr) return nullptr;
314 size_t ServiceConfig::RegisterParser(UniquePtr<Parser> parser) {
315 g_registered_parsers->push_back(std::move(parser));
316 return g_registered_parsers->size() - 1;
319 void ServiceConfig::Init() {
320 GPR_ASSERT(g_registered_parsers == nullptr);
321 g_registered_parsers = New<ServiceConfigParserList>();
324 void ServiceConfig::Shutdown() {
325 Delete(g_registered_parsers);
326 g_registered_parsers = nullptr;
329 } // namespace grpc_core