From e4a5e4913cafc412ecd3c48eae54afcac1a93f6b Mon Sep 17 00:00:00 2001 From: PetitBaguette Date: Wed, 4 Feb 2026 21:04:13 +0900 Subject: [PATCH 1/6] fix(xds): Allow and normalize trailing dot (FQDN) in matchHostName --- .../main/java/io/grpc/xds/RoutingUtils.java | 13 ++++++++++-- .../java/io/grpc/xds/XdsNameResolver.java | 13 ++++++++++-- .../java/io/grpc/xds/XdsNameResolverTest.java | 21 +++++++++++++++++++ 3 files changed, 43 insertions(+), 4 deletions(-) diff --git a/xds/src/main/java/io/grpc/xds/RoutingUtils.java b/xds/src/main/java/io/grpc/xds/RoutingUtils.java index 2b60e90deda..bff6756a9a4 100644 --- a/xds/src/main/java/io/grpc/xds/RoutingUtils.java +++ b/xds/src/main/java/io/grpc/xds/RoutingUtils.java @@ -92,15 +92,24 @@ static VirtualHost findVirtualHostForHostName(List virtualHosts, St * */ private static boolean matchHostName(String hostName, String pattern) { - checkArgument(hostName.length() != 0 && !hostName.startsWith(".") && !hostName.endsWith("."), + checkArgument(hostName.length() != 0 && !hostName.startsWith("."), "Invalid host name"); - checkArgument(pattern.length() != 0 && !pattern.startsWith(".") && !pattern.endsWith("."), + checkArgument(pattern.length() != 0 && !pattern.startsWith("."), "Invalid pattern/domain name"); hostName = hostName.toLowerCase(Locale.US); pattern = pattern.toLowerCase(Locale.US); // hostName and pattern are now in lower case -- domain names are case-insensitive. + // Strip trailing dot to normalize FQDN (e.g. "example.com.") to a relative form, + // as per RFC 1034 Section 3.1 the two are semantically equivalent. + if (hostName.endsWith(".")) { + hostName = hostName.substring(0, hostName.length() - 1); + } + if (pattern.endsWith(".")) { + pattern = pattern.substring(0, pattern.length() - 1); + } + if (!pattern.contains("*")) { // Not a wildcard pattern -- hostName and pattern must match exactly. return hostName.equals(pattern); diff --git a/xds/src/main/java/io/grpc/xds/XdsNameResolver.java b/xds/src/main/java/io/grpc/xds/XdsNameResolver.java index 196d51fb5a6..3021c035d04 100644 --- a/xds/src/main/java/io/grpc/xds/XdsNameResolver.java +++ b/xds/src/main/java/io/grpc/xds/XdsNameResolver.java @@ -354,15 +354,24 @@ private void updateResolutionResult(XdsConfig xdsConfig) { */ @VisibleForTesting static boolean matchHostName(String hostName, String pattern) { - checkArgument(hostName.length() != 0 && !hostName.startsWith(".") && !hostName.endsWith("."), + checkArgument(hostName.length() != 0 && !hostName.startsWith("."), "Invalid host name"); - checkArgument(pattern.length() != 0 && !pattern.startsWith(".") && !pattern.endsWith("."), + checkArgument(pattern.length() != 0 && !pattern.startsWith("."), "Invalid pattern/domain name"); hostName = hostName.toLowerCase(Locale.US); pattern = pattern.toLowerCase(Locale.US); // hostName and pattern are now in lower case -- domain names are case-insensitive. + // Strip trailing dot to normalize FQDN (e.g. "example.com.") to a relative form, + // as per RFC 1034 Section 3.1 the two are semantically equivalent. + if (hostName.endsWith(".")) { + hostName = hostName.substring(0, hostName.length() - 1); + } + if (pattern.endsWith(".")) { + pattern = pattern.substring(0, pattern.length() - 1); + } + if (!pattern.contains("*")) { // Not a wildcard pattern -- hostName and pattern must match exactly. return hostName.equals(pattern); diff --git a/xds/src/test/java/io/grpc/xds/XdsNameResolverTest.java b/xds/src/test/java/io/grpc/xds/XdsNameResolverTest.java index 45a96ee172f..8d6a1765ed9 100644 --- a/xds/src/test/java/io/grpc/xds/XdsNameResolverTest.java +++ b/xds/src/test/java/io/grpc/xds/XdsNameResolverTest.java @@ -2062,6 +2062,27 @@ public void matchHostName_postfixWildCard() { assertThat(XdsNameResolver.matchHostName("foo-bar", pattern)).isTrue(); } + @Test + public void matchHostName_trailingDot() { + // FQDN (trailing dot) is semantically equivalent to the relative form per RFC 1034 Section 3.1. + assertThat(XdsNameResolver.matchHostName("foo.googleapis.com.", "foo.googleapis.com")).isTrue(); + assertThat(XdsNameResolver.matchHostName("foo.googleapis.com", "foo.googleapis.com.")).isTrue(); + assertThat(XdsNameResolver.matchHostName("foo.googleapis.com.", "foo.googleapis.com.")).isTrue(); + assertThat(XdsNameResolver.matchHostName("bar.googleapis.com.", "foo.googleapis.com")).isFalse(); + + // Wildcard + trailing dot combinations. + String pattern = "*.foo.googleapis.com"; + assertThat(XdsNameResolver.matchHostName("bar.foo.googleapis.com.", pattern)).isTrue(); + assertThat(XdsNameResolver.matchHostName("bar.foo.googleapis.com", pattern + ".")).isTrue(); + assertThat(XdsNameResolver.matchHostName("bar.foo.googleapis.com.", pattern + ".")).isTrue(); + assertThat(XdsNameResolver.matchHostName("foo.googleapis.com.", pattern)).isFalse(); + + pattern = "foo.*"; + assertThat(XdsNameResolver.matchHostName("foo.googleapis.com.", pattern)).isTrue(); + assertThat(XdsNameResolver.matchHostName("foo.com.", pattern)).isTrue(); + assertThat(XdsNameResolver.matchHostName("bar.googleapis.com.", pattern)).isFalse(); + } + @Test public void resolved_faultAbortInLdsUpdate() { resolver.start(mockListener); From 4adb94d844bd72d8c8614f3aa2e001b8aac2dcf3 Mon Sep 17 00:00:00 2001 From: PetitBaguette Date: Wed, 4 Feb 2026 21:37:09 +0900 Subject: [PATCH 2/6] style(xds): Fix line length in matchHostName_trailingDot test for checkstyle --- xds/src/test/java/io/grpc/xds/XdsNameResolverTest.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/xds/src/test/java/io/grpc/xds/XdsNameResolverTest.java b/xds/src/test/java/io/grpc/xds/XdsNameResolverTest.java index 8d6a1765ed9..86fcddfc62d 100644 --- a/xds/src/test/java/io/grpc/xds/XdsNameResolverTest.java +++ b/xds/src/test/java/io/grpc/xds/XdsNameResolverTest.java @@ -2067,8 +2067,10 @@ public void matchHostName_trailingDot() { // FQDN (trailing dot) is semantically equivalent to the relative form per RFC 1034 Section 3.1. assertThat(XdsNameResolver.matchHostName("foo.googleapis.com.", "foo.googleapis.com")).isTrue(); assertThat(XdsNameResolver.matchHostName("foo.googleapis.com", "foo.googleapis.com.")).isTrue(); - assertThat(XdsNameResolver.matchHostName("foo.googleapis.com.", "foo.googleapis.com.")).isTrue(); - assertThat(XdsNameResolver.matchHostName("bar.googleapis.com.", "foo.googleapis.com")).isFalse(); + assertThat(XdsNameResolver.matchHostName("foo.googleapis.com.", "foo.googleapis.com.")) + .isTrue(); + assertThat(XdsNameResolver.matchHostName("bar.googleapis.com.", "foo.googleapis.com")) + .isFalse(); // Wildcard + trailing dot combinations. String pattern = "*.foo.googleapis.com"; From cb2e509bef5586cdd386966cdfae5781a23ce1f9 Mon Sep 17 00:00:00 2001 From: petit_baguette Date: Thu, 5 Feb 2026 18:26:34 +0900 Subject: [PATCH 3/6] test(xds): Add trailing dot test for findVirtualHostForHostName in RoutingUtilsTest --- .../java/io/grpc/xds/RoutingUtilsTest.java | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/xds/src/test/java/io/grpc/xds/RoutingUtilsTest.java b/xds/src/test/java/io/grpc/xds/RoutingUtilsTest.java index a460501e85b..cd1afccbb9d 100644 --- a/xds/src/test/java/io/grpc/xds/RoutingUtilsTest.java +++ b/xds/src/test/java/io/grpc/xds/RoutingUtilsTest.java @@ -88,6 +88,54 @@ public void findVirtualHostForHostName_asteriskMatchAnyDomain() { .isEqualTo(vHost1); } + @Test + public void findVirtualHostForHostName_trailingDot() { + // FQDN (trailing dot) is semantically equivalent to the relative form + // per RFC 1034 Section 3.1. + List routes = Collections.emptyList(); + VirtualHost vHost1 = VirtualHost.create("virtualhost01.googleapis.com", + Collections.singletonList("a.googleapis.com"), routes, + ImmutableMap.of()); + VirtualHost vHost2 = VirtualHost.create("virtualhost02.googleapis.com", + Collections.singletonList("*.googleapis.com"), routes, + ImmutableMap.of()); + VirtualHost vHost3 = VirtualHost.create("virtualhost03.googleapis.com", + Collections.singletonList("*"), routes, + ImmutableMap.of()); + List virtualHosts = Arrays.asList(vHost1, vHost2, vHost3); + + // Trailing dot in hostName, exact match. + assertThat(RoutingUtils.findVirtualHostForHostName( + virtualHosts, "a.googleapis.com.")).isEqualTo(vHost1); + // Trailing dot in hostName, wildcard match. + assertThat(RoutingUtils.findVirtualHostForHostName( + virtualHosts, "b.googleapis.com.")).isEqualTo(vHost2); + + // Trailing dot in domain pattern, exact match. + VirtualHost vHost4 = VirtualHost.create("virtualhost04.googleapis.com", + Collections.singletonList("a.googleapis.com."), routes, + ImmutableMap.of()); + List virtualHosts2 = + Arrays.asList(vHost4, vHost2, vHost3); + assertThat(RoutingUtils.findVirtualHostForHostName( + virtualHosts2, "a.googleapis.com")).isEqualTo(vHost4); + + // Trailing dot in both hostName and domain pattern. + assertThat(RoutingUtils.findVirtualHostForHostName( + virtualHosts2, "a.googleapis.com.")).isEqualTo(vHost4); + + // Trailing dot in domain pattern, wildcard match. + VirtualHost vHost5 = VirtualHost.create("virtualhost05.googleapis.com", + Collections.singletonList("*.googleapis.com."), routes, + ImmutableMap.of()); + List virtualHosts3 = + Arrays.asList(vHost5, vHost3); + assertThat(RoutingUtils.findVirtualHostForHostName( + virtualHosts3, "b.googleapis.com")).isEqualTo(vHost5); + assertThat(RoutingUtils.findVirtualHostForHostName( + virtualHosts3, "b.googleapis.com.")).isEqualTo(vHost5); + } + @Test public void routeMatching_pathOnly() { Metadata headers = new Metadata(); From 4265498c56448f48cff354fa9e2ef9ed90003d28 Mon Sep 17 00:00:00 2001 From: petit_baguette Date: Thu, 5 Feb 2026 21:43:02 +0900 Subject: [PATCH 4/6] refactor(xds): Remove unused matchHostName from XdsNameResolver, move tests to RoutingUtilsTest --- .../java/io/grpc/xds/XdsNameResolver.java | 69 ----------------- .../java/io/grpc/xds/RoutingUtilsTest.java | 77 +++++++++++++++++++ .../java/io/grpc/xds/XdsNameResolverTest.java | 65 ---------------- 3 files changed, 77 insertions(+), 134 deletions(-) diff --git a/xds/src/main/java/io/grpc/xds/XdsNameResolver.java b/xds/src/main/java/io/grpc/xds/XdsNameResolver.java index 3021c035d04..cfc09bd5cad 100644 --- a/xds/src/main/java/io/grpc/xds/XdsNameResolver.java +++ b/xds/src/main/java/io/grpc/xds/XdsNameResolver.java @@ -341,75 +341,6 @@ private void updateResolutionResult(XdsConfig xdsConfig) { } } - /** - * Returns {@code true} iff {@code hostName} matches the domain name {@code pattern} with - * case-insensitive. - * - *

Wildcard pattern rules: - *

    - *
  1. A single asterisk (*) matches any domain.
  2. - *
  3. Asterisk (*) is only permitted in the left-most or the right-most part of the pattern, - * but not both.
  4. - *
- */ - @VisibleForTesting - static boolean matchHostName(String hostName, String pattern) { - checkArgument(hostName.length() != 0 && !hostName.startsWith("."), - "Invalid host name"); - checkArgument(pattern.length() != 0 && !pattern.startsWith("."), - "Invalid pattern/domain name"); - - hostName = hostName.toLowerCase(Locale.US); - pattern = pattern.toLowerCase(Locale.US); - // hostName and pattern are now in lower case -- domain names are case-insensitive. - - // Strip trailing dot to normalize FQDN (e.g. "example.com.") to a relative form, - // as per RFC 1034 Section 3.1 the two are semantically equivalent. - if (hostName.endsWith(".")) { - hostName = hostName.substring(0, hostName.length() - 1); - } - if (pattern.endsWith(".")) { - pattern = pattern.substring(0, pattern.length() - 1); - } - - if (!pattern.contains("*")) { - // Not a wildcard pattern -- hostName and pattern must match exactly. - return hostName.equals(pattern); - } - // Wildcard pattern - - if (pattern.length() == 1) { - return true; - } - - int index = pattern.indexOf('*'); - - // At most one asterisk (*) is allowed. - if (pattern.indexOf('*', index + 1) != -1) { - return false; - } - - // Asterisk can only match prefix or suffix. - if (index != 0 && index != pattern.length() - 1) { - return false; - } - - // HostName must be at least as long as the pattern because asterisk has to - // match one or more characters. - if (hostName.length() < pattern.length()) { - return false; - } - - if (index == 0 && hostName.endsWith(pattern.substring(1))) { - // Prefix matching fails. - return true; - } - - // Pattern matches hostname if suffix matching succeeds. - return index == pattern.length() - 1 - && hostName.startsWith(pattern.substring(0, pattern.length() - 1)); - } - private final class ConfigSelector extends InternalConfigSelector { @Override public Result selectConfig(PickSubchannelArgs args) { diff --git a/xds/src/test/java/io/grpc/xds/RoutingUtilsTest.java b/xds/src/test/java/io/grpc/xds/RoutingUtilsTest.java index cd1afccbb9d..817f5337330 100644 --- a/xds/src/test/java/io/grpc/xds/RoutingUtilsTest.java +++ b/xds/src/test/java/io/grpc/xds/RoutingUtilsTest.java @@ -136,6 +136,83 @@ public void findVirtualHostForHostName_trailingDot() { virtualHosts3, "b.googleapis.com.")).isEqualTo(vHost5); } + @Test + public void findVirtualHostForHostName_exactMatch() { + List routes = Collections.emptyList(); + VirtualHost vHostFoo = VirtualHost.create("vhost-foo", + Collections.singletonList("foo.googleapis.com"), routes, + ImmutableMap.of()); + VirtualHost vHostBar = VirtualHost.create("vhost-bar", + Collections.singletonList("bar.googleapis.com"), routes, + ImmutableMap.of()); + List virtualHosts = + Arrays.asList(vHostFoo, vHostBar); + + assertThat(RoutingUtils.findVirtualHostForHostName( + virtualHosts, "foo.googleapis.com")).isEqualTo(vHostFoo); + assertThat(RoutingUtils.findVirtualHostForHostName( + virtualHosts, "bar.googleapis.com")).isEqualTo(vHostBar); + // No match returns null. + assertThat(RoutingUtils.findVirtualHostForHostName( + virtualHosts, "baz.googleapis.com")).isNull(); + assertThat(RoutingUtils.findVirtualHostForHostName( + virtualHosts, "foo.googleapis")).isNull(); + } + + @Test + public void findVirtualHostForHostName_prefixWildcard() { + List routes = Collections.emptyList(); + VirtualHost vHostWild = VirtualHost.create("vhost-wild", + Collections.singletonList("*.foo.googleapis.com"), + routes, ImmutableMap.of()); + VirtualHost vHostOther = VirtualHost.create("vhost-other", + Collections.singletonList("other.googleapis.com"), + routes, ImmutableMap.of()); + List virtualHosts = + Arrays.asList(vHostWild, vHostOther); + + // Prefix wildcard matches. + assertThat(RoutingUtils.findVirtualHostForHostName( + virtualHosts, "bar.foo.googleapis.com")) + .isEqualTo(vHostWild); + // Base domain without subdomain does not match *.foo.googleapis.com. + assertThat(RoutingUtils.findVirtualHostForHostName( + virtualHosts, "foo.googleapis.com")).isNull(); + + // Longer prefix wildcard is preferred over shorter one. + VirtualHost vHostLong = VirtualHost.create("vhost-long", + Collections.singletonList("*.bar.foo.googleapis.com"), + routes, ImmutableMap.of()); + List virtualHosts2 = + Arrays.asList(vHostLong, vHostWild); + assertThat(RoutingUtils.findVirtualHostForHostName( + virtualHosts2, "baz.bar.foo.googleapis.com")) + .isEqualTo(vHostLong); + } + + @Test + public void findVirtualHostForHostName_postfixWildcard() { + List routes = Collections.emptyList(); + VirtualHost vHostWild = VirtualHost.create("vhost-wild", + Collections.singletonList("foo.*"), routes, + ImmutableMap.of()); + VirtualHost vHostOther = VirtualHost.create("vhost-other", + Collections.singletonList("bar.googleapis.com"), + routes, ImmutableMap.of()); + List virtualHosts = + Arrays.asList(vHostWild, vHostOther); + + // Postfix wildcard matches. + assertThat(RoutingUtils.findVirtualHostForHostName( + virtualHosts, "foo.googleapis.com")) + .isEqualTo(vHostWild); + assertThat(RoutingUtils.findVirtualHostForHostName( + virtualHosts, "foo.com")).isEqualTo(vHostWild); + // Different prefix does not match foo.*. + assertThat(RoutingUtils.findVirtualHostForHostName( + virtualHosts, "bar.foo.googleapis.com")).isNull(); + } + @Test public void routeMatching_pathOnly() { Metadata headers = new Metadata(); diff --git a/xds/src/test/java/io/grpc/xds/XdsNameResolverTest.java b/xds/src/test/java/io/grpc/xds/XdsNameResolverTest.java index 86fcddfc62d..3f50d92c2b5 100644 --- a/xds/src/test/java/io/grpc/xds/XdsNameResolverTest.java +++ b/xds/src/test/java/io/grpc/xds/XdsNameResolverTest.java @@ -2020,71 +2020,6 @@ public void generateServiceConfig_forPerMethodConfig() throws IOException { .isEqualTo(expectedServiceConfig); } - @Test - public void matchHostName_exactlyMatch() { - String pattern = "foo.googleapis.com"; - assertThat(XdsNameResolver.matchHostName("bar.googleapis.com", pattern)).isFalse(); - assertThat(XdsNameResolver.matchHostName("fo.googleapis.com", pattern)).isFalse(); - assertThat(XdsNameResolver.matchHostName("oo.googleapis.com", pattern)).isFalse(); - assertThat(XdsNameResolver.matchHostName("googleapis.com", pattern)).isFalse(); - assertThat(XdsNameResolver.matchHostName("foo.googleapis", pattern)).isFalse(); - assertThat(XdsNameResolver.matchHostName("foo.googleapis.com", pattern)).isTrue(); - } - - @Test - public void matchHostName_prefixWildcard() { - String pattern = "*.foo.googleapis.com"; - assertThat(XdsNameResolver.matchHostName("foo.googleapis.com", pattern)).isFalse(); - assertThat(XdsNameResolver.matchHostName("bar-baz.foo.googleapis", pattern)).isFalse(); - assertThat(XdsNameResolver.matchHostName("bar.foo.googleapis.com", pattern)).isTrue(); - pattern = "*-bar.foo.googleapis.com"; - assertThat(XdsNameResolver.matchHostName("bar.foo.googleapis.com", pattern)).isFalse(); - assertThat(XdsNameResolver.matchHostName("baz-bar.foo.googleapis", pattern)).isFalse(); - assertThat(XdsNameResolver.matchHostName("-bar.foo.googleapis.com", pattern)).isFalse(); - assertThat(XdsNameResolver.matchHostName("baz-bar.foo.googleapis.com", pattern)) - .isTrue(); - } - - @Test - public void matchHostName_postfixWildCard() { - String pattern = "foo.*"; - assertThat(XdsNameResolver.matchHostName("bar.googleapis.com", pattern)).isFalse(); - assertThat(XdsNameResolver.matchHostName("bar.foo.googleapis.com", pattern)).isFalse(); - assertThat(XdsNameResolver.matchHostName("foo.googleapis.com", pattern)).isTrue(); - assertThat(XdsNameResolver.matchHostName("foo.com", pattern)).isTrue(); - pattern = "foo-*"; - assertThat(XdsNameResolver.matchHostName("bar-.googleapis.com", pattern)).isFalse(); - assertThat(XdsNameResolver.matchHostName("foo.googleapis.com", pattern)).isFalse(); - assertThat(XdsNameResolver.matchHostName("foo.googleapis.com", pattern)).isFalse(); - assertThat(XdsNameResolver.matchHostName("foo-", pattern)).isFalse(); - assertThat(XdsNameResolver.matchHostName("foo-bar.com", pattern)).isTrue(); - assertThat(XdsNameResolver.matchHostName("foo-.com", pattern)).isTrue(); - assertThat(XdsNameResolver.matchHostName("foo-bar", pattern)).isTrue(); - } - - @Test - public void matchHostName_trailingDot() { - // FQDN (trailing dot) is semantically equivalent to the relative form per RFC 1034 Section 3.1. - assertThat(XdsNameResolver.matchHostName("foo.googleapis.com.", "foo.googleapis.com")).isTrue(); - assertThat(XdsNameResolver.matchHostName("foo.googleapis.com", "foo.googleapis.com.")).isTrue(); - assertThat(XdsNameResolver.matchHostName("foo.googleapis.com.", "foo.googleapis.com.")) - .isTrue(); - assertThat(XdsNameResolver.matchHostName("bar.googleapis.com.", "foo.googleapis.com")) - .isFalse(); - - // Wildcard + trailing dot combinations. - String pattern = "*.foo.googleapis.com"; - assertThat(XdsNameResolver.matchHostName("bar.foo.googleapis.com.", pattern)).isTrue(); - assertThat(XdsNameResolver.matchHostName("bar.foo.googleapis.com", pattern + ".")).isTrue(); - assertThat(XdsNameResolver.matchHostName("bar.foo.googleapis.com.", pattern + ".")).isTrue(); - assertThat(XdsNameResolver.matchHostName("foo.googleapis.com.", pattern)).isFalse(); - - pattern = "foo.*"; - assertThat(XdsNameResolver.matchHostName("foo.googleapis.com.", pattern)).isTrue(); - assertThat(XdsNameResolver.matchHostName("foo.com.", pattern)).isTrue(); - assertThat(XdsNameResolver.matchHostName("bar.googleapis.com.", pattern)).isFalse(); - } - @Test public void resolved_faultAbortInLdsUpdate() { resolver.start(mockListener); From 88e63d800846ead9231ec340b6e541a330de65be Mon Sep 17 00:00:00 2001 From: petit_baguette Date: Thu, 5 Feb 2026 21:53:29 +0900 Subject: [PATCH 5/6] chore(xds): remove unused import --- xds/src/main/java/io/grpc/xds/XdsNameResolver.java | 1 - 1 file changed, 1 deletion(-) diff --git a/xds/src/main/java/io/grpc/xds/XdsNameResolver.java b/xds/src/main/java/io/grpc/xds/XdsNameResolver.java index cfc09bd5cad..ec3e417e53a 100644 --- a/xds/src/main/java/io/grpc/xds/XdsNameResolver.java +++ b/xds/src/main/java/io/grpc/xds/XdsNameResolver.java @@ -73,7 +73,6 @@ import java.util.HashMap; import java.util.HashSet; import java.util.List; -import java.util.Locale; import java.util.Map; import java.util.Objects; import java.util.Set; From da579a1dc20550a1a507908a70707e7418bc31b6 Mon Sep 17 00:00:00 2001 From: petit_baguette Date: Thu, 5 Feb 2026 22:21:25 +0900 Subject: [PATCH 6/6] test(xds): Add invalid input tests for matchHostName in RoutingUtilsTest --- .../java/io/grpc/xds/RoutingUtilsTest.java | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/xds/src/test/java/io/grpc/xds/RoutingUtilsTest.java b/xds/src/test/java/io/grpc/xds/RoutingUtilsTest.java index 817f5337330..e9fde9f4c4a 100644 --- a/xds/src/test/java/io/grpc/xds/RoutingUtilsTest.java +++ b/xds/src/test/java/io/grpc/xds/RoutingUtilsTest.java @@ -17,6 +17,7 @@ package io.grpc.xds; import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertThrows; import static org.mockito.Mockito.mock; import com.google.common.collect.ImmutableMap; @@ -159,6 +160,45 @@ public void findVirtualHostForHostName_exactMatch() { virtualHosts, "foo.googleapis")).isNull(); } + @Test + public void findVirtualHostForHostName_invalidHostName() { + List routes = Collections.emptyList(); + VirtualHost vHost = VirtualHost.create("vhost", + Collections.singletonList("a.googleapis.com"), routes, + ImmutableMap.of()); + List virtualHosts = Collections.singletonList(vHost); + + // Empty hostName. + assertThrows(IllegalArgumentException.class, + () -> RoutingUtils.findVirtualHostForHostName( + virtualHosts, "")); + // HostName starting with dot. + assertThrows(IllegalArgumentException.class, + () -> RoutingUtils.findVirtualHostForHostName( + virtualHosts, ".a.googleapis.com")); + } + + @Test + public void findVirtualHostForHostName_invalidPattern() { + List routes = Collections.emptyList(); + // Empty domain pattern. + VirtualHost vHostEmpty = VirtualHost.create("vhost-empty", + Collections.singletonList(""), routes, + ImmutableMap.of()); + assertThrows(IllegalArgumentException.class, + () -> RoutingUtils.findVirtualHostForHostName( + Collections.singletonList(vHostEmpty), + "a.googleapis.com")); + // Domain pattern starting with dot. + VirtualHost vHostDot = VirtualHost.create("vhost-dot", + Collections.singletonList(".a.googleapis.com"), routes, + ImmutableMap.of()); + assertThrows(IllegalArgumentException.class, + () -> RoutingUtils.findVirtualHostForHostName( + Collections.singletonList(vHostDot), + "a.googleapis.com")); + } + @Test public void findVirtualHostForHostName_prefixWildcard() { List routes = Collections.emptyList();