or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

conditions.mdconfiguration.mdcontrol.mddecompression.mdencoding.mdindex.md

control.mddocs/

0

# Compression Control

1

2

The Compression plugin provides runtime control mechanisms to selectively suppress compression or decompression on a per-request basis, giving you fine-grained control over when these operations occur.

3

4

## Suppression Functions

5

6

### Suppress Response Compression

7

8

```kotlin { .api }

9

fun ApplicationCall.suppressCompression()

10

```

11

12

Prevents the current response from being compressed, regardless of plugin configuration:

13

14

```kotlin

15

routing {

16

get("/no-compression") {

17

call.suppressCompression()

18

call.respondText("This response will never be compressed")

19

}

20

21

get("/conditional") {

22

if (call.request.queryParameters["raw"] == "true") {

23

call.suppressCompression()

24

}

25

call.respond("Conditionally compressed response")

26

}

27

}

28

```

29

30

### Suppress Request Decompression

31

32

```kotlin { .api }

33

fun ApplicationCall.suppressDecompression()

34

```

35

36

Prevents the current request body from being decompressed, allowing access to raw compressed data:

37

38

```kotlin

39

routing {

40

post("/raw-upload") {

41

call.suppressDecompression()

42

43

// Receive compressed bytes directly

44

val compressedData = call.receive<ByteArray>()

45

46

// Process compressed data or decompress manually

47

val originalSize = call.request.headers[HttpHeaders.ContentLength]?.toInt() ?: 0

48

logger.info("Received $originalSize bytes of compressed data")

49

50

call.respond("Processed raw compressed upload")

51

}

52

}

53

```

54

55

## Suppression Status Checking

56

57

### Check Compression Suppression

58

59

```kotlin { .api }

60

val ApplicationCall.isCompressionSuppressed: Boolean

61

```

62

63

Determine if response compression has been suppressed for the current call:

64

65

```kotlin

66

routing {

67

get("/debug-compression") {

68

if (call.isCompressionSuppressed) {

69

call.respond("Compression is suppressed")

70

} else {

71

call.respond("Compression is active")

72

}

73

}

74

}

75

```

76

77

### Check Decompression Suppression

78

79

```kotlin { .api }

80

val ApplicationCall.isDecompressionSuppressed: Boolean

81

```

82

83

Determine if request decompression has been suppressed for the current call:

84

85

```kotlin

86

routing {

87

post("/upload") {

88

val message = if (call.isDecompressionSuppressed) {

89

"Processing raw compressed data"

90

} else {

91

"Processing decompressed data"

92

}

93

94

logger.info(message)

95

val data = call.receiveText()

96

call.respond("Processed: ${data.length} characters")

97

}

98

}

99

```

100

101

## Use Cases

102

103

### Pre-compressed Content

104

105

Serve pre-compressed static files without double compression:

106

107

```kotlin

108

routing {

109

static("/assets") {

110

files("static")

111

// Ktor automatically calls suppressCompression() for pre-compressed files

112

// like .gz, .br variants

113

}

114

115

get("/precompressed/{file}") {

116

val filename = call.parameters["file"]

117

val gzFile = File("compressed/$filename.gz")

118

119

if (gzFile.exists()) {

120

call.suppressCompression()

121

call.response.header(HttpHeaders.ContentEncoding, "gzip")

122

call.respondFile(gzFile)

123

} else {

124

call.respondText("File not found", status = HttpStatusCode.NotFound)

125

}

126

}

127

}

128

```

129

130

### Binary Data Handling

131

132

Handle binary uploads that shouldn't be decompressed:

133

134

```kotlin

135

routing {

136

post("/binary-upload") {

137

val contentType = call.request.contentType()

138

139

if (contentType?.match(ContentType.Application.OctetStream) == true) {

140

// Keep binary data compressed for efficient storage

141

call.suppressDecompression()

142

143

val compressedBytes = call.receive<ByteArray>()

144

// Store compressed data directly

145

database.storeBinary(compressedBytes)

146

} else {

147

// Normal decompression for text/JSON data

148

val content = call.receiveText()

149

processTextContent(content)

150

}

151

152

call.respond("Upload processed")

153

}

154

}

155

```

156

157

### Performance Optimization

158

159

Skip compression for small responses or specific content types:

160

161

```kotlin

162

routing {

163

get("/small-response") {

164

val data = generateSmallResponse()

165

166

if (data.length < 100) {

167

// Skip compression overhead for very small responses

168

call.suppressCompression()

169

}

170

171

call.respondText(data)

172

}

173

174

get("/image-proxy/{id}") {

175

val imageData = imageService.getImage(call.parameters["id"])

176

177

// Images are already compressed

178

call.suppressCompression()

179

call.respondBytes(imageData, ContentType.Image.JPEG)

180

}

181

}

182

```

183

184

### Debug and Development

185

186

Disable compression for easier debugging:

187

188

```kotlin

189

routing {

190

get("/api/{...}") {

191

if (call.request.headers["X-Debug-Mode"] == "true") {

192

call.suppressCompression()

193

}

194

195

val response = apiService.processRequest(call)

196

call.respond(response)

197

}

198

}

199

```

200

201

### Conditional Suppression with Interceptors

202

203

Apply suppression logic globally using interceptors:

204

205

```kotlin

206

install(createApplicationPlugin("CompressionControl") {

207

onCall { call ->

208

// Suppress compression for API documentation endpoints

209

if (call.request.uri.startsWith("/docs/")) {

210

call.suppressCompression()

211

}

212

213

// Suppress decompression for webhook endpoints that need raw data

214

if (call.request.uri.startsWith("/webhooks/")) {

215

call.suppressDecompression()

216

}

217

}

218

})

219

```

220

221

## Implementation Notes

222

223

### Suppression Attributes

224

225

The suppression system uses internal attribute keys:

226

227

```kotlin

228

internal val SuppressionAttribute: AttributeKey<Boolean>

229

internal val DecompressionSuppressionAttribute: AttributeKey<Boolean>

230

```

231

232

These attributes are automatically checked by the compression plugin during request/response processing.

233

234

### Timing Requirements

235

236

Suppression calls must be made before the compression/decompression logic executes:

237

238

- **Compression suppression**: Call before response content is processed

239

- **Decompression suppression**: Call before request body is consumed

240

241

```kotlin

242

routing {

243

post("/example") {

244

// ✅ Correct: suppress before processing

245

call.suppressDecompression()

246

val body = call.receiveText()

247

248

// ❌ Incorrect: too late to suppress compression

249

call.suppressCompression() // This won't work

250

call.respond(body)

251

}

252

}

253

```

254

255

### Interaction with Conditions

256

257

Suppression overrides all configured conditions. Even if conditions would normally allow compression/decompression, suppression takes precedence:

258

259

```kotlin

260

install(Compression) {

261

matchContentType(ContentType.Text.Plain) // Condition allows text compression

262

}

263

264

routing {

265

get("/text") {

266

call.suppressCompression() // Overrides condition - no compression occurs

267

call.respondText("This text won't be compressed", ContentType.Text.Plain)

268

}

269

}

270

```