or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

authentication.mdcontent-handling.mdcontent-types.mdcookie-management.mdheaders-parameters.mdhttp-core-types.mdindex.mdmessage-properties.mdmultipart-data.mdurl-encoding.mdurl-handling.md

content-handling.mddocs/

0

# Content Handling

1

2

Outgoing content system with JVM-specific implementations for streams, writers, and file content. Provides base classes and concrete implementations for handling various types of HTTP response content.

3

4

## Capabilities

5

6

### OutgoingContent Base Class

7

8

Abstract base class for all outgoing HTTP content with property management and caching support.

9

10

```kotlin { .api }

11

/**

12

* Base class for outgoing HTTP content

13

*/

14

abstract class OutgoingContent {

15

/**

16

* Content type of the response

17

*/

18

open val contentType: ContentType?

19

20

/**

21

* Content length in bytes if known

22

*/

23

open val contentLength: Long?

24

25

/**

26

* HTTP status code for the response

27

*/

28

open val status: HttpStatusCode?

29

30

/**

31

* Additional HTTP headers

32

*/

33

open val headers: Headers?

34

35

/**

36

* Trailing headers (HTTP/1.1 chunked encoding)

37

*/

38

open fun trailers(): Headers?

39

40

/**

41

* Get property by key

42

*/

43

fun <T : Any> getProperty(key: AttributeKey<T>): T?

44

45

/**

46

* Set property value

47

*/

48

fun <T : Any> setProperty(key: AttributeKey<T>, value: T?)

49

}

50

51

/**

52

* Check if content is empty

53

*/

54

fun OutgoingContent.isEmpty(): Boolean

55

```

56

57

### ByteArrayContent

58

59

Content backed by a byte array for small, in-memory content.

60

61

```kotlin { .api }

62

/**

63

* Outgoing content backed by byte array

64

*/

65

abstract class OutgoingContent.ByteArrayContent : OutgoingContent() {

66

/**

67

* Get content as byte array

68

*/

69

abstract fun bytes(): ByteArray

70

}

71

72

/**

73

* Concrete byte array content implementation

74

*/

75

class ByteArrayContent(

76

private val bytes: ByteArray,

77

override val contentType: ContentType,

78

override val status: HttpStatusCode? = null

79

) : OutgoingContent.ByteArrayContent() {

80

81

override val contentLength: Long = bytes.size.toLong()

82

83

override fun bytes(): ByteArray = bytes

84

}

85

```

86

87

### TextContent

88

89

Text content with automatic charset handling and encoding.

90

91

```kotlin { .api }

92

/**

93

* Text content with charset support

94

*/

95

class TextContent(

96

private val text: String,

97

override val contentType: ContentType,

98

override val status: HttpStatusCode? = null

99

) : OutgoingContent.ByteArrayContent() {

100

101

override val contentLength: Long

102

103

/**

104

* Get original text

105

*/

106

val text: String

107

108

override fun bytes(): ByteArray

109

}

110

```

111

112

### WriteChannelContent

113

114

Content that writes data to a ByteWriteChannel for streaming.

115

116

```kotlin { .api }

117

/**

118

* Content that writes to a channel

119

*/

120

abstract class OutgoingContent.WriteChannelContent : OutgoingContent() {

121

/**

122

* Write content to the channel

123

* @param channel channel to write to

124

*/

125

abstract suspend fun writeTo(channel: ByteWriteChannel)

126

}

127

128

/**

129

* Channel writer content with suspend function body

130

*/

131

class ChannelWriterContent(

132

private val body: suspend ByteWriteChannel.() -> Unit,

133

override val contentType: ContentType,

134

override val status: HttpStatusCode? = null,

135

override val contentLength: Long? = null

136

) : OutgoingContent.WriteChannelContent() {

137

138

override suspend fun writeTo(channel: ByteWriteChannel) {

139

channel.body()

140

}

141

}

142

```

143

144

### ReadChannelContent

145

146

Content that provides data through a ByteReadChannel for streaming reads.

147

148

```kotlin { .api }

149

/**

150

* Content that provides a read channel

151

*/

152

abstract class OutgoingContent.ReadChannelContent : OutgoingContent() {

153

/**

154

* Create read channel for full content

155

*/

156

abstract fun readFrom(): ByteReadChannel

157

158

/**

159

* Create read channel for content range

160

* @param range byte range to read

161

*/

162

open fun readFrom(range: LongRange): ByteReadChannel

163

}

164

```

