Skip to content

Commit 8f852d6

Browse files
committed
core: Use io.grpc.Uri to parse the target, if flagged
1 parent eb7ecd5 commit 8f852d6

File tree

4 files changed

+357
-25
lines changed

4 files changed

+357
-25
lines changed

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

Lines changed: 60 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;
@@ -719,8 +720,11 @@ protected ManagedChannelImplBuilder addMetricSink(MetricSink metricSink) {
719720
public ManagedChannel build() {
720721
ClientTransportFactory clientTransportFactory =
721722
clientTransportFactoryBuilder.buildClientTransportFactory();
722-
ResolvedNameResolver resolvedResolver = getNameResolverProvider(
723-
target, nameResolverRegistry, clientTransportFactory.getSupportedSocketAddressTypes());
723+
ResolvedNameResolver resolvedResolver =
724+
GrpcUtil.getFlag("GRPC_ENABLE_RFC3986_URIS", false)
725+
? getNameResolverProviderNew(target, nameResolverRegistry)
726+
: getNameResolverProvider(target, nameResolverRegistry);
727+
resolvedResolver.checkAddressTypes(clientTransportFactory.getSupportedSocketAddressTypes());
724728
return new ManagedChannelOrphanWrapper(new ManagedChannelImpl(
725729
this,
726730
clientTransportFactory,
@@ -822,12 +826,25 @@ public ResolvedNameResolver(UriWrapper targetUri, NameResolverProvider provider)
822826
this.targetUri = checkNotNull(targetUri, "targetUri");
823827
this.provider = checkNotNull(provider, "provider");
824828
}
829+
830+
void checkAddressTypes(
831+
Collection<Class<? extends SocketAddress>> channelTransportSocketAddressTypes) {
832+
if (channelTransportSocketAddressTypes != null) {
833+
Collection<Class<? extends SocketAddress>> nameResolverSocketAddressTypes =
834+
provider.getProducedSocketAddressTypes();
835+
if (!channelTransportSocketAddressTypes.containsAll(nameResolverSocketAddressTypes)) {
836+
throw new IllegalArgumentException(
837+
String.format(
838+
"Address types of NameResolver '%s' for '%s' not supported by transport",
839+
provider.getDefaultScheme(), targetUri));
840+
}
841+
}
842+
}
825843
}
826844

827845
@VisibleForTesting
828846
static ResolvedNameResolver getNameResolverProvider(
829-
String target, NameResolverRegistry nameResolverRegistry,
830-
Collection<Class<? extends SocketAddress>> channelTransportSocketAddressTypes) {
847+
String target, NameResolverRegistry nameResolverRegistry) {
831848
// Finding a NameResolver. Try using the target string as the URI. If that fails, try prepending
832849
// "dns:///".
833850
NameResolverProvider provider = null;
@@ -863,14 +880,45 @@ static ResolvedNameResolver getNameResolverProvider(
863880
target, uriSyntaxErrors.length() > 0 ? " (" + uriSyntaxErrors + ")" : ""));
864881
}
865882

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-
}
883+
return new ResolvedNameResolver(wrap(targetUri), provider);
884+
}
885+
886+
static ResolvedNameResolver getNameResolverProviderNew(
887+
String target, NameResolverRegistry nameResolverRegistry) {
888+
// Finding a NameResolver. Try using the target string as the URI. If that fails, try prepending
889+
// "dns:///".
890+
NameResolverProvider provider = null;
891+
Uri targetUri = null;
892+
StringBuilder uriSyntaxErrors = new StringBuilder();
893+
try {
894+
targetUri = Uri.parse(target);
895+
} catch (URISyntaxException e) {
896+
// Can happen with ip addresses like "[::1]:1234" or 127.0.0.1:1234.
897+
uriSyntaxErrors.append(e.getMessage());
898+
}
899+
if (targetUri != null) {
900+
// For "localhost:8080" this would likely cause provider to be null, because "localhost" is
901+
// parsed as the scheme. Will hit the next case and try "dns:///localhost:8080".
902+
provider = nameResolverRegistry.getProviderForScheme(targetUri.getScheme());
903+
}
904+
905+
if (provider == null && !URI_PATTERN.matcher(target).matches()) {
906+
// It doesn't look like a URI target. Maybe it's an authority string. Try with the default
907+
// scheme from the registry.
908+
targetUri =
909+
Uri.newBuilder()
910+
.setScheme(nameResolverRegistry.getDefaultScheme())
911+
.setHost("")
912+
.setPath("/" + target)
913+
.build();
914+
provider = nameResolverRegistry.getProviderForScheme(targetUri.getScheme());
915+
}
916+
917+
if (provider == null) {
918+
throw new IllegalArgumentException(
919+
String.format(
920+
"Could not find a NameResolverProvider for %s%s",
921+
target, uriSyntaxErrors.length() > 0 ? " (" + uriSyntaxErrors + ")" : ""));
874922
}
875923

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

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

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package io.grpc.internal;
1818

1919
import static com.google.common.truth.Truth.assertThat;
20+
import static io.grpc.internal.TestUtils.setFlagForScope;
2021
import static junit.framework.TestCase.assertFalse;
2122
import static org.junit.Assert.assertEquals;
2223
import static org.junit.Assert.assertNotEquals;
@@ -56,26 +57,31 @@
5657
import java.net.InetSocketAddress;
5758
import java.net.SocketAddress;
5859
import java.net.URI;
60+
import java.util.ArrayDeque;
5961
import java.util.ArrayList;
6062
import java.util.Arrays;
6163
import java.util.Collections;
64+
import java.util.Deque;
6265
import java.util.HashMap;
6366
import java.util.List;
6467
import java.util.Map;
6568
import java.util.concurrent.Executor;
6669
import java.util.concurrent.TimeUnit;
6770
import java.util.regex.Pattern;
71+
import org.junit.After;
6872
import org.junit.Before;
6973
import org.junit.Rule;
7074
import org.junit.Test;
7175
import org.junit.runner.RunWith;
72-
import org.junit.runners.JUnit4;
76+
import org.junit.runners.Parameterized;
77+
import org.junit.runners.Parameterized.Parameter;
78+
import org.junit.runners.Parameterized.Parameters;
7379
import org.mockito.Mock;
7480
import org.mockito.junit.MockitoJUnit;
7581
import org.mockito.junit.MockitoRule;
7682

7783
/** Unit tests for {@link ManagedChannelImplBuilder}. */
78-
@RunWith(JUnit4.class)
84+
@RunWith(Parameterized.class)
7985
public class ManagedChannelImplBuilderTest {
8086
private static final int DUMMY_PORT = 42;
8187
private static final String DUMMY_TARGET = "fake-target";
@@ -98,6 +104,13 @@ public <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(
98104
}
99105
};
100106

107+
@Parameters(name = "enableRfc3986UrisParam={0}")
108+
public static Iterable<Object[]> data() {
109+
return Arrays.asList(new Object[][] {{true}, {false}});
110+
}
111+
112+
@Parameter public boolean enableRfc3986UrisParam;
113+
101114
@Rule public final MockitoRule mocks = MockitoJUnit.rule();
102115
@Rule public final GrpcCleanupRule grpcCleanupRule = new GrpcCleanupRule();
103116

@@ -114,9 +127,12 @@ public <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(
114127
"io\\.grpc\\.InternalConfigurator|io\\.grpc\\.Configurator|"
115128
+ "io\\.grpc\\.InternalConfiguratorRegistry|io\\.grpc\\.ConfiguratorRegistry|"
116129
+ "io\\.grpc\\.internal\\.[^.]+"));
130+
private final Deque<AutoCloseable> toBeClosedUponTeardown = new ArrayDeque<>();
117131

