|
47 | 47 | import io.grpc.NameResolverRegistry; |
48 | 48 | import io.grpc.ProxyDetector; |
49 | 49 | import io.grpc.StatusOr; |
| 50 | +import io.grpc.Uri; |
50 | 51 | import java.lang.reflect.InvocationTargetException; |
51 | 52 | import java.lang.reflect.Method; |
52 | 53 | import java.net.SocketAddress; |
@@ -105,6 +106,12 @@ public static ManagedChannelBuilder<?> forTarget(String target) { |
105 | 106 | */ |
106 | 107 | static final long IDLE_MODE_MIN_TIMEOUT_MILLIS = TimeUnit.SECONDS.toMillis(1); |
107 | 108 |
|
| 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 | + |
108 | 115 | private static final ObjectPool<? extends Executor> DEFAULT_EXECUTOR_POOL = |
109 | 116 | SharedResourcePool.forResource(GrpcUtil.SHARED_CHANNEL_EXECUTOR); |
110 | 117 |
|
@@ -719,8 +726,11 @@ protected ManagedChannelImplBuilder addMetricSink(MetricSink metricSink) { |
719 | 726 | public ManagedChannel build() { |
720 | 727 | ClientTransportFactory clientTransportFactory = |
721 | 728 | 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()); |
724 | 734 | return new ManagedChannelOrphanWrapper(new ManagedChannelImpl( |
725 | 735 | this, |
726 | 736 | clientTransportFactory, |
@@ -822,12 +832,25 @@ public ResolvedNameResolver(UriWrapper targetUri, NameResolverProvider provider) |
822 | 832 | this.targetUri = checkNotNull(targetUri, "targetUri"); |
823 | 833 | this.provider = checkNotNull(provider, "provider"); |
824 | 834 | } |
| 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 | + } |
825 | 849 | } |
826 | 850 |
|
827 | 851 | @VisibleForTesting |
828 | 852 | static ResolvedNameResolver getNameResolverProvider( |
829 | | - String target, NameResolverRegistry nameResolverRegistry, |
830 | | - Collection<Class<? extends SocketAddress>> channelTransportSocketAddressTypes) { |
| 853 | + String target, NameResolverRegistry nameResolverRegistry) { |
831 | 854 | // Finding a NameResolver. Try using the target string as the URI. If that fails, try prepending |
832 | 855 | // "dns:///". |
833 | 856 | NameResolverProvider provider = null; |
@@ -863,14 +886,45 @@ static ResolvedNameResolver getNameResolverProvider( |
863 | 886 | target, uriSyntaxErrors.length() > 0 ? " (" + uriSyntaxErrors + ")" : "")); |
864 | 887 | } |
865 | 888 |
|
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 + ")" : "")); |
874 | 928 | } |
875 | 929 |
|
876 | 930 | return new ResolvedNameResolver(wrap(targetUri), provider); |
|
0 commit comments