0
# Engine Architecture
1
2
Client engine abstraction allowing different HTTP implementations with engine-specific configuration, capabilities management, and pluggable backend support for various HTTP client implementations.
3
4
## Capabilities
5
6
### HttpClientEngine Interface
7
8
Core engine interface that all HTTP client implementations must implement.
9
10
```kotlin { .api }
11
/**
12
* HTTP client engine interface
13
*/
14
interface HttpClientEngine : CoroutineScope, Closeable {
15
/** Engine configuration */
16
val config: HttpClientEngineConfig
17
18
/** Coroutine dispatcher for engine operations */
19
val dispatcher: CoroutineDispatcher
20
21
/** Set of capabilities supported by this engine */
22
val supportedCapabilities: Set<HttpClientEngineCapability<*>>
23
24
/** Execute HTTP request and return response data */
25
suspend fun execute(data: HttpRequestData): HttpResponseData
26
27
/** Install engine in HTTP client */
28
fun install(client: HttpClient)
29
30
/** Close engine and release resources */
31
override fun close()
32
}
33
```
34
35
### HttpClientEngineFactory
36
37
Factory interface for creating engine instances.
38
39
```kotlin { .api }
40
/**
41
* Factory for creating HTTP client engines
42
*/
43
interface HttpClientEngineFactory<T : HttpClientEngineConfig> {
44
/** Create engine instance with configuration */
45
fun create(block: T.() -> Unit = {}): HttpClientEngine
46
}
47
48
/**
49
* Engine container for default engine selection
50
*/
51
object HttpClientEngineContainer {
52
/** Default engine for current platform */
53
val default: HttpClientEngine
54
55
/** Install engine factory */
56
fun install(factory: HttpClientEngineFactory<*>)
57
}
58
```
59
60
**Usage Examples:**
61
62
```kotlin
63
import io.ktor.client.engine.cio.*
64
import io.ktor.client.engine.apache.*
65
66
// Create client with specific engine
67
val cioClient = HttpClient(CIO) {
68
engine {
69
maxConnectionsCount = 1000
70
endpoint {
71
maxConnectionsPerRoute = 100
72
pipelineMaxSize = 20
73
}
74
}
75
}
76
77
val apacheClient = HttpClient(Apache) {
78
engine {
79
followRedirects = true
80
socketTimeout = 10_000
81
connectTimeout = 10_000
82
connectionRequestTimeout = 20_000
83
}
84
}
85
86
// Use default engine
87
val defaultClient = HttpClient() // Uses HttpClientEngineContainer.default
88
```
89
90
### HttpClientEngineConfig
91
92
Base configuration class for all HTTP client engines.
93
94
```kotlin { .api }
95
/**
96
* Base configuration for HTTP client engines
97
*/
98
open class HttpClientEngineConfig {
99
/** Number of threads for the engine */
100
var threadsCount: Int = 4
101
102
/** Whether to enable HTTP pipelining */
103
var pipelining: Boolean = false
104
105
/** Proxy configuration */
106
var proxy: ProxyConfig? = null
107
108
/** Custom certificate verification */
109
var https: HttpsConfig = HttpsConfig()
110
}
111
112
/**
113
* HTTPS configuration
114
*/
115
class HttpsConfig {
116
/** Trust all certificates (development only) */
117
var trustManager: X509TrustManager? = null
118
119
/** Custom SSL context */
120
var sslContext: SSLContext? = null
121
122
/** Hostname verifier */
123
var hostnameVerifier: HostnameVerifier? = null
124
125
/** Certificate pinning */
126
var certificates: List<X509Certificate> = emptyList()
127
}
128
```
129
130
### Engine Capabilities
131
132
System for declaring and checking engine capabilities.
133
134
```kotlin { .api }
135
/**
136
* Represents a capability that an engine may support
137
*/
138
class HttpClientEngineCapability<T>(
139
val key: String
140
) {
141
override fun equals(other: Any?): Boolean
142
override fun hashCode(): Int
143
override fun toString(): String
144
}
145
146
/**
147
* Check if engine supports a capability
148
*/
149
fun HttpClientEngine.supports(capability: HttpClientEngineCapability<*>): Boolean
150
151
/**
152
* Get capability from engine if supported
153
*/
154
fun <T> HttpClientEngine.getCapability(capability: HttpClientEngineCapability<T>): T?
155
156
/**
157
* Require capability from engine, throw if not supported
158
*/
159
fun <T> HttpClientEngine.requireCapability(capability: HttpClientEngineCapability<T>): T
160
```
161
162
**Usage Examples:**
163
164
```kotlin
165
// Define custom capability
166
val CompressionCapability = HttpClientEngineCapability<CompressionConfig>("compression")
167
168
// Check if engine supports capability
169
if (client.engine.supports(CompressionCapability)) {
170
val compressionConfig = client.engine.getCapability(CompressionCapability)
171
println("Compression supported with config: $compressionConfig")
172
}
173
174
// Require capability (throws if not supported)
175
try {
176
val config = client.engine.requireCapability(CompressionCapability)
177
// Use compression
178
} catch (e: IllegalStateException) {
179
println("Engine does not support compression")
180
}
181
```
182
183
### Engine-Specific Configurations
184
185
Configurations for different engine implementations.
186
187
```kotlin { .api }
188
/**
189
* CIO engine configuration
190
*/
191
class CIOEngineConfig : HttpClientEngineConfig() {
192
/** Maximum number of connections */
193
var maxConnectionsCount: Int = 1000
194
195
/** Endpoint configuration */
196
val endpoint: EndpointConfig = EndpointConfig()
197
198
/** Request timeout */
199
var requestTimeout: Long = 15_000
200
}
201
202
class EndpointConfig {
203
/** Maximum connections per route */
204
var maxConnectionsPerRoute: Int = 100
205
206
/** Pipeline maximum size */
207
var pipelineMaxSize: Int = 20
208
209
/** Keep alive time */
210
var keepAliveTime: Long = 5000
211
212
/** Connection idle timeout */
213
var connectTimeout: Long = 5000
214
215
/** Connection retry attempts */
216
var connectAttempts: Int = 5
217
}
218
219
/**
220
* Apache engine configuration
221
*/
222
class ApacheEngineConfig : HttpClientEngineConfig() {
223
/** Follow redirects automatically */
224
var followRedirects: Boolean = true
225
226
/** Socket timeout */
227
var socketTimeout: Int = 10_000
228
229
/** Connection timeout */
230
var connectTimeout: Int = 10_000
231
232
/** Connection request timeout */
233
var connectionRequestTimeout: Int = 20_000
234
235
/** Custom request configuration */
236
var customRequest: (RequestConfig.Builder.() -> Unit)? = null
237
}
238
239
/**
240
* OkHttp engine configuration
241
*/
242
class OkHttpConfig : HttpClientEngineConfig() {
243
/** Custom OkHttpClient instance */
244
var preconfigured: OkHttpClient? = null
245
246
/** OkHttp client configuration */
247
var config: (OkHttpClient.Builder.() -> Unit)? = null
248
249
/** WebSocket configuration */
250
var webSocketFactory: WebSocket.Factory? = null
251
}
252
```
253
254
**Usage Examples:**
255
256
```kotlin
257
// CIO engine with detailed configuration
258
val cioClient = HttpClient(CIO) {
259
engine {
260
maxConnectionsCount = 2000
261
requestTimeout = 30_000
262
263
endpoint {
264
maxConnectionsPerRoute = 200
265
pipelineMaxSize = 50
266
keepAliveTime = 10_000
267
connectTimeout = 3_000
268
connectAttempts = 3
269
}
270
271
https {
272
trustManager = customTrustManager
273
}
274
}
275
}
276
277
// Apache engine configuration
278
val apacheClient = HttpClient(Apache) {
279
engine {
280
followRedirects = false
281
socketTimeout = 15_000
282
connectTimeout = 5_000
283
connectionRequestTimeout = 10_000
284
285
customRequest = {
286
setCircularRedirectsAllowed(false)
287
setRedirectsEnabled(false)
288
setAuthenticationEnabled(true)
289
}
290
}
291
}
292
293
// OkHttp engine with custom client
294
val okHttpClient = OkHttpClient.Builder()
295
.connectTimeout(10, TimeUnit.SECONDS)
296
.readTimeout(30, TimeUnit.SECONDS)
297
.addInterceptor(loggingInterceptor)
298
.build()
299
300
val client = HttpClient(OkHttp) {
301
engine {
302
preconfigured = okHttpClient
303
}
304
}
305
```
306
307
### Engine Lifecycle
308
309
Manage engine lifecycle and resource cleanup.
310
311
```kotlin { .api }
312
/**
313
* Engine lifecycle management
314
*/
315
interface EngineLifecycle {
316
/** Initialize engine */
317
suspend fun start()
318
319
/** Shutdown engine gracefully */
320
suspend fun shutdown()
321
322
/** Force shutdown engine */
323
suspend fun shutdownNow()
324
325
/** Check if engine is running */
326
val isRunning: Boolean
327
}
328
329
/**
330
* Engine monitoring and metrics
331
*/
332
interface EngineMetrics {
333
/** Active connections count */
334
val activeConnections: Int
335
336
/** Total requests made */
337
val totalRequests: Long
338
339
/** Failed requests count */
340
val failedRequests: Long
341
342
/** Average response time */
343
val averageResponseTime: Double
344
}
345
```
346
347
### Engine Selection
348
349
Utilities for engine selection and management.
350
351
```kotlin { .api }
352
/**
353
* Engine selector for automatic engine selection
354
*/
355
object EngineSelector {
356
/** Select best engine for current platform */
357
fun selectDefault(): HttpClientEngineFactory<*>
358
359
/** Select engine by name */
360
fun selectByName(name: String): HttpClientEngineFactory<*>?
361
362
/** Get available engines */
363
fun getAvailableEngines(): List<HttpClientEngineFactory<*>>
364
}
365
366
/**
367
* Platform-specific engine recommendations
368
*/
369
object PlatformEngines {
370
/** Recommended engine for JVM */
371
val JVM: HttpClientEngineFactory<*>
372
373
/** Recommended engine for Android */
374
val Android: HttpClientEngineFactory<*>
375
376
/** Recommended engine for JavaScript */
377
val JavaScript: HttpClientEngineFactory<*>
378
379
/** Recommended engine for Native */
380
val Native: HttpClientEngineFactory<*>
381
}
382
```
383
384
### Engine Testing
385
386
Utilities for testing engine implementations.
387
388
```kotlin { .api }
389
/**
390
* Mock engine for testing
391
*/
392
class MockEngine(
393
val config: MockEngineConfig
394
) : HttpClientEngine {
395
396
class MockEngineConfig : HttpClientEngineConfig() {
397
/** Response handlers */
398
val responseHandlers: MutableList<MockRequestHandler> = mutableListOf()
399
400
/** Add response handler */
401
fun addHandler(handler: MockRequestHandler)
402
403
/** Add response handler with DSL */
404
fun addHandler(block: MockRequestHandlerBuilder.() -> Unit)
405
}
406
}
407
408
/**
409
* Mock request handler
410
*/
411
class MockRequestHandler(
412
val matcher: (HttpRequestData) -> Boolean,
413
val responseBuilder: suspend MockRequestHandlerScope.(HttpRequestData) -> HttpResponseData
414
)
415
416
/**
417
* Test engine utilities
418
*/
419
object TestEngineUtils {
420
/** Create test engine with mock responses */
421
fun createTestEngine(block: MockEngineConfig.() -> Unit): MockEngine
422
423
/** Verify request expectations */
424
fun verifyRequests(engine: MockEngine, expectations: List<RequestExpectation>)
425
}
426
```
427
428
**Usage Examples:**
429
430
```kotlin
431
// Mock engine for testing
432
val mockEngine = MockEngine {
433
addHandler { request ->
434
when (request.url.encodedPath) {
435
"/users" -> respond(
436
content = """[{"id": 1, "name": "John"}]""",
437
status = HttpStatusCode.OK,
438
headers = headersOf(HttpHeaders.ContentType, "application/json")
439
)
440
"/error" -> respond(
441
content = "Not Found",
442
status = HttpStatusCode.NotFound
443
)
444
else -> error("Unhandled request: ${request.url}")
445
}
446
}
447
}
448
449
val testClient = HttpClient(mockEngine)
450
451
// Test with mock engine
452
val response = testClient.get("/users")
453
assertEquals(HttpStatusCode.OK, response.status)
454
```
455
456
## Types
457
458
```kotlin { .api }
459
// Engine data types
460
data class HttpRequestData(
461
val url: Url,
462
val method: HttpMethod,
463
val headers: Headers,
464
val body: OutgoingContent,
465
val executionContext: Job,
466
val attributes: Attributes
467
)
468
469
data class HttpResponseData(
470
val statusCode: HttpStatusCode,
471
val requestTime: GMTDate,
472
val headers: Headers,
473
val version: HttpProtocolVersion,
474
val body: Any,
475
val callContext: CoroutineContext
476
)
477
478
// Engine exception types
479
class UnsupportedEngineException(
480
message: String
481
) : IllegalStateException(message)
482
483
class EngineClosedException(
484
message: String = "Engine is closed"
485
) : IllegalStateException(message)
486
487
// Configuration types
488
data class ProxyConfig(
489
val url: Url
490
) {
491
constructor(host: String, port: Int) : this(
492
URLBuilder().apply {
493
this.host = host
494
this.port = port
495
}.build()
496
)
497
498
enum class Type {
499
HTTP, HTTPS, SOCKS
500
}
501
}
502
503
// Capability types
504
interface EngineCapabilityProvider {
505
fun <T> provide(capability: HttpClientEngineCapability<T>): T?
506
}
507
508
// Engine factory registry
509
object EngineFactoryRegistry {
510
fun register(name: String, factory: HttpClientEngineFactory<*>)
511
fun unregister(name: String)
512
fun get(name: String): HttpClientEngineFactory<*>?
513
fun getAll(): Map<String, HttpClientEngineFactory<*>>
514
}
515
```