From 303b550a57c1f6e10fcd9519c960a5d889ce3b72 Mon Sep 17 00:00:00 2001 From: John Cormie Date: Mon, 20 Apr 2026 11:21:09 -0700 Subject: [PATCH] api: Turn on RFC 3986 parsing by default and update javadoc. Removed the "NameResolver-compliant" terminology because it's no longer needed. All RFC 3986 URIs are absolute in the sense that have a scheme (URI != "URI-reference"). RFC 3986 also does away with the hierarchical vs opaque distinction. All URIs now have a hierarchy of components (scheme, authority, path, query and fragment) it's just that some components can be absent and/or the empty string. Added discussion of ambiguity which is technically new with the RFC 3986 change. If you believed the current javadoc, a target like foo:8888 didn't used to be ambiguous because it is not a "valid NameResolver- compliant" URI -- the path doesn't start with / and so java.net.URI considers it opaque, not hierarchical as required. Fortunately (???) ManagedChannelImplBuilder never enforced the !isOpaque() requirement mentioned in the javadoc and so this ambiguity isn't actually new in practice. gRPC C++ also appears to suffer from the same problem. --- api/src/main/java/io/grpc/FeatureFlags.java | 2 +- api/src/main/java/io/grpc/Grpc.java | 25 ++++++++++++------- .../java/io/grpc/ManagedChannelBuilder.java | 25 ++++++++++++------- 3 files changed, 33 insertions(+), 19 deletions(-) diff --git a/api/src/main/java/io/grpc/FeatureFlags.java b/api/src/main/java/io/grpc/FeatureFlags.java index 0e414ed7b31..36fec1b9a59 100644 --- a/api/src/main/java/io/grpc/FeatureFlags.java +++ b/api/src/main/java/io/grpc/FeatureFlags.java @@ -20,7 +20,7 @@ import com.google.common.base.Strings; class FeatureFlags { - private static boolean enableRfc3986Uris = getFlag("GRPC_ENABLE_RFC3986_URIS", false); + private static boolean enableRfc3986Uris = getFlag("GRPC_ENABLE_RFC3986_URIS", true); /** Whether to parse targets as RFC 3986 URIs (true), or use {@link java.net.URI} (false). */ @VisibleForTesting diff --git a/api/src/main/java/io/grpc/Grpc.java b/api/src/main/java/io/grpc/Grpc.java index a45c613fd18..f211ea999d6 100644 --- a/api/src/main/java/io/grpc/Grpc.java +++ b/api/src/main/java/io/grpc/Grpc.java @@ -73,11 +73,10 @@ private Grpc() { public @interface TransportAttr {} /** - * Creates a channel builder with a target string and credentials. The target can be either a - * valid {@link NameResolver}-compliant URI, or an authority string. + * Creates a channel builder with a target string and credentials. The target can be either an RFC + * 3986 URI, or an authority string. * - *

A {@code NameResolver}-compliant URI is an absolute hierarchical URI as defined by {@link - * java.net.URI}. Example URIs: + *

Example URIs: *

* - *

An authority string will be converted to a {@code NameResolver}-compliant URI, which has - * the scheme from the name resolver with the highest priority (e.g. {@code "dns"}), - * no authority, and the original authority string as its path after properly escaped. - * We recommend libraries to specify the schema explicitly if it is known, since libraries cannot - * know which NameResolver will be default during runtime. + *

An authority string will be converted to a URI having the scheme of the name resolver with + * the highest priority (e.g. {@code "dns"}), the empty string as the authority, and + * {@code target} as its absolute path. We recommend libraries specify {@code target} as a URI + * instead since they cannot know which NameResolver will be default at runtime. * Example authority strings: *

+ * + *

We strongly recommend the URI form of {@code target} because the alternative is ambiguous. + * For example, the target string {@code foo:8080} is a valid authority string with host + * {@code foo} and port {@code 8080} but it is also a valid RFC 3986 URI with scheme {@code foo} + * and path {@code 8080}. {@code NameResolver}s are discovered dynamically from your classpath + * using SPI, so it's hard to be sure in advance how such a target will be resolved. A + * {@code NameResolver} for scheme {@code foo} might someday make a host named {@code foo} + * unreachable! On the other hand, the {@code dns:///foo:8080} target will always behave the same. */ public static ManagedChannelBuilder newChannelBuilder( String target, ChannelCredentials creds) { diff --git a/api/src/main/java/io/grpc/ManagedChannelBuilder.java b/api/src/main/java/io/grpc/ManagedChannelBuilder.java index 3f370ab3003..e1f9e8db0b2 100644 --- a/api/src/main/java/io/grpc/ManagedChannelBuilder.java +++ b/api/src/main/java/io/grpc/ManagedChannelBuilder.java @@ -45,11 +45,10 @@ public static ManagedChannelBuilder forAddress(String name, int port) { } /** - * Creates a channel with a target string, which can be either a valid {@link - * NameResolver}-compliant URI, or an authority string. + * Creates a channel with a target string, which can be either an RFC 3986 URI, or an authority + * string. * - *

A {@code NameResolver}-compliant URI is an absolute hierarchical URI as defined by {@link - * java.net.URI}. Example URIs: + *

Example URIs: *

* - *

An authority string will be converted to a {@code NameResolver}-compliant URI, which has - * the scheme from the name resolver with the highest priority (e.g. {@code "dns"}), - * no authority, and the original authority string as its path after properly escaped. - * We recommend libraries to specify the schema explicitly if it is known, since libraries cannot - * know which NameResolver will be default during runtime. + *

An authority string will be converted to a URI having the scheme of the name resolver with + * the highest priority (e.g. {@code "dns"}), the empty string as the authority, and + * {@code target} as its absolute path. We recommend libraries specify {@code target} as a URI + * instead since they cannot know which NameResolver will be default at runtime. * Example authority strings: *

* + *

We strongly recommend the URI form of {@code target} because the alternative is ambiguous. + * For example, the target string {@code foo:8080} is a valid authority string with host + * {@code foo} and port {@code 8080} but it is also a valid RFC 3986 URI with scheme {@code foo} + * and path {@code 8080}. {@code NameResolver}s are discovered dynamically from your classpath + * using SPI, so it's hard to be sure in advance how such a target will be resolved. A + * {@code NameResolver} for scheme {@code foo} might someday make a host named {@code foo} + * unreachable! On the other hand, the {@code dns:///foo:8080} target will always behave the same. + * *

Note that there is an open JDK bug on {@link java.net.URI} class parsing an ipv6 scope ID: * bugs.openjdk.org/browse/JDK-8199396. This method is exposed to this bug. If you experience an * issue, a work-around is to convert the scope ID to its numeric form (e.g. by using