165

166

### JVM-specific Content Types

167

168

JVM-specific content implementations using Java I/O streams and writers.

169

170

#### OutputStreamContent

171

172

```kotlin { .api }

173

/**

174

* Content that writes to an OutputStream (JVM-specific)

175

*/

176

class OutputStreamContent(

177

private val body: suspend OutputStream.() -> Unit,

178

override val contentType: ContentType,

179

override val status: HttpStatusCode? = null,

180

override val contentLength: Long? = null

181

) : OutgoingContent.WriteChannelContent() {

182

183

override suspend fun writeTo(channel: ByteWriteChannel)

184

}

185

```

186

187

#### WriterContent

188

189

```kotlin { .api }

190

/**

191

* Content that writes to a Writer with charset handling (JVM-specific)

192

*/

193

class WriterContent(

194

private val body: suspend Writer.() -> Unit,

195

override val contentType: ContentType,

196

override val status: HttpStatusCode? = null,

197

override val contentLength: Long? = null

198

) : OutgoingContent.WriteChannelContent() {

199

200

override suspend fun writeTo(channel: ByteWriteChannel)

201

}

202

```

203

204

#### URIFileContent

205

206

```kotlin { .api }

207

/**

208

* Content served from URI/URL (JVM-specific)

209

*/

210

class URIFileContent(

211

val uri: URI,

212

override val contentType: ContentType = ContentType.defaultForFilePath(uri.path),

213

override val contentLength: Long? = null

214

) : OutgoingContent.ReadChannelContent() {

215

216

/**

217

* Constructor from URL

218

*/

219

constructor(

220

url: URL,

221

contentType: ContentType = ContentType.defaultForFilePath(url.path)

222

)

223

224

override fun readFrom(): ByteReadChannel

225

}

226

```

227

228

### NoContent

229

230

Content for responses without body (like HTTP 204).

231

232

```kotlin { .api }

233

/**

234

* Content representing no content

235

*/

236

abstract class OutgoingContent.NoContent : OutgoingContent()

237

```

238

239

### ProtocolUpgrade

240

241

Content for protocol upgrade responses (like WebSocket).

242

243

```kotlin { .api }

244

/**

245

* Content for protocol upgrade

246

*/

247

abstract class OutgoingContent.ProtocolUpgrade : OutgoingContent() {

248

override val status: HttpStatusCode = HttpStatusCode.SwitchingProtocols

249

250

/**

251

* Perform protocol upgrade

252

*/

253

abstract suspend fun upgrade(

254

input: ByteReadChannel,

255

output: ByteWriteChannel,

256

engineContext: CoroutineContext,

257

userContext: CoroutineContext

258

)

259

}

260

```

261

262

### ContentWrapper

263

264

Base class for content wrappers that delegate to another content.

265

266

```kotlin { .api }

267

/**

268

* Content wrapper that delegates to another content

269

*/

270

abstract class OutgoingContent.ContentWrapper(

271

private val delegate: OutgoingContent

272

) : OutgoingContent() {

273

274

/**

275

* Create copy with different delegate

276

*/

277

abstract fun copy(delegate: OutgoingContent): ContentWrapper

278

279

/**

280

* Get wrapped content

281

*/

282

fun delegate(): OutgoingContent

283

284

override val contentType: ContentType? get() = delegate.contentType

285

override val contentLength: Long? get() = delegate.contentLength

286

override val status: HttpStatusCode? get() = delegate.status

287

override val headers: Headers? get() = delegate.headers

288

}

289

```

290

291

### Content Compression

292

293

Utilities for compressing outgoing content.

294

295

```kotlin { .api }

296

/**

297

* Compress content using specified encoder

298

* @param encoder content encoder to use

299

* @param coroutineContext context for compression

300

* @return compressed content

301

*/

302

fun OutgoingContent.compressed(

303

encoder: ContentEncoder,

304

coroutineContext: CoroutineContext = EmptyCoroutineContext

305

): OutgoingContent

306

```

307

308

### Content Caching

309

310

Caching options and utilities for outgoing content.

311

312

