Skip to content

Commit 7ef40a9

Browse files
committed
core: Use io.grpc.Uri to parse the target, if flagged
1 parent fc5efee commit 7ef40a9

File tree

4 files changed

+361
-25
lines changed

4 files changed

+361
-25
lines changed

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

Lines changed: 71 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,16 @@ public static ManagedChannelBuilder<?> forTarget(String target) {
105106
*/
106107
static final long IDLE_MODE_MIN_TIMEOUT_MILLIS = TimeUnit.SECONDS.toMillis(1);
107108

109+
private static boolean enableRfc3986Uris = GrpcUtil.getFlag("GRPC_ENABLE_RFC3986_URIS", false);
110+
111+
/** Whether to parse targets as RFC 3986 URIs (true), or use {@link java.net.URI} (false). */
112+
@VisibleForTesting
113+
static boolean setRfc3986UrisEnabled(boolean value) {
114+
boolean prevValue = ManagedChannelImplBuilder.enableRfc3986Uris;
115+
ManagedChannelImplBuilder.enableRfc3986Uris = value;
116+
return prevValue;
117+
}
118+
108119
private static final ObjectPool<? extends Executor> DEFAULT_EXECUTOR_POOL =
109120
SharedResourcePool.forResource(GrpcUtil.SHARED_CHANNEL_EXECUTOR);
110121

@@ -719,8 +730,11 @@ protected ManagedChannelImplBuilder addMetricSink(MetricSink metricSink) {
719730
public ManagedChannel build() {
720731
ClientTransportFactory clientTransportFactory =
721732
clientTransportFactoryBuilder.buildClientTransportFactory();
722-
ResolvedNameResolver resolvedResolver = getNameResolverProvider(
723-
target, nameResolverRegistry, clientTransportFactory.getSupportedSocketAddressTypes());
733+
ResolvedNameResolver resolvedResolver =
734+
enableRfc3986Uris
735+
? getNameResolverProviderRfc3986(target, nameResolverRegistry)
736+
: getNameResolverProvider(target, nameResolverRegistry);
737+
resolvedResolver.checkAddressTypes(clientTransportFactory.getSupportedSocketAddressTypes());
724738
return new ManagedChannelOrphanWrapper(new ManagedChannelImpl(
725739
this,
726740
clientTransportFactory,
@@ -822,12 +836,25 @@ public ResolvedNameResolver(UriWrapper targetUri, NameResolverProvider provider)
822836
this.targetUri = checkNotNull(targetUri, "targetUri");
823837
this.provider = checkNotNull(provider, "provider");
824838
}
839+
840+
void checkAddressTypes(
841+
Collection<Class<? extends SocketAddress>> channelTransportSocketAddressTypes) {
842+
if (channelTransportSocketAddressTypes != null) {
843+
Collection<Class<? extends SocketAddress>> nameResolverSocketAddressTypes =
844+
provider.getProducedSocketAddressTypes();
845+
if (!channelTransportSocketAddressTypes.containsAll(nameResolverSocketAddressTypes)) {
846+
throw new IllegalArgumentException(
847+
String.format(
848+
"Address types of NameResolver '%s' for '%s' not supported by transport",
849+
provider.getDefaultScheme(), targetUri));
850+
}
851+
}
852+
}
825853
}
826854

827855
@VisibleForTesting
828856
static ResolvedNameResolver getNameResolverProvider(
829-
String target, NameResolverRegistry nameResolverRegistry,
830-
Collection<Class<? extends SocketAddress>> channelTransportSocketAddressTypes) {
857+
String target, NameResolverRegistry nameResolverRegistry) {
831858
// Finding a NameResolver. Try using the target string as the URI. If that fails, try prepending
832859
// "dns:///".
833860
NameResolverProvider provider = null;
@@ -863,14 +890,46 @@ static ResolvedNameResolver getNameResolverProvider(
863890
target, uriSyntaxErrors.length() > 0 ? " (" + uriSyntaxErrors + ")" : ""));
864891
}
865892

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

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

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

Lines changed: 20 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,8 +100,16 @@ 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();
112+
@Rule public final FlagResetRule flagResetRule = new FlagResetRule();
103113

104114
@Mock private ClientTransportFactory mockClientTransportFactory;
105115
@Mock private ClientTransportFactoryBuilder mockClientTransportFactoryBuilder;
@@ -117,6 +127,9 @@ public <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(
117127

118128
@Before
119129
public void setUp() throws Exception {
130+
flagResetRule.setFlagForTest(
131+
ManagedChannelImplBuilder::setRfc3986UrisEnabled, enableRfc3986UrisParam);
132+
120133
builder = new ManagedChannelImplBuilder(
121134
DUMMY_TARGET,
122135
new UnsupportedClientTransportFactoryBuilder(),
@@ -373,8 +386,11 @@ public void transportDoesNotSupportAddressTypes() {
373386
ManagedChannel unused = grpcCleanupRule.register(builder.build());
374387
fail("Should fail");
375388
} catch (IllegalArgumentException e) {
376-
assertThat(e).hasMessageThat().isEqualTo(
377-
"Address types of NameResolver 'dns' for 'valid:1234' not supported by transport");
389+
assertThat(e)
390+
.hasMessageThat()
391+
.isEqualTo(
392+
"Address types of NameResolver 'dns' for 'dns:///valid:1234' not supported by"
393+
+ " transport");
378394
}
379395
}
380396

0 commit comments

Comments
 (0)