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