Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 23 additions & 5 deletions core/src/main/java/io/grpc/internal/DnsNameResolver.java
Original file line number Diff line number Diff line change
Expand Up @@ -163,14 +163,32 @@ protected DnsNameResolver(
// Must prepend a "//" to the name when constructing a URI, otherwise it will be treated as an
// opaque URI, thus the authority and host of the resulted URI would be null.
URI nameUri = URI.create("//" + checkNotNull(name, "name"));
Preconditions.checkArgument(nameUri.getHost() != null, "Invalid DNS name: %s", name);
authority = Preconditions.checkNotNull(nameUri.getAuthority(),
"nameUri (%s) doesn't have an authority", nameUri);
host = nameUri.getHost();
if (nameUri.getPort() == -1) {
port = args.getDefaultPort();
if (nameUri.getHost() != null) {
host = nameUri.getHost();
if (nameUri.getPort() == -1) {
port = args.getDefaultPort();
} else {
port = nameUri.getPort();
}
} else {
port = nameUri.getPort();
// JDK-8188305: java.net.URI.getHost() returns null when the last label of a hostname
// starts with a digit (e.g. otlp.1234-k8s-namespace). Parse host and port from authority.
Preconditions.checkArgument(authority.indexOf('@') == -1, "Invalid DNS name: %s", name);
int colonIndex = authority.lastIndexOf(':');
if (colonIndex != -1 && (authority.indexOf(']') == -1 || colonIndex > authority.lastIndexOf(']'))) {
host = authority.substring(0, colonIndex);
try {
port = Integer.parseInt(authority.substring(colonIndex + 1));
} catch (NumberFormatException e) {
throw new IllegalArgumentException("Invalid DNS name: " + name, e);
}
} else {
host = authority;
port = args.getDefaultPort();
}
Preconditions.checkArgument(!host.isEmpty(), "Invalid DNS name: %s", name);
}
this.proxyDetector = checkNotNull(args.getProxyDetector(), "proxyDetector");
Executor offloadExecutor = args.getOffloadExecutor();
Expand Down
10 changes: 9 additions & 1 deletion core/src/main/java/io/grpc/internal/GrpcUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -547,7 +547,15 @@ public static String authorityFromHostAndPort(String host, int port) {
try {
return new URI(null, null, host, port, null, null, null).getAuthority();
} catch (URISyntaxException ex) {
throw new IllegalArgumentException("Invalid host or port: " + host + " " + port, ex);
// JDK-8188305: java.net.URI rejects valid RFC 1123 hostnames whose last label starts with
// a digit (e.g. otlp.1234-k8s-namespace). Fall back to manual combination and checkAuthority.
String formattedHost = (host.contains(":") && !host.startsWith("[")) ? "[" + host + "]" : host;
String authority = formattedHost + ":" + port;
try {
return checkAuthority(authority);
} catch (IllegalArgumentException e) {
throw new IllegalArgumentException("Invalid host or port: " + host + " " + port, ex);
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,16 @@ public void newNameResolver_acceptsHostAndPort() {
assertThat(((DnsNameResolver) nameResolver).getPort()).isEqualTo(443);
}

@Test
public void newNameResolver_acceptsHostStartingWithDigit() {
NameResolver nameResolver = newNameResolver("dns:///otlp.1234-k8s-namespace:4317", args);
assertThat(nameResolver).isNotNull();
assertThat(nameResolver.getClass()).isSameInstanceAs(DnsNameResolver.class);
assertThat(nameResolver.getServiceAuthority()).isEqualTo("otlp.1234-k8s-namespace:4317");
assertThat(((DnsNameResolver) nameResolver).getHost()).isEqualTo("otlp.1234-k8s-namespace");
assertThat(((DnsNameResolver) nameResolver).getPort()).isEqualTo(4317);
}

@Test
public void newNameResolver_acceptsRootless() {
assume().that(enableRfc3986UrisParam).isTrue();
Expand Down
6 changes: 6 additions & 0 deletions core/src/test/java/io/grpc/internal/GrpcUtilTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,12 @@ public void checkAuthority_failsOnNull() {
assertThrows(NullPointerException.class, () -> GrpcUtil.checkAuthority(null));
}

@Test
public void authorityFromHostAndPort_succeedsOnHostStartingWithDigit() {
String actual = GrpcUtil.authorityFromHostAndPort("otlp.1234-k8s-namespace", 4317);
assertEquals("otlp.1234-k8s-namespace:4317", actual);
}

@Test
public void checkAuthority_succeedsOnHostAndPort() {
String actual = GrpcUtil.checkAuthority("valid:1234");
Expand Down
Loading