0
# Request Compression
1
2
Compress outgoing HTTP request bodies to reduce bandwidth usage and improve upload performance using configurable compression algorithms.
3
4
## Request Compression API
5
6
```kotlin { .api }
7
/**
8
* Compresses request body using ContentEncoding plugin.
9
* @param contentEncoderName names of compression encoders to use, such as "gzip", "deflate", etc
10
*/
11
fun HttpRequestBuilder.compress(vararg contentEncoderName: String): Unit
12
13
/**
14
* Compress request body using ContentEncoding plugin.
15
* @param contentEncoderNames names of compression encoders to use, such as "gzip", "deflate", etc
16
*/
17
fun HttpRequestBuilder.compress(contentEncoderNames: List<String>): Unit
18
```
19
20
## Basic Request Compression
21
22
### Per-Request Compression
23
24
```kotlin
25
import io.ktor.client.request.*
26
import io.ktor.client.plugins.compression.*
27
28
// Single encoder
29
client.post("/api/upload") {
30
compress("gzip")
31
setBody("Large payload data")
32
}
33
34
// Multiple encoders (applied in order)
35
client.put("/api/update") {
36
compress("gzip", "deflate")
37
setBody(largeData)
38
}
39
40
// List-based specification
41
client.patch("/api/modify") {
42
compress(listOf("deflate", "gzip"))
43
setBody(payload)
44
}
45
```
46
47
### Global Request Compression Mode
48
49
```kotlin
50
val client = HttpClient {
51
install(ContentEncoding) {
52
mode = ContentEncodingConfig.Mode.CompressRequest // Only compress requests
53
gzip()
54
deflate()
55
}
56
}
57
58
// All requests can now use compression
59
client.post("/upload1") {
60
compress("gzip")
61
setBody(data1)
62
}
63
64
client.post("/upload2") {
65
compress("deflate")
66
setBody(data2)
67
}
68
```
69
70
### Bidirectional Mode
71
72
```kotlin
73
val client = HttpClient {
74
install(ContentEncoding) {
75
mode = ContentEncodingConfig.Mode.All // Compress requests AND decompress responses
76
gzip()
77
deflate()
78
identity()
79
}
80
}
81
82
client.post("/api/data") {
83
compress("gzip")
84
setBody(requestData)
85
}
86
// Response automatically decompressed if server sends compressed data
87
```
88
89
## Compression Behavior
90
91
### Header Management
92
93
```kotlin
94
client.post("/upload") {
95
compress("gzip")
96
setBody("Data to compress")
97
}
98
99
// Automatically sets: Content-Encoding: gzip
100
// Original Content-Length header is removed (compressed length is different)
101
// Vary header includes Accept-Encoding
102
```
103
104
### Multi-Layer Compression
105
106
```kotlin
107
// Apply multiple compression layers
108
client.post("/complex-upload") {
109
compress("deflate", "gzip") // deflate first, then gzip
110
setBody(complexData)
111
}
112
113
// Server must decompress in reverse order: gzip first, then deflate
114
```
115
116
**Processing Order:**
117
1. Original content → deflate compression → intermediate result
118
2. Intermediate result → gzip compression → final compressed content
119
3. Headers: `Content-Encoding: deflate, gzip`
120
121
### Compression with Content Types
122
123
```kotlin
124
import io.ktor.http.*
125
126
// JSON data compression
127
client.post("/api/json") {
128
compress("gzip")
129
contentType(ContentType.Application.Json)
130
setBody("""{"large": "json", "data": "here"}""")
131
}
132
133
// Binary data compression
134
client.post("/api/binary") {
135
compress("deflate")
136
contentType(ContentType.Application.OctetStream)
137
setBody(binaryData)
138
}
139
140
// Form data compression
141
client.post("/api/form") {
142
compress("gzip")
143
contentType(ContentType.Application.FormUrlEncoded)
144
setBody(formParameters)
145
}
146
```
147
148
## Advanced Request Compression
149
150
### Conditional Compression
151
152
```kotlin
153
suspend fun uploadWithConditionalCompression(data: ByteArray) {
154
val shouldCompress = data.size > 1024 // Only compress large payloads
155
156
client.post("/upload") {
157
if (shouldCompress) {
158
compress("gzip")
159
}
160
setBody(data)
161
}
162
}
163
```
164
165
### Compression Strategy by Content Type
166
167
```kotlin
168
suspend fun uploadWithSmartCompression(content: Any, contentType: ContentType) {
169
client.post("/smart-upload") {
170
when (contentType) {
171
ContentType.Application.Json,
172
ContentType.Text.Plain,
173
ContentType.Application.Xml -> {
174
compress("gzip") // Text-based content compresses well
175
}
176
ContentType.Image.JPEG,
177
ContentType.Image.PNG -> {
178
// Images are already compressed, skip compression
179
}
180
else -> {
181
compress("deflate") // Default to deflate for other types
182
}
183
}
184
contentType(contentType)
185
setBody(content)
186
}
187
}
188
```
189
190
### Large File Upload with Compression
191
192
```kotlin
193
import io.ktor.client.request.forms.*
194
import io.ktor.http.content.*
195
196
suspend fun uploadLargeFile(file: ByteArray) {
197
client.post("/large-upload") {
198
compress("gzip")
199
setBody(MultiPartFormDataContent(
200
formData {
201
append("file", file, Headers.build {
202
append(HttpHeaders.ContentDisposition, "filename=large-file.dat")
203
})
204
}
205
))
206
}
207
}
208
```
209
210
## Pipeline Integration
211
212
### Request Processing Pipeline
213
214
```kotlin
215
// Compression occurs in the request pipeline after content rendering
216
// Order: Content Creation → Rendering → Compression → Network Send
217
218
client.post("/data") {
219
// 1. Content created
220
setBody(originalContent)
221
222
// 2. Content rendered to OutgoingContent
223
// 3. Compression applied (if compress() called)
224
compress("gzip")
225
226
// 4. Compressed content sent over network
227
}
228
```
229
230
### Compression Attributes
231
232
```kotlin { .api }
233
internal val CompressionListAttribute: AttributeKey<List<String>>
234
```
235
236
**Internal Usage:**
237
```kotlin
238
// The compress() function sets internal attributes
239
client.post("/upload") {
240
compress("gzip", "deflate")
241
// Internally: attributes.put(CompressionListAttribute, listOf("gzip", "deflate"))
242
setBody(data)
243
}
244
```
245
246
## Error Handling
247
248
### Unsupported Encoder Names
249
250
```kotlin
251
try {
252
client.post("/upload") {
253
compress("unknown-algorithm") // Not registered in ContentEncodingConfig
254
setBody(data)
255
}
256
} catch (e: UnsupportedContentEncodingException) {
257
println("Compression failed: ${e.message}")
258
// Fallback to uncompressed upload
259
client.post("/upload") {
260
setBody(data)
261
}
262
}
263
```
264
265
### Compression Failure Handling
266
267
```kotlin
268
suspend fun safeCompressedUpload(data: ByteArray) {
269
try {
270
// Attempt compressed upload
271
client.post("/upload") {
272
compress("gzip")
273
setBody(data)
274
}
275
} catch (e: Exception) {
276
println("Compressed upload failed: ${e.message}")
277
278
// Retry without compression
279
client.post("/upload") {
280
setBody(data)
281
}
282
}
283
}
284
```
285
286
## Performance Considerations
287
288
### Compression Threshold
289
290
```kotlin
291
suspend fun efficientUpload(data: ByteArray) {
292
val compressionThreshold = 1024 // Don't compress small payloads
293
294
client.post("/upload") {
295
if (data.size >= compressionThreshold) {
296
compress("gzip")
297
}
298
setBody(data)
299
}
300
}
301
```
302
303
### Encoder Selection for Performance
304
305
```kotlin
306
// Fast compression for real-time uploads
307
client.post("/realtime-data") {
308
compress("deflate") // Generally faster than gzip
309
setBody(realtimeData)
310
}
311
312
// Best compression for large uploads
313
client.post("/large-file") {
314
compress("gzip") // Better compression ratio
315
setBody(largeFile)
316
}
317
```
318
319
### Memory-Efficient Streaming
320
321
```kotlin
322
import io.ktor.utils.io.*
323
324
suspend fun streamingCompressedUpload(dataChannel: ByteReadChannel) {
325
client.post("/streaming-upload") {
326
compress("gzip")
327
setBody(object : OutgoingContent.ReadChannelContent() {
328
override fun readFrom(): ByteReadChannel = dataChannel
329
override val contentLength: Long? = null // Unknown length for streaming
330
})
331
}
332
}
333
```
334
335
## Integration Examples
336
337
### File Upload Service
338
339
```kotlin
340
class FileUploadService(private val client: HttpClient) {
341
342
suspend fun uploadFile(filename: String, content: ByteArray): Boolean {
343
return try {
344
val response = client.post("/files/upload") {
345
compress("gzip")
346
contentType(ContentType.Application.OctetStream)
347
header("X-Filename", filename)
348
setBody(content)
349
}
350
response.status.isSuccess()
351
} catch (e: Exception) {
352
false
353
}
354
}
355
356
suspend fun uploadJson(data: Any): Boolean {
357
return try {
358
val response = client.post("/api/data") {
359
compress("gzip")
360
contentType(ContentType.Application.Json)
361
setBody(data)
362
}
363
response.status.isSuccess()
364
} catch (e: Exception) {
365
false
366
}
367
}
368
}
369
```
370
371
### Batch Data Upload
372
373
```kotlin
374
suspend fun uploadBatchData(records: List<DataRecord>) {
375
val jsonData = Json.encodeToString(records)
376
377
client.post("/batch-upload") {
378
compress("gzip") // JSON compresses very well
379
contentType(ContentType.Application.Json)
380
setBody(jsonData)
381
}
382
}
383
```
384
385
### API Client with Smart Compression
386
387
```kotlin
388
class ApiClient(private val client: HttpClient) {
389
390
suspend fun createResource(resource: Resource): Resource {
391
val response = client.post("/resources") {
392
// Compress JSON payloads
393
compress("gzip")
394
contentType(ContentType.Application.Json)
395
setBody(resource)
396
}
397
return response.body<Resource>()
398
}
399
400
suspend fun uploadDocument(document: ByteArray, mimeType: ContentType): String {
401
val response = client.post("/documents") {
402
// Compress based on content type
403
when (mimeType.contentType) {
404
"text", "application" -> compress("gzip")
405
else -> {
406
// Don't compress binary formats that are already compressed
407
}
408
}
409
contentType(mimeType)
410
setBody(document)
411
}
412
return response.body<String>()
413
}
414
}
415
```
416
417
## Complete Example
418
419
```kotlin
420
import io.ktor.client.*
421
import io.ktor.client.plugins.compression.*
422
import io.ktor.client.request.*
423
import io.ktor.http.*
424
425
suspend fun main() {
426
val client = HttpClient {
427
install(ContentEncoding) {
428
mode = ContentEncodingConfig.Mode.All
429
gzip()
430
deflate()
431
}
432
}
433
434
// Small payload - no compression
435
val smallData = "Small payload"
436
client.post("/small") {
437
setBody(smallData)
438
}
439
440
// Large text payload - gzip compression
441
val largeText = "Large text payload...".repeat(1000)
442
client.post("/large-text") {
443
compress("gzip")
444
contentType(ContentType.Text.Plain)
445
setBody(largeText)
446
}
447
448
// JSON data - gzip compression
449
val jsonData = """{"users": [...], "data": [...]}"""
450
client.post("/json-upload") {
451
compress("gzip")
452
contentType(ContentType.Application.Json)
453
setBody(jsonData)
454
}
455
456
// Binary data - deflate compression
457
val binaryData = ByteArray(10000) { it.toByte() }
458
client.post("/binary-upload") {
459
compress("deflate")
460
contentType(ContentType.Application.OctetStream)
461
setBody(binaryData)
462
}
463
464
// Multi-layer compression for maximum compression
465
val criticalData = "Critical data requiring maximum compression"
466
client.post("/critical") {
467
compress("deflate", "gzip") // Double compression
468
setBody(criticalData)
469
}
470
471
client.close()
472
}
473
```