• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2018 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/resolver_result_parsing.h"
20 
21 #include <ctype.h>
22 #include <stdio.h>
23 #include <string.h>
24 
25 #include "absl/strings/str_cat.h"
26 #include "absl/types/optional.h"
27 
28 #include <grpc/support/alloc.h>
29 #include <grpc/support/log.h>
30 #include <grpc/support/string_util.h>
31 
32 #include "src/core/ext/filters/client_channel/client_channel.h"
33 #include "src/core/ext/filters/client_channel/lb_policy_registry.h"
34 #include "src/core/ext/filters/client_channel/server_address.h"
35 #include "src/core/lib/channel/channel_args.h"
36 #include "src/core/lib/channel/status_util.h"
37 #include "src/core/lib/gpr/string.h"
38 #include "src/core/lib/gprpp/memory.h"
39 #include "src/core/lib/json/json_util.h"
40 #include "src/core/lib/uri/uri_parser.h"
41 
42 // As per the retry design, we do not allow more than 5 retry attempts.
43 #define MAX_MAX_RETRY_ATTEMPTS 5
44 
45 namespace grpc_core {
46 namespace internal {
47 
48 namespace {
49 size_t g_client_channel_service_config_parser_index;
50 }
51 
ParserIndex()52 size_t ClientChannelServiceConfigParser::ParserIndex() {
53   return g_client_channel_service_config_parser_index;
54 }
55 
Register()56 void ClientChannelServiceConfigParser::Register() {
57   g_client_channel_service_config_parser_index =
58       ServiceConfigParser::RegisterParser(
59           absl::make_unique<ClientChannelServiceConfigParser>());
60 }
61 
62 namespace {
63 
ParseHealthCheckConfig(const Json & field,grpc_error_handle * error)64 absl::optional<std::string> ParseHealthCheckConfig(const Json& field,
65                                                    grpc_error_handle* error) {
66   GPR_DEBUG_ASSERT(error != nullptr && *error == GRPC_ERROR_NONE);
67   if (field.type() != Json::Type::OBJECT) {
68     *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
69         "field:healthCheckConfig error:should be of type object");
70     return absl::nullopt;
71   }
72   std::vector<grpc_error_handle> error_list;
73   absl::optional<std::string> service_name;
74   auto it = field.object_value().find("serviceName");
75   if (it != field.object_value().end()) {
76     if (it->second.type() != Json::Type::STRING) {
77       error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
78           "field:serviceName error:should be of type string"));
79     } else {
80       service_name = it->second.string_value();
81     }
82   }
83   *error =
84       GRPC_ERROR_CREATE_FROM_VECTOR("field:healthCheckConfig", &error_list);
85   return service_name;
86 }
87 
88 }  // namespace
89 
90 std::unique_ptr<ServiceConfigParser::ParsedConfig>
ParseGlobalParams(const grpc_channel_args *,const Json & json,grpc_error_handle * error)91 ClientChannelServiceConfigParser::ParseGlobalParams(
92     const grpc_channel_args* /*args*/, const Json& json,
93     grpc_error_handle* error) {
94   GPR_DEBUG_ASSERT(error != nullptr && *error == GRPC_ERROR_NONE);
95   std::vector<grpc_error_handle> error_list;
96   // Parse LB config.
97   RefCountedPtr<LoadBalancingPolicy::Config> parsed_lb_config;
98   auto it = json.object_value().find("loadBalancingConfig");
99   if (it != json.object_value().end()) {
100     grpc_error_handle parse_error = GRPC_ERROR_NONE;
101     parsed_lb_config = LoadBalancingPolicyRegistry::ParseLoadBalancingConfig(
102         it->second, &parse_error);
103     if (parsed_lb_config == nullptr) {
104       std::vector<grpc_error_handle> lb_errors;
105       lb_errors.push_back(parse_error);
106       error_list.push_back(GRPC_ERROR_CREATE_FROM_VECTOR(
107           "field:loadBalancingConfig", &lb_errors));
108     }
109   }
110   // Parse deprecated LB policy.
111   std::string lb_policy_name;
112   it = json.object_value().find("loadBalancingPolicy");
113   if (it != json.object_value().end()) {
114     if (it->second.type() != Json::Type::STRING) {
115       error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
116           "field:loadBalancingPolicy error:type should be string"));
117     } else {
118       lb_policy_name = it->second.string_value();
119       for (size_t i = 0; i < lb_policy_name.size(); ++i) {
120         lb_policy_name[i] = tolower(lb_policy_name[i]);
121       }
122       bool requires_config = false;
123       if (!LoadBalancingPolicyRegistry::LoadBalancingPolicyExists(
124               lb_policy_name.c_str(), &requires_config)) {
125         error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
126             "field:loadBalancingPolicy error:Unknown lb policy"));
127       } else if (requires_config) {
128         error_list.push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING(
129             absl::StrCat("field:loadBalancingPolicy error:", lb_policy_name,
130                          " requires a config. Please use loadBalancingConfig "
131                          "instead.")
132                 .c_str()));
133       }
134     }
135   }
136   // Parse health check config.
137   absl::optional<std::string> health_check_service_name;
138   it = json.object_value().find("healthCheckConfig");
139   if (it != json.object_value().end()) {
140     grpc_error_handle parsing_error = GRPC_ERROR_NONE;
141     health_check_service_name =
142         ParseHealthCheckConfig(it->second, &parsing_error);
143     if (parsing_error != GRPC_ERROR_NONE) {
144       error_list.push_back(parsing_error);
145     }
146   }
147   *error = GRPC_ERROR_CREATE_FROM_VECTOR("Client channel global parser",
148                                          &error_list);
149   if (*error == GRPC_ERROR_NONE) {
150     return absl::make_unique<ClientChannelGlobalParsedConfig>(
151         std::move(parsed_lb_config), std::move(lb_policy_name),
152         std::move(health_check_service_name));
153   }
154   return nullptr;
155 }
156 
157 std::unique_ptr<ServiceConfigParser::ParsedConfig>
ParsePerMethodParams(const grpc_channel_args *,const Json & json,grpc_error_handle * error)158 ClientChannelServiceConfigParser::ParsePerMethodParams(
159     const grpc_channel_args* /*args*/, const Json& json,
160     grpc_error_handle* error) {
161   GPR_DEBUG_ASSERT(error != nullptr && *error == GRPC_ERROR_NONE);
162   std::vector<grpc_error_handle> error_list;
163   // Parse waitForReady.
164   absl::optional<bool> wait_for_ready;
165   auto it = json.object_value().find("waitForReady");
166   if (it != json.object_value().end()) {
167     if (it->second.type() == Json::Type::JSON_TRUE) {
168       wait_for_ready.emplace(true);
169     } else if (it->second.type() == Json::Type::JSON_FALSE) {
170       wait_for_ready.emplace(false);
171     } else {
172       error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
173           "field:waitForReady error:Type should be true/false"));
174     }
175   }
176   // Parse timeout.
177   grpc_millis timeout = 0;
178   ParseJsonObjectFieldAsDuration(json.object_value(), "timeout", &timeout,
179                                  &error_list, false);
180   // Return result.
181   *error = GRPC_ERROR_CREATE_FROM_VECTOR("Client channel parser", &error_list);
182   if (*error == GRPC_ERROR_NONE) {
183     return absl::make_unique<ClientChannelMethodParsedConfig>(timeout,
184                                                               wait_for_ready);
185   }
186   return nullptr;
187 }
188 
189 }  // namespace internal
190 }  // namespace grpc_core
191