Merge pull request #19584 from bigfacebear/add_IsValidTarget_api_to_ResolverRegistry

add IsValidTarget API to ResolverRegistry
diff --git a/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc b/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc
index 43b28bc..4e7bb5e 100644
--- a/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc
+++ b/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc
@@ -433,6 +433,8 @@
 
 class AresDnsResolverFactory : public ResolverFactory {
  public:
+  bool IsValidUri(const grpc_uri* uri) const override { return true; }
+
   OrphanablePtr<Resolver> CreateResolver(ResolverArgs args) const override {
     return OrphanablePtr<Resolver>(New<AresDnsResolver>(std::move(args)));
   }
diff --git a/src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc b/src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc
index 1abe9ad..bc6d73a 100644
--- a/src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc
+++ b/src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc
@@ -258,11 +258,16 @@
 
 class NativeDnsResolverFactory : public ResolverFactory {
  public:
-  OrphanablePtr<Resolver> CreateResolver(ResolverArgs args) const override {
-    if (GPR_UNLIKELY(0 != strcmp(args.uri->authority, ""))) {
+  bool IsValidUri(const grpc_uri* uri) const override {
+    if (GPR_UNLIKELY(0 != strcmp(uri->authority, ""))) {
       gpr_log(GPR_ERROR, "authority based dns uri's not supported");
-      return OrphanablePtr<Resolver>(nullptr);
+      return false;
     }
+    return true;
+  }
+
+  OrphanablePtr<Resolver> CreateResolver(ResolverArgs args) const override {
+    if (!IsValidUri(args.uri)) return nullptr;
     return OrphanablePtr<Resolver>(New<NativeDnsResolver>(std::move(args)));
   }
 
diff --git a/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc b/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc
index c48f232..c5a27f1 100644
--- a/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc
+++ b/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc
@@ -321,6 +321,8 @@
 
 class FakeResolverFactory : public ResolverFactory {
  public:
+  bool IsValidUri(const grpc_uri* uri) const override { return true; }
+
   OrphanablePtr<Resolver> CreateResolver(ResolverArgs args) const override {
     return OrphanablePtr<Resolver>(New<FakeResolver>(std::move(args)));
   }
diff --git a/src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc b/src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc
index 517b929..532fd6d 100644
--- a/src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc
+++ b/src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc
@@ -80,24 +80,23 @@
 
 void DoNothing(void* ignored) {}
 
-OrphanablePtr<Resolver> CreateSockaddrResolver(
-    ResolverArgs args,
-    bool parse(const grpc_uri* uri, grpc_resolved_address* dst)) {
-  if (0 != strcmp(args.uri->authority, "")) {
+bool ParseUri(const grpc_uri* uri,
+              bool parse(const grpc_uri* uri, grpc_resolved_address* dst),
+              ServerAddressList* addresses) {
+  if (0 != strcmp(uri->authority, "")) {
     gpr_log(GPR_ERROR, "authority-based URIs not supported by the %s scheme",
-            args.uri->scheme);
-    return nullptr;
+            uri->scheme);
+    return false;
   }
   // Construct addresses.
   grpc_slice path_slice =
-      grpc_slice_new(args.uri->path, strlen(args.uri->path), DoNothing);
+      grpc_slice_new(uri->path, strlen(uri->path), DoNothing);
   grpc_slice_buffer path_parts;
   grpc_slice_buffer_init(&path_parts);
   grpc_slice_split(path_slice, ",", &path_parts);
-  ServerAddressList addresses;
   bool errors_found = false;
   for (size_t i = 0; i < path_parts.count; i++) {
-    grpc_uri ith_uri = *args.uri;
+    grpc_uri ith_uri = *uri;
     UniquePtr<char> part_str(grpc_slice_to_c_string(path_parts.slices[i]));
     ith_uri.path = part_str.get();
     grpc_resolved_address addr;
@@ -105,13 +104,20 @@
       errors_found = true;
       break;
     }
-    addresses.emplace_back(addr, nullptr /* args */);
+    if (addresses != nullptr) {
+      addresses->emplace_back(addr, nullptr /* args */);
+    }
   }
   grpc_slice_buffer_destroy_internal(&path_parts);
   grpc_slice_unref_internal(path_slice);
-  if (errors_found) {
-    return OrphanablePtr<Resolver>(nullptr);
-  }
+  return !errors_found;
+}
+
+OrphanablePtr<Resolver> CreateSockaddrResolver(
+    ResolverArgs args,
+    bool parse(const grpc_uri* uri, grpc_resolved_address* dst)) {
+  ServerAddressList addresses;
+  if (!ParseUri(args.uri, parse, &addresses)) return nullptr;
   // Instantiate resolver.
   return OrphanablePtr<Resolver>(
       New<SockaddrResolver>(std::move(addresses), std::move(args)));
@@ -119,6 +125,10 @@
 
 class IPv4ResolverFactory : public ResolverFactory {
  public:
+  bool IsValidUri(const grpc_uri* uri) const override {
+    return ParseUri(uri, grpc_parse_ipv4, nullptr);
+  }
+
   OrphanablePtr<Resolver> CreateResolver(ResolverArgs args) const override {
     return CreateSockaddrResolver(std::move(args), grpc_parse_ipv4);
   }
@@ -128,6 +138,10 @@
 
 class IPv6ResolverFactory : public ResolverFactory {
  public:
+  bool IsValidUri(const grpc_uri* uri) const override {
+    return ParseUri(uri, grpc_parse_ipv6, nullptr);
+  }
+
   OrphanablePtr<Resolver> CreateResolver(ResolverArgs args) const override {
     return CreateSockaddrResolver(std::move(args), grpc_parse_ipv6);
   }
@@ -138,6 +152,10 @@
 #ifdef GRPC_HAVE_UNIX_SOCKET
 class UnixResolverFactory : public ResolverFactory {
  public:
+  bool IsValidUri(const grpc_uri* uri) const override {
+    return ParseUri(uri, grpc_parse_unix, nullptr);
+  }
+
   OrphanablePtr<Resolver> CreateResolver(ResolverArgs args) const override {
     return CreateSockaddrResolver(std::move(args), grpc_parse_unix);
   }
diff --git a/src/core/ext/filters/client_channel/resolver_factory.h b/src/core/ext/filters/client_channel/resolver_factory.h
index 273fd8d..7fed48b 100644
--- a/src/core/ext/filters/client_channel/resolver_factory.h
+++ b/src/core/ext/filters/client_channel/resolver_factory.h
@@ -47,6 +47,10 @@
 
 class ResolverFactory {
  public:
+  /// Returns a bool indicating whether the input uri is valid to create a
+  /// resolver.
+  virtual bool IsValidUri(const grpc_uri* uri) const GRPC_ABSTRACT;
+
   /// Returns a new resolver instance.
   virtual OrphanablePtr<Resolver> CreateResolver(ResolverArgs args) const
       GRPC_ABSTRACT;
diff --git a/src/core/ext/filters/client_channel/resolver_registry.cc b/src/core/ext/filters/client_channel/resolver_registry.cc
index 5b00eab..509c4ef 100644
--- a/src/core/ext/filters/client_channel/resolver_registry.cc
+++ b/src/core/ext/filters/client_channel/resolver_registry.cc
@@ -132,6 +132,17 @@
   return g_state->LookupResolverFactory(scheme);
 }
 
+bool ResolverRegistry::IsValidTarget(const char* target) {
+  grpc_uri* uri = nullptr;
+  char* canonical_target = nullptr;
+  ResolverFactory* factory =
+      g_state->FindResolverFactory(target, &uri, &canonical_target);
+  bool result = factory == nullptr ? false : factory->IsValidUri(uri);
+  grpc_uri_destroy(uri);
+  gpr_free(canonical_target);
+  return result;
+}
+
 OrphanablePtr<Resolver> ResolverRegistry::CreateResolver(
     const char* target, const grpc_channel_args* args,
     grpc_pollset_set* pollset_set, grpc_combiner* combiner,
diff --git a/src/core/ext/filters/client_channel/resolver_registry.h b/src/core/ext/filters/client_channel/resolver_registry.h
index 0eec678..4248a06 100644
--- a/src/core/ext/filters/client_channel/resolver_registry.h
+++ b/src/core/ext/filters/client_channel/resolver_registry.h
@@ -50,6 +50,9 @@
     static void RegisterResolverFactory(UniquePtr<ResolverFactory> factory);
   };
 
+  /// Checks whether the user input \a target is valid to create a resolver.
+  static bool IsValidTarget(const char* target);
+
   /// Creates a resolver given \a target.
   /// First tries to parse \a target as a URI. If this succeeds, tries
   /// to locate a registered resolver factory based on the URI scheme.