Built motion from commit 6a09e18b.|2.6.11
[motion2.git] / legacy-libs / grpc / deps / grpc / src / core / ext / filters / client_channel / service_config.cc
1 //
2 // Copyright 2015 gRPC authors.
3 //
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
7 //
8 //     http://www.apache.org/licenses/LICENSE-2.0
9 //
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.
15 //
16
17 #include <grpc/support/port_platform.h>
18
19 #include "src/core/ext/filters/client_channel/service_config.h"
20
21 #include <string.h>
22
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>
27
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"
33
34 namespace grpc_core {
35
36 namespace {
37 typedef InlinedVector<UniquePtr<ServiceConfig::Parser>,
38                       ServiceConfig::kNumPreallocatedParsers>
39     ServiceConfigParserList;
40 ServiceConfigParserList* g_registered_parsers;
41 }  // namespace
42
43 RefCountedPtr<ServiceConfig> ServiceConfig::Create(const char* json,
44                                                    grpc_error** error) {
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");
52     return nullptr;
53   }
54   return MakeRefCounted<ServiceConfig>(
55       std::move(service_config_json), std::move(json_string), json_tree, error);
56 }
57
58 ServiceConfig::ServiceConfig(UniquePtr<char> service_config_json,
59                              UniquePtr<char> json_string, grpc_json* json_tree,
60                              grpc_error** error)
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");
68     return;
69   }
70   grpc_error* error_list[2];
71   int error_count = 0;
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;
76   }
77   if (local_error != GRPC_ERROR_NONE) {
78     error_list[error_count++] = local_error;
79   }
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);
85   }
86 }
87
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;
94     auto parsed_obj =
95         (*g_registered_parsers)[i]->ParseGlobalParams(json_tree, &parser_error);
96     if (parser_error != GRPC_ERROR_NONE) {
97       error_list.push_back(parser_error);
98     }
99     parsed_global_configs_.push_back(std::move(parsed_obj));
100   }
101   return GRPC_ERROR_CREATE_FROM_VECTOR("Global Params", &error_list);
102 }
103
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;
111     auto parsed_obj =
112         (*g_registered_parsers)[i]->ParsePerMethodParams(json, &parser_error);
113     if (parser_error != GRPC_ERROR_NONE) {
114       error_list.push_back(parser_error);
115     }
116     objs_vector->push_back(std::move(parsed_obj));
117   }
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]
122               .get();
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"));
131         goto wrap_error;
132       }
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);
138         } else {
139           GPR_DEBUG_ASSERT(parse_error == GRPC_ERROR_NONE);
140           paths.push_back(std::move(path));
141         }
142       }
143     }
144   }
145   if (paths.size() == 0) {
146     error_list.push_back(
147         GRPC_ERROR_CREATE_FROM_STATIC_STRING("No names specified"));
148   }
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;
153     ++*idx;
154   }
155 wrap_error:
156   return GRPC_ERROR_CREATE_FROM_VECTOR("methodConfig", &error_list);
157 }
158
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"));
170       continue;
171     }
172     if (strcmp(field->key, "methodConfig") == 0) {
173       if (entries != nullptr) {
174         GPR_ASSERT(false);
175       }
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"));
179       }
180       for (grpc_json* method = field->child; method != nullptr;
181            method = method->next) {
182         int count = CountNamesInMethodConfig(method);
183         if (count <= 0) {
184           error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
185               "field:methodConfig error:No names found"));
186         }
187         num_entries += static_cast<size_t>(count);
188       }
189       entries = static_cast<SliceHashTable<const ParsedConfigVector*>::Entry*>(
190           gpr_zalloc(num_entries *
191                      sizeof(SliceHashTable<const ParsedConfigVector*>::Entry)));
192       size_t idx = 0;
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);
199         }
200       }
201       // idx might not be equal to num_entries due to parsing errors
202       num_entries = idx;
203       break;
204     }
205   }
206   if (entries != nullptr) {
207     parsed_method_configs_table_ =
208         SliceHashTable<const ParsedConfigVector*>::Create(num_entries, entries,
209                                                           nullptr);
210     gpr_free(entries);
211   }
212   return GRPC_ERROR_CREATE_FROM_VECTOR("Method Params", &error_list);
213 }
214
215 ServiceConfig::~ServiceConfig() { grpc_json_destroy(json_tree_); }
216
217 int ServiceConfig::CountNamesInMethodConfig(grpc_json* json) {
218   int num_names = 0;
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;
224         ++num_names;
225       }
226     }
227   }
228   return num_names;
229 }
230
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");
236     return nullptr;
237   }
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");
244       return nullptr;
245     }
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");
249       return nullptr;
250     }
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.
256       }
257       if (child->value == nullptr) {
258         *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
259             "field:name error: field:service error:empty value");
260         return nullptr;
261       }
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.
268       }
269       if (child->value == nullptr) {
270         *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
271             "field:name error: field:method error:empty value");
272         return nullptr;
273       }
274       method_name = child->value;
275     }
276   }
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.
281   }
282   char* path;
283   gpr_asprintf(&path, "/%s/%s", service_name,
284                method_name == nullptr ? "*" : method_name);
285   return UniquePtr<char>(path);
286 }
287
288 const ServiceConfig::ParsedConfigVector*
289 ServiceConfig::GetMethodParsedConfigVector(const grpc_slice& path) {
290   if (parsed_method_configs_table_.get() == nullptr) {
291     return nullptr;
292   }
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);
302     buf[len] = '*';
303     buf[len + 1] = '\0';
304     grpc_slice wildcard_path = grpc_slice_from_copied_string(buf);
305     gpr_free(buf);
306     value = parsed_method_configs_table_->Get(wildcard_path);
307     grpc_slice_unref_internal(wildcard_path);
308     gpr_free(path_str);
309     if (value == nullptr) return nullptr;
310   }
311   return *value;
312 }
313
314 size_t ServiceConfig::RegisterParser(UniquePtr<Parser> parser) {
315   g_registered_parsers->push_back(std::move(parser));
316   return g_registered_parsers->size() - 1;
317 }
318
319 void ServiceConfig::Init() {
320   GPR_ASSERT(g_registered_parsers == nullptr);
321   g_registered_parsers = New<ServiceConfigParserList>();
322 }
323
324 void ServiceConfig::Shutdown() {
325   Delete(g_registered_parsers);
326   g_registered_parsers = nullptr;
327 }
328
329 }  // namespace grpc_core