0
# Utilities and Extensions
1
2
The Ktor HTTP Client Core provides a comprehensive set of utility classes and extension functions for common HTTP client operations. These utilities include exception types, content handling utilities, coroutine integration helpers, client events, and platform-specific extensions that simplify HTTP client development.
3
4
## Exception Types
5
6
### Timeout Exceptions
7
8
Specialized exception types for handling various timeout scenarios in HTTP client operations.
9
10
```kotlin { .api }
11
class ConnectTimeoutException(
12
message: String,
13
cause: Throwable? = null
14
) : Exception(message, cause)
15
16
class SocketTimeoutException(
17
message: String,
18
cause: Throwable? = null
19
) : Exception(message, cause)
20
21
class HttpRequestTimeoutException(
22
request: HttpRequestData,
23
cause: Throwable? = null
24
) : Exception("Request timeout has expired", cause) {
25
val request: HttpRequestData = request
26
}
27
```
28
29
### Plugin-Specific Exceptions
30
31
```kotlin { .api }
32
class SaveBodyAbandonedReadException : Exception("Response body read operation was abandoned")
33
34
class NoTransformationFoundException(
35
from: TypeInfo,
36
to: TypeInfo
37
) : Exception("No transformation found from $from to $to")
38
39
class DoubleReceiveException : Exception("Response has already been received")
40
```
41
42
### Client Configuration Exceptions
43
44
```kotlin { .api }
45
class ClientEngineClosedException : Exception("Client engine is closed")
46
47
class UnsupportedContentTypeException(
48
contentType: ContentType
49
) : Exception("Unsupported content type: $contentType")
50
```
51
52
## Response Extension Functions
53
54
### Body Reading Extensions
55
56
Extension functions for reading response bodies in various formats with proper resource management.
57
58
```kotlin { .api }
59
// Read response as text
60
suspend fun HttpResponse.bodyAsText(charset: Charset = Charsets.UTF_8): String
61
62
// Read response as byte array
63
suspend fun HttpResponse.bodyAsBytes(): ByteArray
64
65
// Get response body as byte read channel
66
fun HttpResponse.bodyAsChannel(): ByteReadChannel
67
68
// Read response as typed object (requires serialization plugin)
69
suspend inline fun <reified T> HttpResponse.body(): T
70
suspend fun <T> HttpResponse.body(typeInfo: TypeInfo): T
71
72
// Save response to file
73
suspend fun HttpResponse.bodyAsChannel(): ByteReadChannel
74
suspend fun HttpResponse.readBytes(): ByteArray
75
suspend fun HttpResponse.readText(charset: Charset = Charsets.UTF_8): String
76
```
77
78
### Response Metadata Extensions
79
80
```kotlin { .api }
81
// Content type utilities
82
fun HttpResponse.contentType(): ContentType?
83
fun HttpResponse.contentLength(): Long?
84
fun HttpResponse.charset(): Charset?
85
86
// Header utilities
87
fun HttpResponse.etag(): String?
88
fun HttpResponse.lastModified(): GMTDate?
89
fun HttpResponse.cacheControl(): List<HeaderValue>?
90
91
// Status utilities
92
fun HttpResponse.isSuccess(): Boolean = status.isSuccess()
93
fun HttpResponse.isInformational(): Boolean = status.value in 100..199
94
fun HttpResponse.isRedirection(): Boolean = status.value in 300..399
95
fun HttpResponse.isClientError(): Boolean = status.value in 400..499
96
fun HttpResponse.isServerError(): Boolean = status.value in 500..599
97
```
98
99
## Content Utilities
100
101
### Content Type Handling
102
103
Utilities for working with HTTP content types and content negotiation.
104
105
```kotlin { .api }
106
// Content type matching and parsing
107
fun ContentType.match(other: ContentType): Boolean
108
fun ContentType.matchesWildcard(pattern: ContentType): Boolean
109
fun ContentType.withCharset(charset: Charset): ContentType
110
fun ContentType.withParameter(name: String, value: String): ContentType
111
112
// Default content types for common scenarios
113
object ContentType {
114
object Application {
115
val Json = ContentType("application", "json")
116
val Xml = ContentType("application", "xml")
117
val FormUrlEncoded = ContentType("application", "x-www-form-urlencoded")
118
val OctetStream = ContentType("application", "octet-stream")
119
val Pdf = ContentType("application", "pdf")
120
val Zip = ContentType("application", "zip")
121
}
122
123
object Text {
124
val Plain = ContentType("text", "plain")
125
val Html = ContentType("text", "html")
126
val CSS = ContentType("text", "css")
127
val JavaScript = ContentType("text", "javascript")
128
val CSV = ContentType("text", "csv")
129
}
130
131
object Image {
132
val JPEG = ContentType("image", "jpeg")
133
val PNG = ContentType("image", "png")
134
val GIF = ContentType("image", "gif")
135
val SVG = ContentType("image", "svg+xml")
136
val Any = ContentType("image", "*")
137
}
138
139
object Video {
140
val MP4 = ContentType("video", "mp4")
141
val AVI = ContentType("video", "x-msvideo")
142
val QuickTime = ContentType("video", "quicktime")
143
}
144
145
object Audio {
146
val MP3 = ContentType("audio", "mpeg")
147
val WAV = ContentType("audio", "wav")
148
val OGG = ContentType("audio", "ogg")
149
}
150
151
object MultiPart {
152
val FormData = ContentType("multipart", "form-data")
153
val Mixed = ContentType("multipart", "mixed")
154
val Alternative = ContentType("multipart", "alternative")
155
}
156
}
157
158
// File extension to content type mapping
159
fun ContentType.Companion.defaultForFile(file: File): ContentType
160
fun ContentType.Companion.defaultForExtension(extension: String): ContentType
161
```
162
163
### Content Encoding Utilities
164
165
```kotlin { .api }
166
// Content encoding support
167
enum class ContentEncoding(val value: String) {
168
GZIP("gzip"),
169
DEFLATE("deflate"),
170
BR("br"),
171
COMPRESS("compress"),
172
IDENTITY("identity")
173
}
174
175
// Content length calculation
176
fun OutgoingContent.contentLength(): Long?
177
fun OutgoingContent.isChunked(): Boolean
178
```
179
180
### Upgrade Content
181
182
Special content type for protocol upgrades like WebSockets.
183
184
```kotlin { .api }
185
class ClientUpgradeContent : OutgoingContent {
186
override val contentType: ContentType? = null
187
override val contentLength: Long? = null
188
189
override fun upgrade(
190
input: ByteReadChannel,
191
output: ByteWriteChannel,
192
engineContext: CoroutineContext,
193
userContext: CoroutineContext
194
): Job
195
}
196
```
197
198
## Client Events
199
200
### Event System
201
202
Event definitions for monitoring HTTP client lifecycle and operations.
203
204
```kotlin { .api }
205
// Request lifecycle events
206
object HttpRequestCreated : EventDefinition<HttpRequestBuilder>()
207
object HttpRequestIsReadyForSending : EventDefinition<HttpRequest>()
208
209
// Response lifecycle events
210
object HttpResponseReceived : EventDefinition<HttpResponseContainer>()
211
object HttpResponseCancelled : EventDefinition<HttpResponseContainer>()
212
213
// Connection events
214
object HttpConnectionCreated : EventDefinition<HttpConnection>()
215
object HttpConnectionClosed : EventDefinition<HttpConnection>()
216
217
// Event containers
218
data class HttpResponseContainer(
219
val response: HttpResponse
220
)
221
222
data class HttpConnection(
223
val host: String,
224
val port: Int,
225
val secure: Boolean
226
)
227
```
228
229
### Event Monitoring
230
231
```kotlin { .api }
232
// Event monitoring with Events interface
233
interface Events {
234
fun <T> subscribe(definition: EventDefinition<T>, handler: suspend (T) -> Unit): Closeable
235
suspend fun <T> raise(definition: EventDefinition<T>, value: T)
236
}
237
238
// Usage example
239
val client = HttpClient()
240
241
val subscription = client.monitor.subscribe(HttpResponseReceived) { container ->
242
println("Response received: ${container.response.status}")
243
}
244
245
// Don't forget to unsubscribe
246
subscription.close()
247
```
248
249
## Coroutine Utilities
250
251
### Coroutine Context Management
252
253
Utilities for proper coroutine context handling in HTTP client operations.
254
255
```kotlin { .api }
256
// Coroutine context utilities
257
fun CoroutineContext.clientContext(): CoroutineContext
258
fun CoroutineContext.withClientDefaults(): CoroutineContext
259
260
// Supervisor job for request isolation
261
fun SupervisorJob.createChildJob(): Job
262
263
// Cancellation utilities
264
suspend fun <T> withCancellation(block: suspend CoroutineScope.() -> T): T
265
fun Job.cancelWithCause(cause: Throwable? = null)
266
```
267
268
### Timeout Utilities
269
270
```kotlin { .api }
271
// Timeout configuration
272
data class HttpTimeoutConfig(
273
val requestTimeoutMillis: Long? = null,
274
val connectTimeoutMillis: Long? = null,
275
val socketTimeoutMillis: Long? = null
276
)
277
278
// Timeout application
279
suspend fun <T> withHttpTimeout(
280
config: HttpTimeoutConfig,
281
block: suspend CoroutineScope.() -> T
282
): T
283
284
// Per-request timeout
285
fun HttpRequestBuilder.timeout(block: HttpTimeoutConfig.() -> Unit)
286
```
287
288
## Header Utilities
289
290
### Header Construction and Manipulation
291
292
Utilities for building and manipulating HTTP headers with type safety.
293
294
```kotlin { .api }
295
// Header building utilities
296
fun headersOf(vararg pairs: Pair<String, String>): Headers
297
fun headersOf(vararg pairs: Pair<String, List<String>>): Headers
298
299
class HeadersBuilder {
300
fun append(name: String, value: String)
301
fun appendAll(headers: Headers)
302
fun remove(name: String)
303
fun clear()
304
fun build(): Headers
305
}
306
307
// Common header utilities
308
fun Headers.authorization(): String?
309
fun Headers.cacheControl(): List<HeaderValue>
310
fun Headers.contentType(): ContentType?
311
fun Headers.contentLength(): Long?
312
fun Headers.userAgent(): String?
313
314
// Header value parsing
315
data class HeaderValue(
316
val value: String,
317
val parameters: Map<String, String> = emptyMap()
318
) {
319
companion object {
320
fun parse(headerValue: String): HeaderValue
321
fun parseList(headerValue: String): List<HeaderValue>
322
}
323
}
324
```
325
326
### Authentication Headers
327
328
```kotlin { .api }
329
// Authentication header utilities
330
fun HeadersBuilder.bearerAuth(token: String) {
331
append(HttpHeaders.Authorization, "Bearer $token")
332
}
333
334
fun HeadersBuilder.basicAuth(username: String, password: String) {
335
val credentials = "$username:$password".encodeBase64()
336
append(HttpHeaders.Authorization, "Basic $credentials")
337
}
338
339
fun HeadersBuilder.apiKeyAuth(apiKey: String, headerName: String = "X-API-Key") {
340
append(headerName, apiKey)
341
}
342
```
343
344
## ByteChannel Utilities
345
346
### Channel Extensions
347
348
Extension functions for working with ByteReadChannel and ByteWriteChannel.
349
350
```kotlin { .api }
351
// ByteReadChannel utilities
352
suspend fun ByteReadChannel.readUTF8Line(limit: Int = Int.MAX_VALUE): String?
353
suspend fun ByteReadChannel.readBytes(): ByteArray
354
suspend fun ByteReadChannel.readBytes(count: Int): ByteArray
355
suspend fun ByteReadChannel.copyTo(output: ByteWriteChannel): Long
356
suspend fun ByteReadChannel.copyTo(output: OutputStream): Long
357
358
// ByteWriteChannel utilities
359
suspend fun ByteWriteChannel.writeStringUtf8(s: String)
360
suspend fun ByteWriteChannel.writeFully(src: ByteArray)
361
suspend fun ByteWriteChannel.writeFully(src: ByteArray, offset: Int, length: Int)
362
363
// Content reading utilities
364
suspend fun ByteReadChannel.readRemaining(limit: Long = Long.MAX_VALUE): ByteReadPacket
365
suspend fun ByteReadChannel.readText(charset: Charset = Charsets.UTF_8): String
366
```
367
368
### Stream Conversion
369
370
```kotlin { .api }
371
// Convert between different stream types
372
fun ByteReadChannel.toInputStream(): InputStream
373
fun InputStream.toByteReadChannel(): ByteReadChannel
374
fun ByteWriteChannel.toOutputStream(): OutputStream
375
fun OutputStream.toByteWriteChannel(): ByteWriteChannel
376
377
// Buffered operations
378
fun ByteReadChannel.buffered(bufferSize: Int = DEFAULT_BUFFER_SIZE): ByteReadChannel
379
fun ByteWriteChannel.buffered(bufferSize: Int = DEFAULT_BUFFER_SIZE): ByteWriteChannel
380
```
381
382
## Cache Control Utilities
383
384
### Cache Directive Handling
385
386
Utilities for parsing and constructing HTTP cache control directives.
387
388
```kotlin { .api }
389
// Cache control directive parsing
390
data class CacheControl(
391
val maxAge: Int? = null,
392
val maxStale: Int? = null,
393
val minFresh: Int? = null,
394
val noCache: Boolean = false,
395
val noStore: Boolean = false,
396
val noTransform: Boolean = false,
397
val onlyIfCached: Boolean = false,
398
val mustRevalidate: Boolean = false,
399
val public: Boolean = false,
400
val private: Boolean = false,
401
val proxyRevalidate: Boolean = false,
402
val immutable: Boolean = false,
403
val staleWhileRevalidate: Int? = null,
404
val staleIfError: Int? = null
405
) {
406
companion object {
407
fun parse(headerValue: String): CacheControl
408
}
409
410
fun toHeaderValue(): String
411
}
412
413
// Cache control builder
414
fun cacheControl(block: CacheControlBuilder.() -> Unit): CacheControl
415
416
class CacheControlBuilder {
417
fun maxAge(seconds: Int)
418
fun noCache()
419
fun noStore()
420
fun mustRevalidate()
421
fun private()
422
fun public()
423
// ... other directives
424
}
425
```
426
427
## URL Utilities
428
429
### URL Building and Manipulation
430
431
```kotlin { .api }
432
// URL construction utilities
433
fun URLBuilder.takeFrom(url: Url): URLBuilder
434
fun URLBuilder.takeFrom(url: String): URLBuilder
435
436
// URL parameter utilities
437
fun URLBuilder.parameter(key: String, value: Any?)
438
fun URLBuilder.parameters(parameters: Parameters)
439
fun URLBuilder.encodedParameters(parameters: String)
440
441
// Path utilities
442
fun URLBuilder.path(vararg components: String)
443
fun URLBuilder.appendEncodedPathSegments(segments: String)
444
fun URLBuilder.pathSegments(segments: List<String>)
445
446
// Fragment utilities
447
fun URLBuilder.fragment(fragment: String?)
448
fun URLBuilder.encodedFragment(fragment: String?)
449
```
450
451
## Platform-Specific Utilities
452
453
### JVM Platform Extensions
454
455
```kotlin { .api }
456
// JVM-specific HttpClient extensions
457
fun HttpClient.executeBlocking(request: HttpRequestBuilder): HttpResponse
458
459
// Service loader integration
460
fun HttpClientEngineFactory.Companion.fromServiceLoader(): List<HttpClientEngineFactory<*>>
461
462
// Java interop utilities
463
fun HttpResponse.toCompletableFuture(): CompletableFuture<HttpResponse>
464
fun HttpClient.async(): AsyncHttpClient
465
```
466
467
### JavaScript Platform Extensions
468
469
```kotlin { .api }
470
// JavaScript Fetch API integration
471
external interface FetchOptions {
472
var method: String?
473
var headers: dynamic
474
var body: dynamic
475
var mode: String?
476
var credentials: String?
477
}
478
479
// Browser-specific utilities
480
fun HttpClient.withCredentials(include: Boolean = true): HttpClient
481
fun HttpRequestBuilder.cors(block: CorsConfig.() -> Unit)
482
483
class CorsConfig {
484
var mode: RequestMode = RequestMode.CORS
485
var credentials: RequestCredentials = RequestCredentials.SAME_ORIGIN
486
}
487
```
488
489
### Native Platform Extensions
490
491
```kotlin { .api }
492
// Native platform networking utilities
493
fun HttpClientEngineConfig.configureNativeSocket(block: NativeSocketConfig.() -> Unit)
494
495
class NativeSocketConfig {
496
var keepAlive: Boolean = true
497
var tcpNoDelay: Boolean = true
498
var socketTimeout: Duration? = null
499
}
500
501
// Platform-specific SSL configuration
502
fun HttpClientEngineConfig.configureTLS(block: TLSConfig.() -> Unit)
503
504
class TLSConfig {
505
var trustManager: X509TrustManager? = null
506
var keyManager: X509KeyManager? = null
507
var protocols: List<String> = listOf("TLSv1.2", "TLSv1.3")
508
}
509
```
510
511
## Error Handling Utilities
512
513
### Exception Wrapping and Conversion
514
515
```kotlin { .api }
516
// Exception conversion utilities
517
fun Throwable.wrapIfNeeded(): Exception
518
fun Exception.unwrapCancellation(): Exception?
519
520
// HTTP-specific exception utilities
521
fun HttpStatusCode.toException(response: HttpResponse): Exception
522
fun createHttpException(status: HttpStatusCode, message: String): Exception
523
524
// Retry utilities
525
suspend fun <T> retryIO(
526
times: Int = 3,
527
initialDelay: Long = 100,
528
maxDelay: Long = 1000,
529
factor: Double = 2.0,
530
block: suspend () -> T
531
): T
532
```
533
534
### Validation Utilities
535
536
```kotlin { .api }
537
// Request validation
538
fun HttpRequestBuilder.validate()
539
fun validateUrl(url: String): Boolean
540
fun validateHeaders(headers: Headers): List<String>
541
542
// Response validation
543
fun HttpResponse.validateContentType(expected: ContentType): Boolean
544
fun HttpResponse.validateStatus(validStatuses: Set<HttpStatusCode>): Boolean
545
```
546
547
## Best Practices
548
549
1. **Use Extension Functions**: Leverage extension functions for cleaner, more readable code
550
2. **Handle Exceptions Properly**: Catch and handle specific exception types appropriately
551
3. **Resource Management**: Always close resources like InputStreams and channels
552
4. **Content Type Detection**: Use utility functions for accurate content type handling
553
5. **Timeout Configuration**: Set appropriate timeouts for different operation types
554
6. **Header Utilities**: Use header utility functions instead of string manipulation
555
7. **Platform Awareness**: Use platform-specific utilities when targeting specific platforms
556
8. **Error Propagation**: Properly propagate errors with meaningful exception types
557
9. **Memory Efficiency**: Use streaming utilities for large content to avoid memory issues
558
10. **Thread Safety**: Be aware that many utilities are not thread-safe by default
559
11. **Charset Handling**: Always specify charset explicitly when working with text content
560
12. **Validation**: Use validation utilities to catch configuration errors early