0
# Plugin System
1
2
Plugin installation, configuration, and built-in plugins for extending client functionality with features like timeouts, cookies, authentication, and more.
3
4
## Capabilities
5
6
### HttpClientPlugin Interface
7
8
Core interface for creating and installing client plugins.
9
10
```kotlin { .api }
11
/**
12
* Interface for HTTP client plugins
13
*/
14
interface HttpClientPlugin<out TConfig : Any, TPlugin : Any> {
15
/** Unique key for identifying the plugin */
16
val key: AttributeKey<TPlugin>
17
18
/**
19
* Prepare the plugin with configuration
20
* @param block Configuration block
21
* @return Configured plugin instance
22
*/
23
fun prepare(block: TConfig.() -> Unit = {}): TPlugin
24
25
/**
26
* Install the plugin into a client
27
* @param plugin Prepared plugin instance
28
* @param scope HttpClient to install into
29
*/
30
fun install(plugin: TPlugin, scope: HttpClient)
31
}
32
```
33
34
### Plugin Installation
35
36
Methods for installing plugins into HttpClient configurations.
37
38
```kotlin { .api }
39
/**
40
* Install a plugin with configuration in HttpClientConfig
41
* @param plugin The plugin to install
42
* @param configure Configuration block for the plugin
43
*/
44
fun <TBuilder : Any, TPlugin : Any> HttpClientConfig<*>.install(
45
plugin: HttpClientPlugin<TBuilder, TPlugin>,
46
configure: TBuilder.() -> Unit = {}
47
)
48
49
/**
50
* Install a plugin by key with custom installation logic
51
* @param key String identifier for the plugin
52
* @param block Installation logic
53
*/
54
fun HttpClientConfig<*>.install(key: String, block: HttpClient.() -> Unit)
55
```
56
57
**Usage Examples:**
58
59
```kotlin
60
import io.ktor.client.*
61
import io.ktor.client.plugins.*
62
63
val client = HttpClient {
64
// Install plugin with configuration
65
install(HttpTimeout) {
66
requestTimeoutMillis = 30000
67
connectTimeoutMillis = 10000
68
socketTimeoutMillis = 60000
69
}
70
71
// Install plugin without configuration
72
install(HttpRedirect)
73
74
// Install by string key
75
install("CustomPlugin") {
76
// Custom installation logic
77
}
78
}
79
```
80
81
## Built-in Plugins
82
83
### HttpTimeout Plugin
84
85
Configures request, connection, and socket timeouts.
86
87
```kotlin { .api }
88
/**
89
* HTTP timeout plugin for configuring request timeouts
90
*/
91
val HttpTimeout: ClientPlugin<HttpTimeoutConfig>
92
93
/**
94
* Configuration for HTTP timeout plugin
95
*/
96
class HttpTimeoutConfig {
97
/** Total request timeout in milliseconds */
98
var requestTimeoutMillis: Long? = null
99
100
/** Connection timeout in milliseconds */
101
var connectTimeoutMillis: Long? = null
102
103
/** Socket timeout in milliseconds */
104
var socketTimeoutMillis: Long? = null
105
}
106
107
/**
108
* Configure timeout for a specific request
109
* @param block Configuration block for timeout
110
*/
111
fun HttpRequestBuilder.timeout(block: HttpTimeoutConfig.() -> Unit)
112
```
113
114
**Usage Examples:**
115
116
```kotlin
117
import io.ktor.client.*
118
import io.ktor.client.plugins.*
119
import io.ktor.client.request.*
120
121
// Global timeout configuration
122
val client = HttpClient {
123
install(HttpTimeout) {
124
requestTimeoutMillis = 30000
125
connectTimeoutMillis = 5000
126
socketTimeoutMillis = 60000
127
}
128
}
129
130
// Per-request timeout configuration
131
val response = client.get("https://api.example.com/slow-endpoint") {
132
timeout {
133
requestTimeoutMillis = 60000
134
}
135
}
136
```
137
138
### HttpRedirect Plugin
139
140
Handles HTTP redirects automatically.
141
142
```kotlin { .api }
143
/**
144
* HTTP redirect plugin for handling redirects
145
*/
146
val HttpRedirect: ClientPlugin<HttpRedirect.Config>
147
148
class HttpRedirect {
149
/**
150
* Configuration for HTTP redirect plugin
151
*/
152
class Config {
153
/** Whether to check HTTP method when following redirects */
154
var checkHttpMethod: Boolean = true
155
156
/** Whether to allow HTTPS to HTTP downgrades */
157
var allowHttpsDowngrade: Boolean = false
158
159
/** Maximum number of redirect jumps to follow */
160
var maxJumps: Int = 20
161
}
162
}
163
```
164
165
**Usage Examples:**
166
167
```kotlin
168
import io.ktor.client.*
169
import io.ktor.client.plugins.*
170
171
val client = HttpClient {
172
install(HttpRedirect) {
173
checkHttpMethod = false
174
allowHttpsDowngrade = true
175
maxJumps = 10
176
}
177
}
178
```
179
180
### HttpCallValidator Plugin
181
182
Validates responses and handles exceptions.
183
184
```kotlin { .api }
185
/**
186
* HTTP call validator plugin for response validation
187
*/
188
val HttpCallValidator: ClientPlugin<HttpCallValidator.Config>
189
190
class HttpCallValidator {
191
/**
192
* Configuration for HTTP call validator plugin
193
*/
194
class Config {
195
/**
196
* Add response validation logic
197
* @param block Validation block that receives the response
198
*/
199
fun validateResponse(block: suspend (response: HttpResponse) -> Unit)
200
201
/**
202
* Add exception handling logic for requests
203
* @param block Exception handling block
204
*/
205
fun handleResponseExceptionWithRequest(
206
block: suspend (exception: Throwable, request: HttpRequest) -> Unit
207
)
208
}
209
}
210
```
211
212
**Usage Examples:**
213
214
```kotlin
215
import io.ktor.client.*
216
import io.ktor.client.plugins.*
217
import io.ktor.client.statement.*
218
219
val client = HttpClient {
220
install(HttpCallValidator) {
221
validateResponse { response ->
222
if (response.status.value !in 200..299) {
223
throw ResponseException(response, "HTTP ${response.status}")
224
}
225
}
226
227
handleResponseExceptionWithRequest { exception, request ->
228
println("Request to ${request.url} failed: ${exception.message}")
229
}
230
}
231
}
232
```
233
234
### UserAgent Plugin
235
236
Sets the User-Agent header for requests.
237
238
```kotlin { .api }
239
/**
240
* User-Agent plugin for setting user agent header
241
*/
242
val UserAgent: ClientPlugin<UserAgentConfig>
243
244
/**
245
* Configuration for User-Agent plugin
246
*/
247
class UserAgentConfig {
248
/** User agent string to use */
249
var agent: String = "Ktor client"
250
}
251
```
252
253
**Usage Examples:**
254
255
```kotlin
256
import io.ktor.client.*
257
import io.ktor.client.plugins.*
258
259
val client = HttpClient {
260
install(UserAgent) {
261
agent = "MyApplication/1.0.0"
262
}
263
}
264
```
265
266
### DefaultRequest Plugin
267
268
Sets default configuration for all requests.
269
270
```kotlin { .api }
271
/**
272
* Default request plugin for setting default request configuration
273
*/
274
val DefaultRequest: ClientPlugin<DefaultRequest.Config>
275
276
class DefaultRequest {
277
/**
278
* Configuration for default request plugin
279
*/
280
class Config {
281
/**
282
* Configure default request settings
283
* @param block Configuration block applied to all requests
284
*/
285
fun request(block: HttpRequestBuilder.() -> Unit)
286
}
287
}
288
```
289
290
**Usage Examples:**
291
292
```kotlin
293
import io.ktor.client.*
294
import io.ktor.client.plugins.*
295
import io.ktor.client.request.*
296
import io.ktor.http.*
297
298
val client = HttpClient {
299
install(DefaultRequest) {
300
request {
301
host = "api.example.com"
302
url {
303
protocol = URLProtocol.HTTPS
304
path("v1/")
305
}
306
header(HttpHeaders.Authorization, "Bearer $token")
307
}
308
}
309
}
310
311
// This request will use the default configuration
312
val response = client.get("users") // Becomes https://api.example.com/v1/users
313
```
314
315
### HttpCookies Plugin
316
317
Handles HTTP cookies automatically.
318
319
```kotlin { .api }
320
/**
321
* HTTP cookies plugin for cookie management
322
*/
323
val HttpCookies: ClientPlugin<HttpCookies.Config>
324
325
class HttpCookies {
326
/**
327
* Configuration for HTTP cookies plugin
328
*/
329
class Config {
330
/** Cookie storage implementation */
331
var storage: CookiesStorage = AcceptAllCookiesStorage()
332
}
333
}
334
335
/**
336
* Interface for cookie storage implementations
337
*/
338
interface CookiesStorage : Closeable {
339
/**
340
* Get cookies for a request URL
341
* @param requestUrl URL of the request
342
* @return List of applicable cookies
343
*/
344
suspend fun get(requestUrl: Url): List<Cookie>
345
346
/**
347
* Add a cookie from a response
348
* @param requestUrl URL of the request
349
* @param cookie Cookie to store
350
*/
351
suspend fun addCookie(requestUrl: Url, cookie: Cookie)
352
}
353
354
/**
355
* Cookie storage that accepts all cookies
356
*/
357
class AcceptAllCookiesStorage : CookiesStorage
358
359
/**
360
* Cookie storage with constant cookies
361
*/
362
class ConstantCookiesStorage(vararg cookies: Cookie) : CookiesStorage
363
```
364
365
**Usage Examples:**
366
367
```kotlin
368
import io.ktor.client.*
369
import io.ktor.client.plugins.cookies.*
370
import io.ktor.http.*
371
372
val client = HttpClient {
373
install(HttpCookies) {
374
storage = AcceptAllCookiesStorage()
375
}
376
}
377
378
// Custom cookie storage
379
val customStorage = ConstantCookiesStorage(
380
Cookie("session", "abc123", domain = "example.com"),
381
Cookie("preferences", "theme=dark", domain = "example.com")
382
)
383
384
val clientWithCustomCookies = HttpClient {
385
install(HttpCookies) {
386
storage = customStorage
387
}
388
}
389
```
390
391
### HttpCache Plugin
392
393
Provides HTTP response caching functionality.
394
395
```kotlin { .api }
396
/**
397
* HTTP cache plugin for response caching
398
*/
399
val HttpCache: ClientPlugin<HttpCache.Config>
400
401
class HttpCache {
402
/**
403
* Configuration for HTTP cache plugin
404
*/
405
class Config {
406
/** Whether the cache is shared between multiple clients */
407
var isShared: Boolean = false
408
409
/**
410
* Configure public cache storage
411
* @param storage Cache storage implementation
412
*/
413
fun publicStorage(storage: CacheStorage)
414
415
/**
416
* Configure private cache storage
417
* @param storage Cache storage implementation
418
*/
419
fun privateStorage(storage: CacheStorage)
420
}
421
}
422
423
/**
424
* Interface for cache storage implementations
425
*/
426
interface CacheStorage {
427
/**
428
* Find cached entry for URL and vary headers
429
* @param url Request URL
430
* @param vary Vary header values
431
* @return Cached entry or null if not found
432
*/
433
suspend fun find(url: Url, vary: Map<String, String>): HttpCacheEntry?
434
435
/**
436
* Find all cached entries for URL
437
* @param url Request URL
438
* @return Set of cached entries
439
*/
440
suspend fun findAll(url: Url): Set<HttpCacheEntry>
441
442
/**
443
* Store cache entry
444
* @param url Request URL
445
* @param data Cache entry to store
446
*/
447
suspend fun store(url: Url, data: HttpCacheEntry)
448
449
companion object {
450
/** Create unlimited cache storage */
451
fun Unlimited(): CacheStorage
452
453
/** Create disabled cache storage */
454
fun Disabled(): CacheStorage
455
}
456
}
457
458
/**
459
* HTTP cache entry
460
*/
461
data class HttpCacheEntry(
462
val url: Url,
463
val statusCode: HttpStatusCode,
464
val requestTime: GMTDate,
465
val responseTime: GMTDate,
466
val version: HttpProtocolVersion,
467
val expires: GMTDate,
468
val headers: Headers,
469
val body: ByteArray
470
)
471
```
472
473
**Usage Examples:**
474
475
```kotlin
476
import io.ktor.client.*
477
import io.ktor.client.plugins.cache.*
478
479
val client = HttpClient {
480
install(HttpCache) {
481
publicStorage(CacheStorage.Unlimited())
482
privateStorage(CacheStorage.Unlimited())
483
}
484
}
485
```
486
487
### BodyProgress Plugin
488
489
Tracks upload and download progress for request and response bodies.
490
491
```kotlin { .api }
492
/**
493
* Body progress plugin for tracking upload/download progress
494
*/
495
val BodyProgress: ClientPlugin<BodyProgress.Config>
496
497
class BodyProgress {
498
/**
499
* Configuration for body progress plugin
500
*/
501
class Config {
502
/**
503
* Register a progress listener
504
* @param listener Progress listener to register
505
*/
506
fun register(listener: ProgressListener)
507
}
508
}
509
510
/**
511
* Interface for progress listeners
512
*/
513
fun interface ProgressListener {
514
/**
515
* Called when progress is made
516
* @param bytesSentTotal Total bytes sent so far
517
* @param contentLength Total content length, null if unknown
518
*/
519
fun onProgress(bytesSentTotal: Long, contentLength: Long?)
520
}
521
```
522
523
**Usage Examples:**
524
525
```kotlin
526
import io.ktor.client.*
527
import io.ktor.client.plugins.*
528
import io.ktor.client.request.*
529
530
val client = HttpClient {
531
install(BodyProgress) {
532
register { bytesSentTotal, contentLength ->
533
val progress = if (contentLength != null) {
534
(bytesSentTotal * 100 / contentLength).toInt()
535
} else {
536
-1
537
}
538
println("Upload progress: $bytesSentTotal bytes ($progress%)")
539
}
540
}
541
}
542
543
// Progress will be tracked for this upload
544
val response = client.post("https://api.example.com/upload") {
545
setBody(largeFileContent)
546
}
547
```
548
549
## Advanced Plugins
550
551
### Server-Sent Events (SSE) Plugin
552
553
Provides Server-Sent Events support.
554
555
```kotlin { .api }
556
/**
557
* Server-Sent Events plugin
558
*/
559
val SSE: ClientPlugin<SSEConfig>
560
561
/**
562
* Configuration for SSE plugin
563
*/
564
class SSEConfig {
565
/** Reconnection time for failed connections */
566
var reconnectionTime: Duration? = null
567
568
/** Whether to show comment events */
569
var showCommentEvents: Boolean? = null
570
571
/** Whether to show retry events */
572
var showRetryEvents: Boolean? = null
573
574
/** Maximum reconnection attempts */
575
var maxReconnectionAttempts: Int = Int.MAX_VALUE
576
}
577
578
/**
579
* SSE session interface
580
*/
581
interface ClientSSESession {
582
/** Flow of incoming server-sent events */
583
val incoming: Flow<ServerSentEvent>
584
}
585
586
/**
587
* SSE session with deserialization support
588
*/
589
interface ClientSSESessionWithDeserialization {
590
/** Flow of incoming typed server-sent events */
591
val incoming: Flow<TypedServerSentEvent<String>>
592
593
/**
594
* Deserialize event data
595
* @param data Event data string
596
* @return Deserialized object of type T
597
*/
598
suspend inline fun <reified T> deserialize(data: String?): T?
599
}
600
601
/**
602
* Connect to Server-Sent Events endpoint
603
* @param host Server host
604
* @param port Server port
605
* @param path URL path
606
* @param request Request configuration
607
* @param block SSE session block
608
*/
609
suspend fun HttpClient.sse(
610
host: String = "localhost",
611
port: Int = DEFAULT_PORT,
612
path: String = "/",
613
request: HttpRequestBuilder.() -> Unit = {},
614
block: suspend ClientSSESession.() -> Unit
615
)
616
617
/**
618
* Connect to Server-Sent Events endpoint with deserialization
619
* @param request Request configuration
620
* @param deserialize Deserialization function
621
* @param block SSE session block
622
*/
623
suspend fun <T> HttpClient.sse(
624
request: HttpRequestBuilder.() -> Unit,
625
deserialize: (TypeInfo, String) -> Any?,
626
block: suspend ClientSSESessionWithDeserialization.() -> Unit
627
)
628
```
629
630
**Usage Examples:**
631
632
```kotlin
633
import io.ktor.client.*
634
import io.ktor.client.plugins.sse.*
635
import kotlinx.coroutines.flow.collect
636
637
val client = HttpClient {
638
install(SSE) {
639
reconnectionTime = 3.seconds
640
showCommentEvents = true
641
}
642
}
643
644
// Connect to SSE endpoint
645
client.sse(
646
host = "api.example.com",
647
path = "/events"
648
) {
649
incoming.collect { event ->
650
println("Received: ${event.data}")
651
}
652
}
653
```
654
655
### WebSockets Plugin
656
657
Provides WebSocket client support.
658
659
```kotlin { .api }
660
/**
661
* WebSockets plugin
662
*/
663
val WebSockets: ClientPlugin<WebSocketConfig>
664
665
/**
666
* Connect to WebSocket endpoint
667
* @param method HTTP method for handshake
668
* @param host Server host
669
* @param port Server port
670
* @param path URL path
671
* @param request Request configuration
672
* @param block WebSocket session block
673
*/
674
suspend fun HttpClient.webSocket(
675
method: HttpMethod = HttpMethod.Get,
676
host: String = "localhost",
677
port: Int = DEFAULT_PORT,
678
path: String = "/",
679
request: HttpRequestBuilder.() -> Unit = {},
680
block: suspend DefaultClientWebSocketSession.() -> Unit
681
)
682
683
/**
684
* Connect to WebSocket endpoint with URL string
685
* @param urlString WebSocket URL
686
* @param request Request configuration
687
* @param block WebSocket session block
688
*/
689
suspend fun HttpClient.webSocket(
690
urlString: String,
691
request: HttpRequestBuilder.() -> Unit = {},
692
block: suspend DefaultClientWebSocketSession.() -> Unit
693
)
694
695
/**
696
* Connect to secure WebSocket endpoint
697
*/
698
suspend fun HttpClient.wss(
699
host: String = "localhost",
700
port: Int = DEFAULT_PORT,
701
path: String = "/",
702
request: HttpRequestBuilder.() -> Unit = {},
703
block: suspend DefaultClientWebSocketSession.() -> Unit
704
)
705
```
706
707
**Usage Examples:**
708
709
```kotlin
710
import io.ktor.client.*
711
import io.ktor.client.plugins.websocket.*
712
import io.ktor.websocket.*
713
714
val client = HttpClient {
715
install(WebSockets)
716
}
717
718
// Connect to WebSocket
719
client.webSocket(
720
host = "echo.websocket.org",
721
port = 80,
722
path = "/"
723
) {
724
// Send message
725
send("Hello WebSocket!")
726
727
// Receive messages
728
for (frame in incoming) {
729
when (frame) {
730
is Frame.Text -> {
731
println("Received: ${frame.readText()}")
732
}
733
is Frame.Binary -> {
734
println("Received binary data")
735
}
736
is Frame.Close -> {
737
println("Connection closed")
738
break
739
}
740
}
741
}
742
}
743
```
744
745
## Types
746
747
Plugin system related types:
748
749
```kotlin { .api }
750
/**
751
* Attribute key for identifying plugins
752
*/
753
data class AttributeKey<T>(val name: String)
754
755
/**
756
* Exception for SSE operations
757
*/
758
class SSEClientException(
759
response: HttpResponse?,
760
cause: Throwable?,
761
message: String?
762
) : IllegalStateException()
763
764
/**
765
* Server-sent event data
766
*/
767
data class ServerSentEvent(
768
val data: String?,
769
val event: String?,
770
val id: String?,
771
val retry: Long?,
772
val comments: String?
773
)
774
775
/**
776
* Typed server-sent event
777
*/
778
data class TypedServerSentEvent<T>(
779
val data: T?,
780
val event: String?,
781
val id: String?,
782
val retry: Long?
783
)
784
785
/**
786
* Cookie data class
787
*/
788
data class Cookie(
789
val name: String,
790
val value: String,
791
val encoding: CookieEncoding = CookieEncoding.URI_ENCODING,
792
val maxAge: Int = 0,
793
val expires: GMTDate? = null,
794
val domain: String? = null,
795
val path: String? = null,
796
val secure: Boolean = false,
797
val httpOnly: Boolean = false,
798
val extensions: Map<String, String?> = emptyMap()
799
)
800
```