• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "src/core/resolver/resolver_registry.h"
18 
19 #include <grpc/support/port_platform.h>
20 
21 #include "absl/log/check.h"
22 #include "absl/log/log.h"
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 namespace grpc_core {
30 
31 //
32 // ResolverRegistry::Builder
33 //
34 
Builder()35 ResolverRegistry::Builder::Builder() { Reset(); }
36 
SetDefaultPrefix(std::string default_prefix)37 void ResolverRegistry::Builder::SetDefaultPrefix(std::string default_prefix) {
38   state_.default_prefix = std::move(default_prefix);
39 }
40 
41 namespace {
42 
IsLowerCase(absl::string_view str)43 bool IsLowerCase(absl::string_view str) {
44   for (unsigned char c : str) {
45     if (absl::ascii_isalpha(c) && !absl::ascii_islower(c)) return false;
46   }
47   return true;
48 }
49 
50 }  // namespace
51 
RegisterResolverFactory(std::unique_ptr<ResolverFactory> factory)52 void ResolverRegistry::Builder::RegisterResolverFactory(
53     std::unique_ptr<ResolverFactory> factory) {
54   CHECK(IsLowerCase(factory->scheme()));
55   auto p = state_.factories.emplace(factory->scheme(), std::move(factory));
56   CHECK(p.second);
57 }
58 
HasResolverFactory(absl::string_view scheme) const59 bool ResolverRegistry::Builder::HasResolverFactory(
60     absl::string_view scheme) const {
61   return state_.factories.find(scheme) != state_.factories.end();
62 }
63 
Reset()64 void ResolverRegistry::Builder::Reset() {
65   state_.factories.clear();
66   state_.default_prefix = "dns:///";
67 }
68 
Build()69 ResolverRegistry ResolverRegistry::Builder::Build() {
70   return ResolverRegistry(std::move(state_));
71 }
72 
73 //
74 // ResolverRegistry
75 //
76 
IsValidTarget(absl::string_view target) const77 bool ResolverRegistry::IsValidTarget(absl::string_view target) const {
78   std::string canonical_target;
79   URI uri;
80   ResolverFactory* factory =
81       FindResolverFactory(target, &uri, &canonical_target);
82   if (factory == nullptr) return false;
83   return factory->IsValidUri(uri);
84 }
85 
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) const86 OrphanablePtr<Resolver> ResolverRegistry::CreateResolver(
87     absl::string_view target, const ChannelArgs& args,
88     grpc_pollset_set* pollset_set,
89     std::shared_ptr<WorkSerializer> work_serializer,
90     std::unique_ptr<Resolver::ResultHandler> result_handler) const {
91   std::string canonical_target;
92   ResolverArgs resolver_args;
93   ResolverFactory* factory =
94       FindResolverFactory(target, &resolver_args.uri, &canonical_target);
95   if (factory == nullptr) return nullptr;
96   resolver_args.args = args;
97   resolver_args.pollset_set = pollset_set;
98   resolver_args.work_serializer = std::move(work_serializer);
99   resolver_args.result_handler = std::move(result_handler);
100   return factory->CreateResolver(std::move(resolver_args));
101 }
102 
GetDefaultAuthority(absl::string_view target) const103 std::string ResolverRegistry::GetDefaultAuthority(
104     absl::string_view target) const {
105   std::string canonical_target;
106   URI uri;
107   ResolverFactory* factory =
108       FindResolverFactory(target, &uri, &canonical_target);
109   if (factory == nullptr) return "";
110   return factory->GetDefaultAuthority(uri);
111 }
112 
AddDefaultPrefixIfNeeded(absl::string_view target) const113 std::string ResolverRegistry::AddDefaultPrefixIfNeeded(
114     absl::string_view target) const {
115   std::string canonical_target;
116   URI uri;
117   FindResolverFactory(target, &uri, &canonical_target);
118   return canonical_target.empty() ? std::string(target) : canonical_target;
119 }
120 
LookupResolverFactory(absl::string_view scheme) const121 ResolverFactory* ResolverRegistry::LookupResolverFactory(
122     absl::string_view scheme) const {
123   auto it = state_.factories.find(scheme);
124   if (it == state_.factories.end()) return nullptr;
125   return it->second.get();
126 }
127 
128 // Returns the factory for the scheme of \a target.  If \a target does
129 // not parse as a URI, prepends \a default_prefix_ and tries again.
130 // If URI parsing is successful (in either attempt), sets \a uri to
131 // point to the parsed URI.
FindResolverFactory(absl::string_view target,URI * uri,std::string * canonical_target) const132 ResolverFactory* ResolverRegistry::FindResolverFactory(
133     absl::string_view target, URI* uri, std::string* canonical_target) const {
134   CHECK_NE(uri, nullptr);
135   absl::StatusOr<URI> tmp_uri = URI::Parse(target);
136   ResolverFactory* factory =
137       tmp_uri.ok() ? LookupResolverFactory(tmp_uri->scheme()) : nullptr;
138   if (factory != nullptr) {
139     *uri = std::move(*tmp_uri);
140     return factory;
141   }
142   *canonical_target = absl::StrCat(state_.default_prefix, target);
143   absl::StatusOr<URI> tmp_uri2 = URI::Parse(*canonical_target);
144   factory = tmp_uri2.ok() ? LookupResolverFactory(tmp_uri2->scheme()) : nullptr;
145   if (factory != nullptr) {
146     *uri = std::move(*tmp_uri2);
147     return factory;
148   }
149   if (!tmp_uri.ok() || !tmp_uri2.ok()) {
150     LOG(ERROR) << "Error parsing URI(s). '" << target
151                << "':" << tmp_uri.status() << "; '" << *canonical_target
152                << "':" << tmp_uri2.status();
153     return nullptr;
154   }
155   LOG(ERROR) << "Don't know how to resolve '" << target << "' or '"
156              << *canonical_target << "'.";
157   return nullptr;
158 }
159 
160 }  // namespace grpc_core
161