HTTP client content encoding plugin for compression and decompression in Ktor applications.
—
Compress outgoing HTTP request bodies to reduce bandwidth usage and improve upload performance using configurable compression algorithms.
/**
* Compresses request body using ContentEncoding plugin.
* @param contentEncoderName names of compression encoders to use, such as "gzip", "deflate", etc
*/
fun HttpRequestBuilder.compress(vararg contentEncoderName: String): Unit
/**
* Compress request body using ContentEncoding plugin.
* @param contentEncoderNames names of compression encoders to use, such as "gzip", "deflate", etc
*/
fun HttpRequestBuilder.compress(contentEncoderNames: List<String>): Unitimport io.ktor.client.request.*
import io.ktor.client.plugins.compression.*
// Single encoder
client.post("/api/upload") {
compress("gzip")
setBody("Large payload data")
}
// Multiple encoders (applied in order)
client.put("/api/update") {
compress("gzip", "deflate")
setBody(largeData)
}
// List-based specification
client.patch("/api/modify") {
compress(listOf("deflate", "gzip"))
setBody(payload)
}val client = HttpClient {
install(ContentEncoding) {
mode = ContentEncodingConfig.Mode.CompressRequest // Only compress requests
gzip()
deflate()
}
}
// All requests can now use compression
client.post("/upload1") {
compress("gzip")
setBody(data1)
}
client.post("/upload2") {
compress("deflate")
setBody(data2)
}val client = HttpClient {
install(ContentEncoding) {
mode = ContentEncodingConfig.Mode.All // Compress requests AND decompress responses
gzip()
deflate()
identity()
}
}
client.post("/api/data") {
compress("gzip")
setBody(requestData)
}
// Response automatically decompressed if server sends compressed dataclient.post("/upload") {
compress("gzip")
setBody("Data to compress")
}
// Automatically sets: Content-Encoding: gzip
// Original Content-Length header is removed (compressed length is different)
// Vary header includes Accept-Encoding// Apply multiple compression layers
client.post("/complex-upload") {
compress("deflate", "gzip") // deflate first, then gzip
setBody(complexData)
}
// Server must decompress in reverse order: gzip first, then deflateProcessing Order:
Content-Encoding: deflate, gzipimport io.ktor.http.*
// JSON data compression
client.post("/api/json") {
compress("gzip")
contentType(ContentType.Application.Json)
setBody("""{"large": "json", "data": "here"}""")
}
// Binary data compression
client.post("/api/binary") {
compress("deflate")
contentType(ContentType.Application.OctetStream)
setBody(binaryData)
}
// Form data compression
client.post("/api/form") {
compress("gzip")
contentType(ContentType.Application.FormUrlEncoded)
setBody(formParameters)
}suspend fun uploadWithConditionalCompression(data: ByteArray) {
val shouldCompress = data.size > 1024 // Only compress large payloads
client.post("/upload") {
if (shouldCompress) {
compress("gzip")
}
setBody(data)
}
}suspend fun uploadWithSmartCompression(content: Any, contentType: ContentType) {
client.post("/smart-upload") {
when (contentType) {
ContentType.Application.Json,
ContentType.Text.Plain,
ContentType.Application.Xml -> {
compress("gzip") // Text-based content compresses well
}
ContentType.Image.JPEG,
ContentType.Image.PNG -> {
// Images are already compressed, skip compression
}
else -> {
compress("deflate") // Default to deflate for other types
}
}
contentType(contentType)
setBody(content)
}
}import io.ktor.client.request.forms.*
import io.ktor.http.content.*
suspend fun uploadLargeFile(file: ByteArray) {
client.post("/large-upload") {
compress("gzip")
setBody(MultiPartFormDataContent(
formData {
append("file", file, Headers.build {
append(HttpHeaders.ContentDisposition, "filename=large-file.dat")
})
}
))
}
}// Compression occurs in the request pipeline after content rendering
// Order: Content Creation → Rendering → Compression → Network Send
client.post("/data") {
// 1. Content created
setBody(originalContent)
// 2. Content rendered to OutgoingContent
// 3. Compression applied (if compress() called)
compress("gzip")
// 4. Compressed content sent over network
}internal val CompressionListAttribute: AttributeKey<List<String>>Internal Usage:
// The compress() function sets internal attributes
client.post("/upload") {
compress("gzip", "deflate")
// Internally: attributes.put(CompressionListAttribute, listOf("gzip", "deflate"))
setBody(data)
}try {
client.post("/upload") {
compress("unknown-algorithm") // Not registered in ContentEncodingConfig
setBody(data)
}
} catch (e: UnsupportedContentEncodingException) {
println("Compression failed: ${e.message}")
// Fallback to uncompressed upload
client.post("/upload") {
setBody(data)
}
}suspend fun safeCompressedUpload(data: ByteArray) {
try {
// Attempt compressed upload
client.post("/upload") {
compress("gzip")
setBody(data)
}
} catch (e: Exception) {
println("Compressed upload failed: ${e.message}")
// Retry without compression
client.post("/upload") {
setBody(data)
}
}
}suspend fun efficientUpload(data: ByteArray) {
val compressionThreshold = 1024 // Don't compress small payloads
client.post("/upload") {
if (data.size >= compressionThreshold) {
compress("gzip")
}
setBody(data)
}
}// Fast compression for real-time uploads
client.post("/realtime-data") {
compress("deflate") // Generally faster than gzip
setBody(realtimeData)
}
// Best compression for large uploads
client.post("/large-file") {
compress("gzip") // Better compression ratio
setBody(largeFile)
}import io.ktor.utils.io.*
suspend fun streamingCompressedUpload(dataChannel: ByteReadChannel) {
client.post("/streaming-upload") {
compress("gzip")
setBody(object : OutgoingContent.ReadChannelContent() {
override fun readFrom(): ByteReadChannel = dataChannel
override val contentLength: Long? = null // Unknown length for streaming
})
}
}class FileUploadService(private val client: HttpClient) {
suspend fun uploadFile(filename: String, content: ByteArray): Boolean {
return try {
val response = client.post("/files/upload") {
compress("gzip")
contentType(ContentType.Application.OctetStream)
header("X-Filename", filename)
setBody(content)
}
response.status.isSuccess()
} catch (e: Exception) {
false
}
}
suspend fun uploadJson(data: Any): Boolean {
return try {
val response = client.post("/api/data") {
compress("gzip")
contentType(ContentType.Application.Json)
setBody(data)
}
response.status.isSuccess()
} catch (e: Exception) {
false
}
}
}suspend fun uploadBatchData(records: List<DataRecord>) {
val jsonData = Json.encodeToString(records)
client.post("/batch-upload") {
compress("gzip") // JSON compresses very well
contentType(ContentType.Application.Json)
setBody(jsonData)
}
}class ApiClient(private val client: HttpClient) {
suspend fun createResource(resource: Resource): Resource {
val response = client.post("/resources") {
// Compress JSON payloads
compress("gzip")
contentType(ContentType.Application.Json)
setBody(resource)
}
return response.body<Resource>()
}
suspend fun uploadDocument(document: ByteArray, mimeType: ContentType): String {
val response = client.post("/documents") {
// Compress based on content type
when (mimeType.contentType) {
"text", "application" -> compress("gzip")
else -> {
// Don't compress binary formats that are already compressed
}
}
contentType(mimeType)
setBody(document)
}
return response.body<String>()
}
}import io.ktor.client.*
import io.ktor.client.plugins.compression.*
import io.ktor.client.request.*
import io.ktor.http.*
suspend fun main() {
val client = HttpClient {
install(ContentEncoding) {
mode = ContentEncodingConfig.Mode.All
gzip()
deflate()
}
}
// Small payload - no compression
val smallData = "Small payload"
client.post("/small") {
setBody(smallData)
}
// Large text payload - gzip compression
val largeText = "Large text payload...".repeat(1000)
client.post("/large-text") {
compress("gzip")
contentType(ContentType.Text.Plain)
setBody(largeText)
}
// JSON data - gzip compression
val jsonData = """{"users": [...], "data": [...]}"""
client.post("/json-upload") {
compress("gzip")
contentType(ContentType.Application.Json)
setBody(jsonData)
}
// Binary data - deflate compression
val binaryData = ByteArray(10000) { it.toByte() }
client.post("/binary-upload") {
compress("deflate")
contentType(ContentType.Application.OctetStream)
setBody(binaryData)
}
// Multi-layer compression for maximum compression
val criticalData = "Critical data requiring maximum compression"
client.post("/critical") {
compress("deflate", "gzip") // Double compression
setBody(criticalData)
}
client.close()
}Install with Tessl CLI
npx tessl i tessl/maven-io-ktor--ktor-client-encoding