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