118132
@Before
119133
public void setUp() throws Exception {
134+
toBeClosedUponTeardown.push(
135+
setFlagForScope("GRPC_ENABLE_RFC3986_URIS", enableRfc3986UrisParam));
120136
builder = new ManagedChannelImplBuilder(
121137
DUMMY_TARGET,
122138
new UnsupportedClientTransportFactoryBuilder(),
@@ -128,6 +144,13 @@ public void setUp() throws Exception {
128144
new FixedPortProvider(DUMMY_PORT));
129145
}
130146

147+
@After
148+
public void cleanUpCloseables() throws Exception {
149+
while (!toBeClosedUponTeardown.isEmpty()) {
150+
toBeClosedUponTeardown.pop().close();
151+
}
152+
}
153+
131154
/** Ensure getDefaultPort() returns default port when no custom implementation provided. */
132155
@Test
133156
public void getDefaultPort_default() {
@@ -373,8 +396,11 @@ public void transportDoesNotSupportAddressTypes() {
373396
ManagedChannel unused = grpcCleanupRule.register(builder.build());
374397
fail("Should fail");
375398
} catch (IllegalArgumentException e) {
376-
assertThat(e).hasMessageThat().isEqualTo(
377-
"Address types of NameResolver 'dns' for 'valid:1234' not supported by transport");
399+
assertThat(e)
400+
.hasMessageThat()
401+
.isEqualTo(
402+
"Address types of NameResolver 'dns' for 'dns:///valid:1234' not supported by"
403+
+ " transport");
378404
}
379405
}
380406

0 commit comments

Comments
 (0)