Built motion from commit 6a09e18b.|2.6.11
[motion2.git] / legacy-libs / grpc / deps / grpc / src / core / ext / filters / client_channel / resolver_result_parsing.cc
1 /*
2  *
3  * Copyright 2018 gRPC authors.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  */
18
19 #include <grpc/support/port_platform.h>
20
21 #include "src/core/ext/filters/client_channel/resolver_result_parsing.h"
22
23 #include <ctype.h>
24 #include <stdio.h>
25 #include <string.h>
26
27 #include <grpc/support/alloc.h>
28 #include <grpc/support/log.h>
29 #include <grpc/support/string_util.h>
30
31 #include "src/core/ext/filters/client_channel/client_channel.h"
32 #include "src/core/ext/filters/client_channel/lb_policy_registry.h"
33 #include "src/core/ext/filters/client_channel/server_address.h"
34 #include "src/core/lib/channel/channel_args.h"
35 #include "src/core/lib/channel/status_util.h"
36 #include "src/core/lib/gpr/string.h"
37 #include "src/core/lib/gprpp/memory.h"
38 #include "src/core/lib/gprpp/optional.h"
39 #include "src/core/lib/uri/uri_parser.h"
40
41 // As per the retry design, we do not allow more than 5 retry attempts.
42 #define MAX_MAX_RETRY_ATTEMPTS 5
43
44 namespace grpc_core {
45 namespace internal {
46
47 namespace {
48 size_t g_client_channel_service_config_parser_index;
49 }
50
51 size_t ClientChannelServiceConfigParser::ParserIndex() {
52   return g_client_channel_service_config_parser_index;
53 }
54
55 void ClientChannelServiceConfigParser::Register() {
56   g_client_channel_service_config_parser_index =
57       ServiceConfig::RegisterParser(UniquePtr<ServiceConfig::Parser>(
58           New<ClientChannelServiceConfigParser>()));
59 }
60
61 namespace {
62
63 // Parses a JSON field of the form generated for a google.proto.Duration
64 // proto message, as per:
65 //   https://developers.google.com/protocol-buffers/docs/proto3#json
66 bool ParseDuration(grpc_json* field, grpc_millis* duration) {
67   if (field->type != GRPC_JSON_STRING) return false;
68   size_t len = strlen(field->value);
69   if (field->value[len - 1] != 's') return false;
70   UniquePtr<char> buf(gpr_strdup(field->value));
71   *(buf.get() + len - 1) = '\0';  // Remove trailing 's'.
72   char* decimal_point = strchr(buf.get(), '.');
73   int nanos = 0;
74   if (decimal_point != nullptr) {
75     *decimal_point = '\0';
76     nanos = gpr_parse_nonnegative_int(decimal_point + 1);
77     if (nanos == -1) {
78       return false;
79     }
80     int num_digits = static_cast<int>(strlen(decimal_point + 1));
81     if (num_digits > 9) {  // We don't accept greater precision than nanos.
82       return false;
83     }
84     for (int i = 0; i < (9 - num_digits); ++i) {
85       nanos *= 10;
86     }
87   }
88   int seconds =
89       decimal_point == buf.get() ? 0 : gpr_parse_nonnegative_int(buf.get());
90   if (seconds == -1) return false;
91   *duration = seconds * GPR_MS_PER_SEC + nanos / GPR_NS_PER_MS;
92   return true;
93 }
94
95 UniquePtr<ClientChannelMethodParsedConfig::RetryPolicy> ParseRetryPolicy(
96     grpc_json* field, grpc_error** error) {
97   GPR_DEBUG_ASSERT(error != nullptr && *error == GRPC_ERROR_NONE);
98   auto retry_policy =
99       MakeUnique<ClientChannelMethodParsedConfig::RetryPolicy>();
100   if (field->type != GRPC_JSON_OBJECT) {
101     *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
102         "field:retryPolicy error:should be of type object");
103     return nullptr;
104   }
105   InlinedVector<grpc_error*, 4> error_list;
106   for (grpc_json* sub_field = field->child; sub_field != nullptr;
107        sub_field = sub_field->next) {
108     if (sub_field->key == nullptr) continue;
109     if (strcmp(sub_field->key, "maxAttempts") == 0) {
110       if (retry_policy->max_attempts != 0) {
111         error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
112             "field:maxAttempts error:Duplicate entry"));
113       }  // Duplicate. Continue Parsing
114       if (sub_field->type != GRPC_JSON_NUMBER) {
115         error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
116             "field:maxAttempts error:should be of type number"));
117         continue;
118       }
119       retry_policy->max_attempts = gpr_parse_nonnegative_int(sub_field->value);
120       if (retry_policy->max_attempts <= 1) {
121         error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
122             "field:maxAttempts error:should be at least 2"));
123         continue;
124       }
125       if (retry_policy->max_attempts > MAX_MAX_RETRY_ATTEMPTS) {
126         gpr_log(GPR_ERROR,
127                 "service config: clamped retryPolicy.maxAttempts at %d",
128                 MAX_MAX_RETRY_ATTEMPTS);
129         retry_policy->max_attempts = MAX_MAX_RETRY_ATTEMPTS;
130       }
131     } else if (strcmp(sub_field->key, "initialBackoff") == 0) {
132       if (retry_policy->initial_backoff > 0) {
133         error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
134             "field:initialBackoff error:Duplicate entry"));
135       }  // Duplicate, continue parsing.
136       if (!ParseDuration(sub_field, &retry_policy->initial_backoff)) {
137         error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
138             "field:initialBackoff error:Failed to parse"));
139         continue;
140       }
141       if (retry_policy->initial_backoff == 0) {
142         error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
143             "field:initialBackoff error:must be greater than 0"));
144       }
145     } else if (strcmp(sub_field->key, "maxBackoff") == 0) {
146       if (retry_policy->max_backoff > 0) {
147         error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
148             "field:maxBackoff error:Duplicate entry"));
149       }  // Duplicate, continue parsing.
150       if (!ParseDuration(sub_field, &retry_policy->max_backoff)) {
151         error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
152             "field:maxBackoff error:failed to parse"));
153         continue;
154       }
155       if (retry_policy->max_backoff == 0) {
156         error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
157             "field:maxBackoff error:should be greater than 0"));
158       }
159     } else if (strcmp(sub_field->key, "backoffMultiplier") == 0) {
160       if (retry_policy->backoff_multiplier != 0) {
161         error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
162             "field:backoffMultiplier error:Duplicate entry"));
163       }  // Duplicate, continue parsing.
164       if (sub_field->type != GRPC_JSON_NUMBER) {
165         error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
166             "field:backoffMultiplier error:should be of type number"));
167         continue;
168       }
169       if (sscanf(sub_field->value, "%f", &retry_policy->backoff_multiplier) !=
170           1) {
171         error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
172             "field:backoffMultiplier error:failed to parse"));
173         continue;
174       }
175       if (retry_policy->backoff_multiplier <= 0) {
176         error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
177             "field:backoffMultiplier error:should be greater than 0"));
178       }
179     } else if (strcmp(sub_field->key, "retryableStatusCodes") == 0) {
180       if (!retry_policy->retryable_status_codes.Empty()) {
181         error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
182             "field:retryableStatusCodes error:Duplicate entry"));
183       }  // Duplicate, continue parsing.
184       if (sub_field->type != GRPC_JSON_ARRAY) {
185         error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
186             "field:retryableStatusCodes error:should be of type array"));
187         continue;
188       }
189       for (grpc_json* element = sub_field->child; element != nullptr;
190            element = element->next) {
191         if (element->type != GRPC_JSON_STRING) {
192           error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
193               "field:retryableStatusCodes error:status codes should be of type "
194               "string"));
195           continue;
196         }
197         grpc_status_code status;
198         if (!grpc_status_code_from_string(element->value, &status)) {
199           error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
200               "field:retryableStatusCodes error:failed to parse status code"));
201           continue;
202         }
203         retry_policy->retryable_status_codes.Add(status);
204       }
205       if (retry_policy->retryable_status_codes.Empty()) {
206         error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
207             "field:retryableStatusCodes error:should be non-empty"));
208       };
209     }
210   }
211   // Make sure required fields are set.
212   if (error_list.empty()) {
213     if (retry_policy->max_attempts == 0 || retry_policy->initial_backoff == 0 ||
214         retry_policy->max_backoff == 0 ||
215         retry_policy->backoff_multiplier == 0 ||
216         retry_policy->retryable_status_codes.Empty()) {
217       *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
218           "field:retryPolicy error:Missing required field(s)");
219       return nullptr;
220     }
221   }
222   *error = GRPC_ERROR_CREATE_FROM_VECTOR("retryPolicy", &error_list);
223   return *error == GRPC_ERROR_NONE ? std::move(retry_policy) : nullptr;
224 }
225
226 const char* ParseHealthCheckConfig(const grpc_json* field, grpc_error** error) {
227   GPR_DEBUG_ASSERT(error != nullptr && *error == GRPC_ERROR_NONE);
228   const char* service_name = nullptr;
229   GPR_DEBUG_ASSERT(strcmp(field->key, "healthCheckConfig") == 0);
230   if (field->type != GRPC_JSON_OBJECT) {
231     *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
232         "field:healthCheckConfig error:should be of type object");
233     return nullptr;
234   }
235   InlinedVector<grpc_error*, 2> error_list;
236   for (grpc_json* sub_field = field->child; sub_field != nullptr;
237        sub_field = sub_field->next) {
238     if (sub_field->key == nullptr) {
239       GPR_DEBUG_ASSERT(false);
240       continue;
241     }
242     if (strcmp(sub_field->key, "serviceName") == 0) {
243       if (service_name != nullptr) {
244         error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
245             "field:serviceName error:Duplicate "
246             "entry"));
247       }  // Duplicate. Continue parsing
248       if (sub_field->type != GRPC_JSON_STRING) {
249         error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
250             "field:serviceName error:should be of type string"));
251         continue;
252       }
253       service_name = sub_field->value;
254     }
255   }
256   if (!error_list.empty()) {
257     return nullptr;
258   }
259   *error =
260       GRPC_ERROR_CREATE_FROM_VECTOR("field:healthCheckConfig", &error_list);
261   return service_name;
262 }
263
264 }  // namespace
265
266 UniquePtr<ServiceConfig::ParsedConfig>
267 ClientChannelServiceConfigParser::ParseGlobalParams(const grpc_json* json,
268                                                     grpc_error** error) {
269   GPR_DEBUG_ASSERT(error != nullptr && *error == GRPC_ERROR_NONE);
270   InlinedVector<grpc_error*, 4> error_list;
271   RefCountedPtr<LoadBalancingPolicy::Config> parsed_lb_config;
272   UniquePtr<char> lb_policy_name;
273   Optional<ClientChannelGlobalParsedConfig::RetryThrottling> retry_throttling;
274   const char* health_check_service_name = nullptr;
275   for (grpc_json* field = json->child; field != nullptr; field = field->next) {
276     if (field->key == nullptr) {
277       continue;  // Not the LB config global parameter
278     }
279     // Parsed Load balancing config
280     if (strcmp(field->key, "loadBalancingConfig") == 0) {
281       if (parsed_lb_config != nullptr) {
282         error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
283             "field:loadBalancingConfig error:Duplicate entry"));
284       }  // Duplicate, continue parsing.
285       grpc_error* parse_error = GRPC_ERROR_NONE;
286       parsed_lb_config = LoadBalancingPolicyRegistry::ParseLoadBalancingConfig(
287           field, &parse_error);
288       if (parsed_lb_config == nullptr) {
289         error_list.push_back(parse_error);
290       }
291     }
292     // Parse deprecated loadBalancingPolicy
293     if (strcmp(field->key, "loadBalancingPolicy") == 0) {
294       if (lb_policy_name != nullptr) {
295         error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
296             "field:loadBalancingPolicy error:Duplicate entry"));
297       }  // Duplicate, continue parsing.
298       if (field->type != GRPC_JSON_STRING) {
299         error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
300             "field:loadBalancingPolicy error:type should be string"));
301         continue;
302       }
303       lb_policy_name.reset(gpr_strdup(field->value));
304       char* lb_policy = lb_policy_name.get();
305       if (lb_policy != nullptr) {
306         for (size_t i = 0; i < strlen(lb_policy); ++i) {
307           lb_policy[i] = tolower(lb_policy[i]);
308         }
309       }
310       bool requires_config = false;
311       if (!LoadBalancingPolicyRegistry::LoadBalancingPolicyExists(
312               lb_policy, &requires_config)) {
313         error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
314             "field:loadBalancingPolicy error:Unknown lb policy"));
315       } else if (requires_config) {
316         char* error_msg;
317         gpr_asprintf(&error_msg,
318                      "field:loadBalancingPolicy error:%s requires a config. "
319                      "Please use loadBalancingConfig instead.",
320                      lb_policy);
321         error_list.push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING(error_msg));
322         gpr_free(error_msg);
323       }
324     }
325     // Parse retry throttling
326     if (strcmp(field->key, "retryThrottling") == 0) {
327       if (retry_throttling.has_value()) {
328         error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
329             "field:retryThrottling error:Duplicate entry"));
330       }  // Duplicate, continue parsing.
331       if (field->type != GRPC_JSON_OBJECT) {
332         error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
333             "field:retryThrottling error:Type should be object"));
334         continue;
335       }
336       Optional<int> max_milli_tokens;
337       Optional<int> milli_token_ratio;
338       for (grpc_json* sub_field = field->child; sub_field != nullptr;
339            sub_field = sub_field->next) {
340         if (sub_field->key == nullptr) continue;
341         if (strcmp(sub_field->key, "maxTokens") == 0) {
342           if (max_milli_tokens.has_value()) {
343             error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
344                 "field:retryThrottling field:maxTokens error:Duplicate "
345                 "entry"));
346           }  // Duplicate, continue parsing.
347           if (sub_field->type != GRPC_JSON_NUMBER) {
348             error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
349                 "field:retryThrottling field:maxTokens error:Type should be "
350                 "number"));
351           } else {
352             max_milli_tokens.set(gpr_parse_nonnegative_int(sub_field->value) *
353                                  1000);
354             if (max_milli_tokens.value() <= 0) {
355               error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
356                   "field:retryThrottling field:maxTokens error:should be "
357                   "greater than zero"));
358             }
359           }
360         } else if (strcmp(sub_field->key, "tokenRatio") == 0) {
361           if (milli_token_ratio.has_value()) {
362             error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
363                 "field:retryThrottling field:tokenRatio error:Duplicate "
364                 "entry"));
365           }  // Duplicate, continue parsing.
366           if (sub_field->type != GRPC_JSON_NUMBER) {
367             error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
368                 "field:retryThrottling field:tokenRatio error:type should be "
369                 "number"));
370           } else {
371             // We support up to 3 decimal digits.
372             size_t whole_len = strlen(sub_field->value);
373             uint32_t multiplier = 1;
374             uint32_t decimal_value = 0;
375             const char* decimal_point = strchr(sub_field->value, '.');
376             if (decimal_point != nullptr) {
377               whole_len = static_cast<size_t>(decimal_point - sub_field->value);
378               multiplier = 1000;
379               size_t decimal_len = strlen(decimal_point + 1);
380               if (decimal_len > 3) decimal_len = 3;
381               if (!gpr_parse_bytes_to_uint32(decimal_point + 1, decimal_len,
382                                              &decimal_value)) {
383                 error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
384                     "field:retryThrottling field:tokenRatio error:Failed "
385                     "parsing"));
386                 continue;
387               }
388               uint32_t decimal_multiplier = 1;
389               for (size_t i = 0; i < (3 - decimal_len); ++i) {
390                 decimal_multiplier *= 10;
391               }
392               decimal_value *= decimal_multiplier;
393             }
394             uint32_t whole_value;
395             if (!gpr_parse_bytes_to_uint32(sub_field->value, whole_len,
396                                            &whole_value)) {
397               error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
398                   "field:retryThrottling field:tokenRatio error:Failed "
399                   "parsing"));
400               continue;
401             }
402             milli_token_ratio.set(
403                 static_cast<int>((whole_value * multiplier) + decimal_value));
404             if (milli_token_ratio.value() <= 0) {
405               error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
406                   "field:retryThrottling field:tokenRatio error:value should "
407                   "be greater than 0"));
408             }
409           }
410         }
411       }
412       ClientChannelGlobalParsedConfig::RetryThrottling data;
413       if (!max_milli_tokens.has_value()) {
414         error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
415             "field:retryThrottling field:maxTokens error:Not found"));
416       } else {
417         data.max_milli_tokens = max_milli_tokens.value();
418       }
419       if (!milli_token_ratio.has_value()) {
420         error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
421             "field:retryThrottling field:tokenRatio error:Not found"));
422       } else {
423         data.milli_token_ratio = milli_token_ratio.value();
424       }
425       retry_throttling.set(data);
426     }
427     if (strcmp(field->key, "healthCheckConfig") == 0) {
428       if (health_check_service_name != nullptr) {
429         error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
430             "field:healthCheckConfig error:Duplicate entry"));
431       }  // Duplicate continue parsing
432       grpc_error* parsing_error = GRPC_ERROR_NONE;
433       health_check_service_name = ParseHealthCheckConfig(field, &parsing_error);
434       if (parsing_error != GRPC_ERROR_NONE) {
435         error_list.push_back(parsing_error);
436       }
437     }
438   }
439   *error = GRPC_ERROR_CREATE_FROM_VECTOR("Client channel global parser",
440                                          &error_list);
441   if (*error == GRPC_ERROR_NONE) {
442     return UniquePtr<ServiceConfig::ParsedConfig>(
443         New<ClientChannelGlobalParsedConfig>(
444             std::move(parsed_lb_config), std::move(lb_policy_name),
445             retry_throttling, health_check_service_name));
446   }
447   return nullptr;
448 }
449
450 UniquePtr<ServiceConfig::ParsedConfig>
451 ClientChannelServiceConfigParser::ParsePerMethodParams(const grpc_json* json,
452                                                        grpc_error** error) {
453   GPR_DEBUG_ASSERT(error != nullptr && *error == GRPC_ERROR_NONE);
454   InlinedVector<grpc_error*, 4> error_list;
455   Optional<bool> wait_for_ready;
456   grpc_millis timeout = 0;
457   UniquePtr<ClientChannelMethodParsedConfig::RetryPolicy> retry_policy;
458   for (grpc_json* field = json->child; field != nullptr; field = field->next) {
459     if (field->key == nullptr) continue;
460     if (strcmp(field->key, "waitForReady") == 0) {
461       if (wait_for_ready.has_value()) {
462         error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
463             "field:waitForReady error:Duplicate entry"));
464       }  // Duplicate, continue parsing.
465       if (field->type == GRPC_JSON_TRUE) {
466         wait_for_ready.set(true);
467       } else if (field->type == GRPC_JSON_FALSE) {
468         wait_for_ready.set(false);
469       } else {
470         error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
471             "field:waitForReady error:Type should be true/false"));
472       }
473     } else if (strcmp(field->key, "timeout") == 0) {
474       if (timeout > 0) {
475         error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
476             "field:timeout error:Duplicate entry"));
477       }  // Duplicate, continue parsing.
478       if (!ParseDuration(field, &timeout)) {
479         error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
480             "field:timeout error:Failed parsing"));
481       };
482     } else if (strcmp(field->key, "retryPolicy") == 0) {
483       if (retry_policy != nullptr) {
484         error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
485             "field:retryPolicy error:Duplicate entry"));
486       }  // Duplicate, continue parsing.
487       grpc_error* error = GRPC_ERROR_NONE;
488       retry_policy = ParseRetryPolicy(field, &error);
489       if (retry_policy == nullptr) {
490         error_list.push_back(error);
491       }
492     }
493   }
494   *error = GRPC_ERROR_CREATE_FROM_VECTOR("Client channel parser", &error_list);
495   if (*error == GRPC_ERROR_NONE) {
496     return UniquePtr<ServiceConfig::ParsedConfig>(
497         New<ClientChannelMethodParsedConfig>(timeout, wait_for_ready,
498                                              std::move(retry_policy)));
499   }
500   return nullptr;
501 }
502
503 }  // namespace internal
504 }  // namespace grpc_core