Skip to content

Commit f06ae56

Browse files
committed
core: Use io.grpc.Uri to parse the target, if flagged
1 parent 54fdc07 commit f06ae56

File tree

4 files changed

+353
-25
lines changed

4 files changed

+353
-25
lines changed

core/src/main/java/io/grpc/internal/ManagedChannelImplBuilder.java

Lines changed: 66 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
import io.grpc.NameResolverRegistry;
4848
import io.grpc.ProxyDetector;
4949
import io.grpc.StatusOr;
50+
import io.grpc.Uri;
5051
import java.lang.reflect.InvocationTargetException;
5152
import java.lang.reflect.Method;
5253
import java.net.SocketAddress;
@@ -105,6 +106,12 @@ public static ManagedChannelBuilder<?> forTarget(String target) {
105106
*/
106107
static final long IDLE_MODE_MIN_TIMEOUT_MILLIS = TimeUnit.SECONDS.toMillis(1);
107108

109+
/**
110+
* Whether to parse targets as RFC 3986 URIs (true), or use {@link java.net.URI} (false).
111+
*/
112+
@VisibleForTesting
113+
static boolean enableRfc3986Uris = GrpcUtil.getFlag("GRPC_ENABLE_RFC3986_URIS", false);
114+
108115
private static final ObjectPool<? extends Executor> DEFAULT_EXECUTOR_POOL =
109116
SharedResourcePool.forResource(GrpcUtil.SHARED_CHANNEL_EXECUTOR);
110117

@@ -719,8 +726,11 @@ protected ManagedChannelImplBuilder addMetricSink(MetricSink metricSink) {
719726
public ManagedChannel build() {
720727
ClientTransportFactory clientTransportFactory =
721728
clientTransportFactoryBuilder.buildClientTransportFactory();
722-
ResolvedNameResolver resolvedResolver = getNameResolverProvider(
723-
target, nameResolverRegistry, clientTransportFactory.getSupportedSocketAddressTypes());
729+
ResolvedNameResolver resolvedResolver =
730+
enableRfc3986Uris
731+
? getNameResolverProviderRfc3986(target, nameResolverRegistry)
732+
: getNameResolverProvider(target, nameResolverRegistry);
733+
resolvedResolver.checkAddressTypes(clientTransportFactory.getSupportedSocketAddressTypes());
724734
return new ManagedChannelOrphanWrapper(new ManagedChannelImpl(
725735
this,
726736
clientTransportFactory,
@@ -822,12 +832,25 @@ public ResolvedNameResolver(UriWrapper targetUri, NameResolverProvider provider)
822832
this.targetUri = checkNotNull(targetUri, "targetUri");
823833
this.provider = checkNotNull(provider, "provider");
824834
}
835+
836+
void checkAddressTypes(
837+
Collection<Class<? extends SocketAddress>> channelTransportSocketAddressTypes) {
838+
if (channelTransportSocketAddressTypes != null) {
839+
Collection<Class<? extends SocketAddress>> nameResolverSocketAddressTypes =
840+
provider.getProducedSocketAddressTypes();
841+
if (!channelTransportSocketAddressTypes.containsAll(nameResolverSocketAddressTypes)) {
842+
throw new IllegalArgumentException(
843+
String.format(
844+
"Address types of NameResolver '%s' for '%s' not supported by transport",
845+
provider.getDefaultScheme(), targetUri));
846+
}
847+
}
848+
}
825849
}
826850

827851
@VisibleForTesting
828852
static ResolvedNameResolver getNameResolverProvider(
829-
String target, NameResolverRegistry nameResolverRegistry,
830-
Collection<Class<? extends SocketAddress>> channelTransportSocketAddressTypes) {
853+
String target, NameResolverRegistry nameResolverRegistry) {
831854
// Finding a NameResolver. Try using the target string as the URI. If that fails, try prepending
832855
// "dns:///".
833856
NameResolverProvider provider = null;
@@ -863,14 +886,45 @@ static ResolvedNameResolver getNameResolverProvider(
863886
target, uriSyntaxErrors.length() > 0 ? " (" + uriSyntaxErrors + ")" : ""));
864887
}
865888

866-
if (channelTransportSocketAddressTypes != null) {
867-
Collection<Class<? extends SocketAddress>> nameResolverSocketAddressTypes
868-
= provider.getProducedSocketAddressTypes();
869-
if (!channelTransportSocketAddressTypes.containsAll(nameResolverSocketAddressTypes)) {
870-
throw new IllegalArgumentException(String.format(
871-
"Address types of NameResolver '%s' for '%s' not supported by transport",
872-
targetUri.getScheme(), target));
873-
}
889+
return new ResolvedNameResolver(wrap(targetUri), provider);
890+
}
891+
892+
static ResolvedNameResolver getNameResolverProviderRfc3986(
893+
String target, NameResolverRegistry nameResolverRegistry) {
894+
// Finding a NameResolver. Try using the target string as the URI. If that fails, try prepending
895+
// "dns:///".
896+
NameResolverProvider provider = null;
897+
Uri targetUri = null;
898+
StringBuilder uriSyntaxErrors = new StringBuilder();
899+
try {
900+
targetUri = Uri.parse(target);
901+
} catch (URISyntaxException e) {
902+
// Can happen with ip addresses like "[::1]:1234" or 127.0.0.1:1234.
903+
uriSyntaxErrors.append(e.getMessage());
904+
}
905+
if (targetUri != null) {
906+
// For "localhost:8080" this would likely cause provider to be null, because "localhost" is
907+
// parsed as the scheme. Will hit the next case and try "dns:///localhost:8080".
908+
provider = nameResolverRegistry.getProviderForScheme(targetUri.getScheme());
909+
}
910+
911+
if (provider == null && !URI_PATTERN.matcher(target).matches()) {
912+
// It doesn't look like a URI target. Maybe it's an authority string. Try with the default
913+
// scheme from the registry.
914+
targetUri =
915+
Uri.newBuilder()
916+
.setScheme(nameResolverRegistry.getDefaultScheme())
917+
.setHost("")
918+
.setPath("/" + target)
919+
.build();
920+
provider = nameResolverRegistry.getProviderForScheme(targetUri.getScheme());
921+
}
922+
923+
if (provider == null) {
924+
throw new IllegalArgumentException(
925+
String.format(
926+
"Could not find a NameResolverProvider for %s%s",
927+
target, uriSyntaxErrors.length() > 0 ? " (" + uriSyntaxErrors + ")" : ""));
874928
}
875929

876930
return new ResolvedNameResolver(wrap(targetUri), provider);

core/src/test/java/io/grpc/internal/ManagedChannelImplBuilderTest.java

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -69,13 +69,15 @@
6969
import org.junit.Rule;
7070
import org.junit.Test;
7171
import org.junit.runner.RunWith;
72-
import org.junit.runners.JUnit4;
72+
import org.junit.runners.Parameterized;
73+
import org.junit.runners.Parameterized.Parameter;
74+
import org.junit.runners.Parameterized.Parameters;
7375
import org.mockito.Mock;
7476
import org.mockito.junit.MockitoJUnit;
7577
import org.mockito.junit.MockitoRule;
7678

7779
/** Unit tests for {@link ManagedChannelImplBuilder}. */
78-
@RunWith(JUnit4.class)
80+
@RunWith(Parameterized.class)
7981
public class ManagedChannelImplBuilderTest {
8082
private static final int DUMMY_PORT = 42;
8183
private static final String DUMMY_TARGET = "fake-target";
@@ -98,6 +100,13 @@ public <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(
98100
}
99101
};
100102

103+
@Parameters(name = "enableRfc3986UrisParam={0}")
104+
public static Iterable<Object[]> data() {
105+
return Arrays.asList(new Object[][] {{true}, {false}});
106+
}
107+
108+
@Parameter public boolean enableRfc3986UrisParam;
109+
101110
@Rule public final MockitoRule mocks = MockitoJUnit.rule();
102111
@Rule public final GrpcCleanupRule grpcCleanupRule = new GrpcCleanupRule();
103112

@@ -117,6 +126,7 @@ public <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(
117126

118127
@Before
119128
public void setUp() throws Exception {
129+
ManagedChannelImplBuilder.enableRfc3986Uris = enableRfc3986UrisParam;
120130
builder = new ManagedChannelImplBuilder(
121131
DUMMY_TARGET,
122132
new UnsupportedClientTransportFactoryBuilder(),
@@ -373,8 +383,11 @@ public void transportDoesNotSupportAddressTypes() {
373383
ManagedChannel unused = grpcCleanupRule.register(builder.build());
374384
fail("Should fail");
375385
} catch (IllegalArgumentException e) {
376-
assertThat(e).hasMessageThat().isEqualTo(
377-
"Address types of NameResolver 'dns' for 'valid:1234' not supported by transport");
386+
assertThat(e)
387+
.hasMessageThat()
388+
.isEqualTo(
389+
"Address types of NameResolver 'dns' for 'dns:///valid:1234' not supported by"
390+
+ " transport");
378391
}
379392
}
380393

0 commit comments

Comments
 (0)