Ktor HTTP client core library providing asynchronous HTTP client capabilities for Kotlin multiplatform applications
—
Client engine abstraction allowing different HTTP implementations with engine-specific configuration, capabilities management, and pluggable backend support for various HTTP client implementations.
Core engine interface that all HTTP client implementations must implement.
/**
* HTTP client engine interface
*/
interface HttpClientEngine : CoroutineScope, Closeable {
/** Engine configuration */
val config: HttpClientEngineConfig
/** Coroutine dispatcher for engine operations */
val dispatcher: CoroutineDispatcher
/** Set of capabilities supported by this engine */
val supportedCapabilities: Set<HttpClientEngineCapability<*>>
/** Execute HTTP request and return response data */
suspend fun execute(data: HttpRequestData): HttpResponseData
/** Install engine in HTTP client */
fun install(client: HttpClient)
/** Close engine and release resources */
override fun close()
}Factory interface for creating engine instances.
/**
* Factory for creating HTTP client engines
*/
interface HttpClientEngineFactory<T : HttpClientEngineConfig> {
/** Create engine instance with configuration */
fun create(block: T.() -> Unit = {}): HttpClientEngine
}
/**
* Engine container for default engine selection
*/
object HttpClientEngineContainer {
/** Default engine for current platform */
val default: HttpClientEngine
/** Install engine factory */
fun install(factory: HttpClientEngineFactory<*>)
}Usage Examples:
import io.ktor.client.engine.cio.*
import io.ktor.client.engine.apache.*
// Create client with specific engine
val cioClient = HttpClient(CIO) {
engine {
maxConnectionsCount = 1000
endpoint {
maxConnectionsPerRoute = 100
pipelineMaxSize = 20
}
}
}
val apacheClient = HttpClient(Apache) {
engine {
followRedirects = true
socketTimeout = 10_000
connectTimeout = 10_000
connectionRequestTimeout = 20_000
}
}
// Use default engine
val defaultClient = HttpClient() // Uses HttpClientEngineContainer.defaultBase configuration class for all HTTP client engines.
/**
* Base configuration for HTTP client engines
*/
open class HttpClientEngineConfig {
/** Number of threads for the engine */
var threadsCount: Int = 4
/** Whether to enable HTTP pipelining */
var pipelining: Boolean = false
/** Proxy configuration */
var proxy: ProxyConfig? = null
/** Custom certificate verification */
var https: HttpsConfig = HttpsConfig()
}
/**
* HTTPS configuration
*/
class HttpsConfig {
/** Trust all certificates (development only) */
var trustManager: X509TrustManager? = null
/** Custom SSL context */
var sslContext: SSLContext? = null
/** Hostname verifier */
var hostnameVerifier: HostnameVerifier? = null
/** Certificate pinning */
var certificates: List<X509Certificate> = emptyList()
}System for declaring and checking engine capabilities.
/**
* Represents a capability that an engine may support
*/
class HttpClientEngineCapability<T>(
val key: String
) {
override fun equals(other: Any?): Boolean
override fun hashCode(): Int
override fun toString(): String
}
/**
* Check if engine supports a capability
*/
fun HttpClientEngine.supports(capability: HttpClientEngineCapability<*>): Boolean
/**
* Get capability from engine if supported
*/
fun <T> HttpClientEngine.getCapability(capability: HttpClientEngineCapability<T>): T?
/**
* Require capability from engine, throw if not supported
*/
fun <T> HttpClientEngine.requireCapability(capability: HttpClientEngineCapability<T>): TUsage Examples:
// Define custom capability
val CompressionCapability = HttpClientEngineCapability<CompressionConfig>("compression")
// Check if engine supports capability
if (client.engine.supports(CompressionCapability)) {
val compressionConfig = client.engine.getCapability(CompressionCapability)
println("Compression supported with config: $compressionConfig")
}
// Require capability (throws if not supported)
try {
val config = client.engine.requireCapability(CompressionCapability)
// Use compression
} catch (e: IllegalStateException) {
println("Engine does not support compression")
}Configurations for different engine implementations.
/**
* CIO engine configuration
*/
class CIOEngineConfig : HttpClientEngineConfig() {
/** Maximum number of connections */
var maxConnectionsCount: Int = 1000
/** Endpoint configuration */
val endpoint: EndpointConfig = EndpointConfig()
/** Request timeout */
var requestTimeout: Long = 15_000
}
class EndpointConfig {
/** Maximum connections per route */
var maxConnectionsPerRoute: Int = 100
/** Pipeline maximum size */
var pipelineMaxSize: Int = 20
/** Keep alive time */
var keepAliveTime: Long = 5000
/** Connection idle timeout */
var connectTimeout: Long = 5000
/** Connection retry attempts */
var connectAttempts: Int = 5
}
/**
* Apache engine configuration
*/
class ApacheEngineConfig : HttpClientEngineConfig() {
/** Follow redirects automatically */
var followRedirects: Boolean = true
/** Socket timeout */
var socketTimeout: Int = 10_000
/** Connection timeout */
var connectTimeout: Int = 10_000
/** Connection request timeout */
var connectionRequestTimeout: Int = 20_000
/** Custom request configuration */
var customRequest: (RequestConfig.Builder.() -> Unit)? = null
}
/**
* OkHttp engine configuration
*/
class OkHttpConfig : HttpClientEngineConfig() {
/** Custom OkHttpClient instance */
var preconfigured: OkHttpClient? = null
/** OkHttp client configuration */
var config: (OkHttpClient.Builder.() -> Unit)? = null
/** WebSocket configuration */
var webSocketFactory: WebSocket.Factory? = null
}Usage Examples:
// CIO engine with detailed configuration
val cioClient = HttpClient(CIO) {
engine {
maxConnectionsCount = 2000
requestTimeout = 30_000
endpoint {
maxConnectionsPerRoute = 200
pipelineMaxSize = 50
keepAliveTime = 10_000
connectTimeout = 3_000
connectAttempts = 3
}
https {
trustManager = customTrustManager
}
}
}
// Apache engine configuration
val apacheClient = HttpClient(Apache) {
engine {
followRedirects = false
socketTimeout = 15_000
connectTimeout = 5_000
connectionRequestTimeout = 10_000
customRequest = {
setCircularRedirectsAllowed(false)
setRedirectsEnabled(false)
setAuthenticationEnabled(true)
}
}
}
// OkHttp engine with custom client
val okHttpClient = OkHttpClient.Builder()
.connectTimeout(10, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.addInterceptor(loggingInterceptor)
.build()
val client = HttpClient(OkHttp) {
engine {
preconfigured = okHttpClient
}
}Manage engine lifecycle and resource cleanup.
/**
* Engine lifecycle management
*/
interface EngineLifecycle {
/** Initialize engine */
suspend fun start()
/** Shutdown engine gracefully */
suspend fun shutdown()
/** Force shutdown engine */
suspend fun shutdownNow()
/** Check if engine is running */
val isRunning: Boolean
}
/**
* Engine monitoring and metrics
*/
interface EngineMetrics {
/** Active connections count */
val activeConnections: Int
/** Total requests made */
val totalRequests: Long
/** Failed requests count */
val failedRequests: Long
/** Average response time */
val averageResponseTime: Double
}Utilities for engine selection and management.
/**
* Engine selector for automatic engine selection
*/
object EngineSelector {
/** Select best engine for current platform */
fun selectDefault(): HttpClientEngineFactory<*>
/** Select engine by name */
fun selectByName(name: String): HttpClientEngineFactory<*>?
/** Get available engines */
fun getAvailableEngines(): List<HttpClientEngineFactory<*>>
}
/**
* Platform-specific engine recommendations
*/
object PlatformEngines {
/** Recommended engine for JVM */
val JVM: HttpClientEngineFactory<*>
/** Recommended engine for Android */
val Android: HttpClientEngineFactory<*>
/** Recommended engine for JavaScript */
val JavaScript: HttpClientEngineFactory<*>
/** Recommended engine for Native */
val Native: HttpClientEngineFactory<*>
}Utilities for testing engine implementations.
/**
* Mock engine for testing
*/
class MockEngine(
val config: MockEngineConfig
) : HttpClientEngine {
class MockEngineConfig : HttpClientEngineConfig() {
/** Response handlers */
val responseHandlers: MutableList<MockRequestHandler> = mutableListOf()
/** Add response handler */
fun addHandler(handler: MockRequestHandler)
/** Add response handler with DSL */
fun addHandler(block: MockRequestHandlerBuilder.() -> Unit)
}
}
/**
* Mock request handler
*/
class MockRequestHandler(
val matcher: (HttpRequestData) -> Boolean,
val responseBuilder: suspend MockRequestHandlerScope.(HttpRequestData) -> HttpResponseData
)
/**
* Test engine utilities
*/
object TestEngineUtils {
/** Create test engine with mock responses */
fun createTestEngine(block: MockEngineConfig.() -> Unit): MockEngine
/** Verify request expectations */
fun verifyRequests(engine: MockEngine, expectations: List<RequestExpectation>)
}Usage Examples:
// Mock engine for testing
val mockEngine = MockEngine {
addHandler { request ->
when (request.url.encodedPath) {
"/users" -> respond(
content = """[{"id": 1, "name": "John"}]""",
status = HttpStatusCode.OK,
headers = headersOf(HttpHeaders.ContentType, "application/json")
)
"/error" -> respond(
content = "Not Found",
status = HttpStatusCode.NotFound
)
else -> error("Unhandled request: ${request.url}")
}
}
}
val testClient = HttpClient(mockEngine)
// Test with mock engine
val response = testClient.get("/users")
assertEquals(HttpStatusCode.OK, response.status)// Engine data types
data class HttpRequestData(
val url: Url,
val method: HttpMethod,
val headers: Headers,
val body: OutgoingContent,
val executionContext: Job,
val attributes: Attributes
)
data class HttpResponseData(
val statusCode: HttpStatusCode,
val requestTime: GMTDate,
val headers: Headers,
val version: HttpProtocolVersion,
val body: Any,
val callContext: CoroutineContext
)
// Engine exception types
class UnsupportedEngineException(
message: String
) : IllegalStateException(message)
class EngineClosedException(
message: String = "Engine is closed"
) : IllegalStateException(message)
// Configuration types
data class ProxyConfig(
val url: Url
) {
constructor(host: String, port: Int) : this(
URLBuilder().apply {
this.host = host
this.port = port
}.build()
)
enum class Type {
HTTP, HTTPS, SOCKS
}
}
// Capability types
interface EngineCapabilityProvider {
fun <T> provide(capability: HttpClientEngineCapability<T>): T?
}
// Engine factory registry
object EngineFactoryRegistry {
fun register(name: String, factory: HttpClientEngineFactory<*>)
fun unregister(name: String)
fun get(name: String): HttpClientEngineFactory<*>?
fun getAll(): Map<String, HttpClientEngineFactory<*>>
}Install with Tessl CLI
npx tessl i tessl/maven-io-ktor--ktor-client-core-jvm