```kotlin { .api }

313

/**

314

* Caching options for content

315

*/

316

data class CachingOptions(

317

val cacheControl: CacheControl? = null,

318

val expires: GMTDate? = null

319

)

320

321

/**

322

* Get caching options from content

323

*/

324

val OutgoingContent.caching: CachingOptions?

325

326

/**

327

* Set caching options for content

328

*/

329

fun OutgoingContent.setCaching(options: CachingOptions)

330

331

/**

332

* Property key for caching options

333

*/

334

val cachingProperty: AttributeKey<CachingOptions>

335

```

336

337

### Special Content Types

338

339

Special content types for specific use cases.

340

341

```kotlin { .api }

342

/**

343

* Represents null/empty body

344

*/

345

object NullBody

346

```

347

348

**Usage Examples:**

349

350

```kotlin

351

import io.ktor.http.*

352

import io.ktor.http.content.*

353

import java.io.*

354

import java.net.URI

355

356

// Simple text content

357

val textResponse = TextContent(

358

text = "Hello, World!",

359

contentType = ContentType.Text.Plain.withCharset(Charsets.UTF_8),

360

status = HttpStatusCode.OK

361

)

362

363

// Byte array content

364

val jsonBytes = """{"message": "Hello"}""".toByteArray()

365

val jsonResponse = ByteArrayContent(

366

bytes = jsonBytes,

367

contentType = ContentType.Application.Json,

368

status = HttpStatusCode.OK

369

)

370

371

// JVM-specific: OutputStream content

372

val streamContent = OutputStreamContent(

373

body = { outputStream ->

374

outputStream.write("Hello from OutputStream".toByteArray())

375

outputStream.flush()

376

},

377

contentType = ContentType.Text.Plain,

378

status = HttpStatusCode.OK

379

)

380

381

// JVM-specific: Writer content with charset handling

382

val writerContent = WriterContent(

383

body = { writer ->

384

writer.write("Hello from Writer")

385

writer.flush()

386

},

387

contentType = ContentType.Text.Html.withCharset(Charsets.UTF_8),

388

status = HttpStatusCode.OK

389

)

390

391

// JVM-specific: File content from URI

392

val fileUri = URI("file:///path/to/document.pdf")

393

val fileContent = URIFileContent(

394

uri = fileUri,

395

contentType = ContentType.Application.Pdf

396

)

397

398

// Channel writer for streaming

399

val streamingContent = ChannelWriterContent(

400

body = { channel ->

401

channel.writeStringUtf8("Chunk 1\n")

402

channel.flush()

403

delay(100)

404

channel.writeStringUtf8("Chunk 2\n")

405

channel.flush()

406

},

407

contentType = ContentType.Text.Plain,

408

contentLength = null // Unknown length for streaming

409

)

410

411

// Content with caching

412

val cachedContent = TextContent("Cached response", ContentType.Text.Plain)

413

cachedContent.setCaching(CachingOptions(

414

cacheControl = CacheControl.MaxAge(maxAgeSeconds = 3600),

415

expires = GMTDate() + 3600_000 // 1 hour from now

416

))

417

418

// Compressed content

419

val compressedContent = textResponse.compressed(

420

encoder = GzipEncoder,

421

coroutineContext = Dispatchers.IO

422

)

423

424

// Check content properties

425

println("Content type: ${textResponse.contentType}")

426

println("Content length: ${textResponse.contentLength}")

427

println("Status: ${textResponse.status}")

428

println("Is empty: ${textResponse.isEmpty()}")

429

430

// Access content data

431

when (val content = response.content) {

432

is TextContent -> println("Text: ${content.text}")

433

is ByteArrayContent -> println("Bytes: ${content.bytes().size}")

434

is URIFileContent -> println("URI: ${content.uri}")

435

}

436

```

437

438

## Types

439

440

All types are defined above in their respective capability sections.

441

442

## Content Properties

443

444

```kotlin { .api }

445

/**

446

* Property key for version list

447

*/

448

val versionListProperty: AttributeKey<List<Version>>

449

450

/**

451

* Get versions from content

452

*/

453

val OutgoingContent.versions: List<Version>

454

455

/**

456

* Set versions for content

457

*/

458

fun OutgoingContent.setVersions(versions: List<Version>)

459

```