diff --git a/ktor-client/ktor-client-okhttp/api/ktor-client-okhttp.api b/ktor-client/ktor-client-okhttp/api/ktor-client-okhttp.api index 0faf85248b7..5df09d12859 100644 --- a/ktor-client/ktor-client-okhttp/api/ktor-client-okhttp.api +++ b/ktor-client/ktor-client-okhttp/api/ktor-client-okhttp.api @@ -12,10 +12,12 @@ public final class io/ktor/client/engine/okhttp/OkHttpConfig : io/ktor/client/en public final fun addNetworkInterceptor (Lokhttp3/Interceptor;)V public final fun config (Lkotlin/jvm/functions/Function1;)V public final fun getClientCacheSize ()I + public final fun getDns ()Lokhttp3/Dns; public final fun getDuplexStreamingEnabled ()Z public final fun getPreconfigured ()Lokhttp3/OkHttpClient; public final fun getWebSocketFactory ()Lokhttp3/WebSocket$Factory; public final fun setClientCacheSize (I)V + public final fun setDns (Lokhttp3/Dns;)V public final fun setDuplexStreamingEnabled (Z)V public final fun setPreconfigured (Lokhttp3/OkHttpClient;)V public final fun setWebSocketFactory (Lokhttp3/WebSocket$Factory;)V diff --git a/ktor-client/ktor-client-okhttp/jvm/src/io/ktor/client/engine/okhttp/OkHttpConfig.kt b/ktor-client/ktor-client-okhttp/jvm/src/io/ktor/client/engine/okhttp/OkHttpConfig.kt index f001a7c3a43..3ed5036acff 100644 --- a/ktor-client/ktor-client-okhttp/jvm/src/io/ktor/client/engine/okhttp/OkHttpConfig.kt +++ b/ktor-client/ktor-client-okhttp/jvm/src/io/ktor/client/engine/okhttp/OkHttpConfig.kt @@ -55,6 +55,24 @@ public class OkHttpConfig : HttpClientEngineConfig() { */ public var duplexStreamingEnabled: Boolean = false + /** + * Specifies the [Dns] resolver used by the [OkHttpClient] to look up IP addresses for hostnames. + * When `null`, OkHttp's default [Dns.SYSTEM] resolver is used. + * + * Set this to inject a custom resolver, for example to enable DNS-over-HTTPS or + * to override host resolution in tests: + * ```kotlin + * install(OkHttp) { + * engine { + * dns = Dns { hostname -> listOf(InetAddress.getByName("127.0.0.1")) } + * } + * } + * ``` + * + * [Report a problem](https://ktor.io/feedback/?fqname=io.ktor.client.engine.okhttp.OkHttpConfig.dns) + */ + public var dns: Dns? = null + /** * Configures [OkHttpClient] using [OkHttpClient.Builder]. * diff --git a/ktor-client/ktor-client-okhttp/jvm/src/io/ktor/client/engine/okhttp/OkHttpEngine.kt b/ktor-client/ktor-client-okhttp/jvm/src/io/ktor/client/engine/okhttp/OkHttpEngine.kt index 2a2d3db0299..2d733e37414 100644 --- a/ktor-client/ktor-client-okhttp/jvm/src/io/ktor/client/engine/okhttp/OkHttpEngine.kt +++ b/ktor-client/ktor-client-okhttp/jvm/src/io/ktor/client/engine/okhttp/OkHttpEngine.kt @@ -152,6 +152,7 @@ public class OkHttpEngine(override val config: OkHttpConfig) : HttpClientEngineB } builder.apply(config.config) config.proxy?.let { builder.proxy(it) } + config.dns?.let { builder.dns(it) } timeoutExtension?.let { builder.setupTimeoutAttributes(it) } diff --git a/ktor-client/ktor-client-okhttp/jvm/test/io/ktor/client/engine/okhttp/OkHttpEngineTest.kt b/ktor-client/ktor-client-okhttp/jvm/test/io/ktor/client/engine/okhttp/OkHttpEngineTest.kt index ebf6bb2ff74..969d3d72c89 100644 --- a/ktor-client/ktor-client-okhttp/jvm/test/io/ktor/client/engine/okhttp/OkHttpEngineTest.kt +++ b/ktor-client/ktor-client-okhttp/jvm/test/io/ktor/client/engine/okhttp/OkHttpEngineTest.kt @@ -5,7 +5,9 @@ package io.ktor.client.engine.okhttp import okhttp3.Dispatcher +import okhttp3.Dns import okhttp3.OkHttpClient +import java.net.InetAddress import kotlin.test.Test import kotlin.test.assertSame @@ -26,4 +28,36 @@ class OkHttpEngineTest { assertSame(dispatcher, client.dispatcher) } + + @Test + fun `dns config is applied to OkHttpClient`() { + val customDns = Dns { _ -> listOf(InetAddress.getByName("127.0.0.1")) } + + val engine = OkHttpEngine(OkHttpConfig().apply { dns = customDns }) + try { + val cacheField = engine.javaClass.getDeclaredField("clientCache").apply { isAccessible = true } + val clientCache = cacheField.get(engine) as Map<*, *> + + val client = clientCache[null] as OkHttpClient + + assertSame(customDns, client.dns) + } finally { + engine.close() + } + } + + @Test + fun `default dns is preserved when dns config is not set`() { + val engine = OkHttpEngine(OkHttpConfig()) + try { + val cacheField = engine.javaClass.getDeclaredField("clientCache").apply { isAccessible = true } + val clientCache = cacheField.get(engine) as Map<*, *> + + val client = clientCache[null] as OkHttpClient + + assertSame(Dns.SYSTEM, client.dns) + } finally { + engine.close() + } + } }