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/lib/resolver/resolver_registry.h"
20
21 #include <initializer_list>
22
23 #include "absl/status/status.h"
24 #include "absl/status/statusor.h"
25 #include "absl/strings/ascii.h"
26 #include "absl/strings/str_cat.h"
27 #include "absl/strings/str_format.h"
28
29 #include <grpc/support/log.h>
30
31 namespace grpc_core {
32
33 //
34 // ResolverRegistry::Builder
35 //
36
Builder()37 ResolverRegistry::Builder::Builder() { Reset(); }
38
SetDefaultPrefix(std::string default_prefix)39 void ResolverRegistry::Builder::SetDefaultPrefix(std::string default_prefix) {
40 state_.default_prefix = std::move(default_prefix);
41 }
42
43 namespace {
44
IsLowerCase(absl::string_view str)45 bool IsLowerCase(absl::string_view str) {
46 for (unsigned char c : str) {
47 if (absl::ascii_isalpha(c) && !absl::ascii_islower(c)) return false;
48 }
49 return true;
50 }
51
52 } // namespace
53
RegisterResolverFactory(std::unique_ptr<ResolverFactory> factory)54 void ResolverRegistry::Builder::RegisterResolverFactory(
55 std::unique_ptr<ResolverFactory> factory) {
56 GPR_ASSERT(IsLowerCase(factory->scheme()));
57 auto p = state_.factories.emplace(factory->scheme(), std::move(factory));
58 GPR_ASSERT(p.second);
59 }
60
HasResolverFactory(absl::string_view scheme) const61 bool ResolverRegistry::Builder::HasResolverFactory(
62 absl::string_view scheme) const {
63 return state_.factories.find(scheme) != state_.factories.end();
64 }
65
Reset()66 void ResolverRegistry::Builder::Reset() {
67 state_.factories.clear();
68 state_.default_prefix = "dns:///";
69 }
70
Build()71 ResolverRegistry ResolverRegistry::Builder::Build() {
72 return ResolverRegistry(std::move(state_));
73 }
74
75 //
76 // ResolverRegistry
77 //
78
IsValidTarget(absl::string_view target) const79 bool ResolverRegistry::IsValidTarget(absl::string_view target) const {
80 std::string canonical_target;
81 URI uri;
82 ResolverFactory* factory =
83 FindResolverFactory(target, &uri, &canonical_target);
84 if (factory == nullptr) return false;
85 return factory->IsValidUri(uri);
86 }
87
CreateResolver(absl::string_view target,const ChannelArgs & args,grpc_pollset_set * pollset_set,std::shared_ptr<WorkSerializer> work_serializer,std::unique_ptr<Resolver::ResultHandler> result_handler) const88 OrphanablePtr<Resolver> ResolverRegistry::CreateResolver(
89 absl::string_view target, const ChannelArgs& args,
90 grpc_pollset_set* pollset_set,
91 std::shared_ptr<WorkSerializer> work_serializer,
92 std::unique_ptr<Resolver::ResultHandler> result_handler) const {
93 std::string canonical_target;
94 ResolverArgs resolver_args;
95 ResolverFactory* factory =
96 FindResolverFactory(target, &resolver_args.uri, &canonical_target);
97 if (factory == nullptr) return nullptr;
98 resolver_args.args = args;
99 resolver_args.pollset_set = pollset_set;
100 resolver_args.work_serializer = std::move(work_serializer);
101 resolver_args.result_handler = std::move(result_handler);
102 return factory->CreateResolver(std::move(resolver_args));
103 }
104
GetDefaultAuthority(absl::string_view target) const105 std::string ResolverRegistry::GetDefaultAuthority(
106 absl::string_view target) const {
107 std::string canonical_target;
108 URI uri;
109 ResolverFactory* factory =
110 FindResolverFactory(target, &uri, &canonical_target);
111 if (factory == nullptr) return "";
112 return factory->GetDefaultAuthority(uri);
113 }
114
AddDefaultPrefixIfNeeded(absl::string_view target) const115 std::string ResolverRegistry::AddDefaultPrefixIfNeeded(
116 absl::string_view target) const {
117 std::string canonical_target;
118 URI uri;
119 FindResolverFactory(target, &uri, &canonical_target);
120 return canonical_target.empty() ? std::string(target) : canonical_target;
121 }
122
LookupResolverFactory(absl::string_view scheme) const123 ResolverFactory* ResolverRegistry::LookupResolverFactory(
124 absl::string_view scheme) const {
125 auto it = state_.factories.find(scheme);
126 if (it == state_.factories.end()) return nullptr;
127 return it->second.get();
128 }
129
130 // Returns the factory for the scheme of \a target. If \a target does
131 // not parse as a URI, prepends \a default_prefix_ and tries again.
132 // If URI parsing is successful (in either attempt), sets \a uri to
133 // point to the parsed URI.
FindResolverFactory(absl::string_view target,URI * uri,std::string * canonical_target) const134 ResolverFactory* ResolverRegistry::FindResolverFactory(
135 absl::string_view target, URI* uri, std::string* canonical_target) const {
136 GPR_ASSERT(uri != nullptr);
137 absl::StatusOr<URI> tmp_uri = URI::Parse(target);
138 ResolverFactory* factory =
139 tmp_uri.ok() ? LookupResolverFactory(tmp_uri->scheme()) : nullptr;
140 if (factory != nullptr) {
141 *uri = std::move(*tmp_uri);
142 return factory;
143 }
144 *canonical_target = absl::StrCat(state_.default_prefix, target);
145 absl::StatusOr<URI> tmp_uri2 = URI::Parse(*canonical_target);
146 factory = tmp_uri2.ok() ? LookupResolverFactory(tmp_uri2->scheme()) : nullptr;
147 if (factory != nullptr) {
148 *uri = std::move(*tmp_uri2);
149 return factory;
150 }
151 if (!tmp_uri.ok() || !tmp_uri2.ok()) {
152 gpr_log(GPR_ERROR, "%s",
153 absl::StrFormat("Error parsing URI(s). '%s':%s; '%s':%s", target,
154 tmp_uri.status().ToString(), *canonical_target,
155 tmp_uri2.status().ToString())
156 .c_str());
157 return nullptr;
158 }
159 gpr_log(GPR_ERROR, "Don't know how to resolve '%s' or '%s'.",
160 std::string(target).c_str(), canonical_target->c_str());
161 return nullptr;
162 }
163
164 } // namespace grpc_core
165