HTTP client content encoding plugin for compression and decompression in Ktor applications.
—
Comprehensive configuration options for the ContentEncoding plugin including operation modes, encoder settings, and quality value management.
class ContentEncodingConfig {
enum class Mode(internal val request: Boolean, internal val response: Boolean) {
CompressRequest(true, false),
DecompressResponse(false, true),
All(true, true)
}
var mode: Mode
/**
* Installs the `gzip` encoder.
* @param quality a priority value to use in the `Accept-Encoding` header.
*/
fun gzip(quality: Float? = null): Unit
/**
* Installs the `deflate` encoder.
* @param quality a priority value to use in the `Accept-Encoding` header.
*/
fun deflate(quality: Float? = null): Unit
/**
* Installs the `identity` encoder.
* @param quality a priority value to use in the `Accept-Encoding` header.
*/
fun identity(quality: Float? = null): Unit
/**
* Installs a custom encoder.
* @param encoder a custom encoder to use.
* @param quality a priority value to use in the `Accept-Encoding` header.
*/
fun customEncoder(encoder: ContentEncoder, quality: Float? = null): Unit
}fun HttpClientConfig<*>.ContentEncoding(
mode: ContentEncodingConfig.Mode = ContentEncodingConfig.Mode.DecompressResponse,
block: ContentEncodingConfig.() -> Unit = {
gzip()
deflate()
identity()
}
): Unitimport io.ktor.client.*
import io.ktor.client.plugins.compression.*
val client = HttpClient {
install(ContentEncoding) {
gzip()
deflate()
identity()
}
}val client = HttpClient {
install(ContentEncoding) {
mode = ContentEncodingConfig.Mode.All
gzip(0.9f)
deflate(0.8f)
identity(0.1f)
}
}Only decompresses incoming response bodies. Does not compress outgoing requests.
install(ContentEncoding) {
mode = ContentEncodingConfig.Mode.DecompressResponse
gzip()
deflate()
}Behavior:
Accept-Encoding header on outgoing requestsContent-Encoding headerUse Cases:
Only compresses outgoing request bodies. Does not decompress incoming responses.
install(ContentEncoding) {
mode = ContentEncodingConfig.Mode.CompressRequest
gzip()
deflate()
}Behavior:
compress() functionAccept-Encoding headerUse Cases:
Both compresses outgoing requests and decompresses incoming responses.
install(ContentEncoding) {
mode = ContentEncodingConfig.Mode.All
gzip()
deflate()
}Behavior:
Accept-Encoding header on requestsUse Cases:
Quality values (q-values) specify preference order in the Accept-Encoding header, ranging from 0.0 to 1.0.
install(ContentEncoding) {
gzip(0.9f) // Highest preference
deflate(0.8f) // Medium preference
identity(0.1f) // Lowest preference (fallback)
}Generated Accept-Encoding Header:
Accept-Encoding: gzip;q=0.9,deflate;q=0.8,identity;q=0.1install(ContentEncoding) {
// Valid quality values (0.0 to 1.0)
gzip(1.0f) // Maximum preference
deflate(0.5f) // Medium preference
identity(0.0f) // Minimum preference
// No quality value = included without q-value
gzip() // Equivalent to highest preference
}Validation:
IllegalArgumentExceptionval highBandwidth = true
install(ContentEncoding) {
if (highBandwidth) {
gzip(0.9f)
deflate(0.8f)
} else {
identity(1.0f) // Prefer no compression on low bandwidth
}
}fun customEncoder(encoder: ContentEncoder, quality: Float? = null): Unitclass BrotliEncoder : ContentEncoder {
override val name: String = "br"
override fun encode(
source: ByteReadChannel,
coroutineContext: CoroutineContext
): ByteReadChannel {
// Brotli compression implementation
TODO("Implement Brotli compression")
}
override fun decode(
source: ByteReadChannel,
coroutineContext: CoroutineContext
): ByteReadChannel {
// Brotli decompression implementation
TODO("Implement Brotli decompression")
}
override fun predictCompressedLength(contentLength: Long): Long? {
return (contentLength * 0.7).toLong() // Estimate 30% compression
}
}
// Register custom encoder
install(ContentEncoding) {
customEncoder(BrotliEncoder(), 0.95f)
gzip(0.9f)
deflate(0.8f)
}install(ContentEncoding) {
// Add encoders
gzip(0.9f)
deflate(0.8f)
// Remove encoder (by re-adding with null quality)
gzip(null) // Removes gzip encoder
// Re-add with different quality
gzip(0.5f) // Adds gzip back with lower priority
}install(ContentEncoding) {
try {
gzip(1.5f) // Invalid: > 1.0
} catch (e: IllegalArgumentException) {
println("Invalid quality value: ${e.message}")
}
try {
deflate(-0.1f) // Invalid: < 0.0
} catch (e: IllegalArgumentException) {
println("Invalid quality value: ${e.message}")
}
}class InvalidEncoder : ContentEncoder {
override val name: String = "" // Invalid: empty name
// ... rest of implementation
}
install(ContentEncoding) {
try {
customEncoder(InvalidEncoder())
} catch (e: IllegalArgumentException) {
println("Invalid encoder: ${e.message}")
}
}val client = HttpClient {
install(ContentEncoding) // Uses defaults: DecompressResponse mode with gzip, deflate, identity
}val uploadClient = HttpClient {
install(ContentEncoding) {
mode = ContentEncodingConfig.Mode.CompressRequest
gzip()
}
}val performanceClient = HttpClient {
install(ContentEncoding) {
mode = ContentEncodingConfig.Mode.All
gzip(1.0f) // Prefer gzip for best compression
deflate(0.8f) // Fallback to deflate
identity(0.1f) // Last resort: no compression
}
}val debugClient = HttpClient {
install(ContentEncoding) {
mode = ContentEncodingConfig.Mode.DecompressResponse
identity(1.0f) // Prefer uncompressed for easier debugging
gzip(0.5f) // Allow compression if server insists
}
}Install with Tessl CLI
npx tessl i tessl/maven-io-ktor--ktor-client-encoding