diff --git a/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/connection/RouteSelector.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/connection/RouteSelector.kt index c4fc3149d817..548d2bac48b4 100644 --- a/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/connection/RouteSelector.kt +++ b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/connection/RouteSelector.kt @@ -104,8 +104,15 @@ class RouteSelector internal constructor( val uri = url.toUri() if (uri.host == null) return immutableListOf(Proxy.NO_PROXY) - // Try each of the ProxySelector choices until one connection succeeds. - val proxiesOrNull = address.proxySelector.select(uri) + // Try each of the ProxySelector choices until one connection succeeds. A misconfigured + // system proxy (such as one with no port set) can make ProxySelector.select() itself throw + // IllegalArgumentException; treat that as "no usable proxy" rather than letting it crash. + val proxiesOrNull = + try { + address.proxySelector.select(uri) + } catch (_: IllegalArgumentException) { + null + } if (proxiesOrNull.isNullOrEmpty()) return immutableListOf(Proxy.NO_PROXY) return proxiesOrNull.toImmutableList() diff --git a/okhttp/src/jvmTest/kotlin/okhttp3/internal/connection/RouteSelectorTest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/internal/connection/RouteSelectorTest.kt index ff50fbf8967c..c1be7fbd8201 100644 --- a/okhttp/src/jvmTest/kotlin/okhttp3/internal/connection/RouteSelectorTest.kt +++ b/okhttp/src/jvmTest/kotlin/okhttp3/internal/connection/RouteSelectorTest.kt @@ -206,6 +206,35 @@ class RouteSelectorTest { assertThat(routeSelector.hasNext()).isFalse() } + @Test fun proxySelectorThrowingIllegalArgumentExceptionFallsBackToDirect() { + val brokenProxySelector: ProxySelector = + object : ProxySelector() { + override fun select(uri: URI): List? { + // A system proxy with an unset port makes the platform ProxySelector throw this. + throw IllegalArgumentException("port out of range:-1") + } + + override fun connectFailed( + uri: URI, + socketAddress: SocketAddress, + e: IOException, + ): Unit = throw AssertionError() + } + + val address = + factory.newAddress( + proxySelector = brokenProxySelector, + ) + val routeSelector = newRouteSelector(address) + assertThat(routeSelector.hasNext()).isTrue() + dns[uriHost] = dns.allocate(1) + val selection = routeSelector.next() + assertRoute(selection.next(), address, Proxy.NO_PROXY, dns.lookup(uriHost, 0), uriPort) + dns.assertRequests(uriHost) + assertThat(selection.hasNext()).isFalse() + assertThat(routeSelector.hasNext()).isFalse() + } + @Test fun proxySelectorReturnsNoProxies() { val address = factory.newAddress() val routeSelector = newRouteSelector(address)