CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-io-ktor--ktor-http-jvm

JVM-specific HTTP utilities and extensions for the Ktor framework providing URL utilities, file content type detection, HTTP message properties, and content handling for JVM platforms

Pending
Overview
Eval results
Files

content-handling.mddocs/

Content Handling

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.

Capabilities

OutgoingContent Base Class

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

/**
 * Base class for outgoing HTTP content
 */
abstract class OutgoingContent {
    /**
     * Content type of the response
     */
    open val contentType: ContentType?
    
    /**
     * Content length in bytes if known
     */
    open val contentLength: Long?
    
    /**
     * HTTP status code for the response
     */
    open val status: HttpStatusCode?
    
    /**
     * Additional HTTP headers
     */
    open val headers: Headers?
    
    /**
     * Trailing headers (HTTP/1.1 chunked encoding)
     */
    open fun trailers(): Headers?
    
    /**
     * Get property by key
     */
    fun <T : Any> getProperty(key: AttributeKey<T>): T?
    
    /**
     * Set property value
     */
    fun <T : Any> setProperty(key: AttributeKey<T>, value: T?)
}

/**
 * Check if content is empty
 */
fun OutgoingContent.isEmpty(): Boolean

ByteArrayContent

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

/**
 * Outgoing content backed by byte array
 */
abstract class OutgoingContent.ByteArrayContent : OutgoingContent() {
    /**
     * Get content as byte array
     */
    abstract fun bytes(): ByteArray
}

/**
 * Concrete byte array content implementation
 */
class ByteArrayContent(
    private val bytes: ByteArray,
    override val contentType: ContentType,
    override val status: HttpStatusCode? = null
) : OutgoingContent.ByteArrayContent() {
    
    override val contentLength: Long = bytes.size.toLong()
    
    override fun bytes(): ByteArray = bytes
}

TextContent

Text content with automatic charset handling and encoding.

/**
 * Text content with charset support
 */
class TextContent(
    private val text: String,
    override val contentType: ContentType,
    override val status: HttpStatusCode? = null
) : OutgoingContent.ByteArrayContent() {
    
    override val contentLength: Long
    
    /**
     * Get original text
     */
    val text: String
    
    override fun bytes(): ByteArray
}

WriteChannelContent

Content that writes data to a ByteWriteChannel for streaming.

/**
 * Content that writes to a channel
 */
abstract class OutgoingContent.WriteChannelContent : OutgoingContent() {
    /**
     * Write content to the channel
     * @param channel channel to write to
     */
    abstract suspend fun writeTo(channel: ByteWriteChannel)
}

/**
 * Channel writer content with suspend function body
 */
class ChannelWriterContent(
    private val body: suspend ByteWriteChannel.() -> Unit,
    override val contentType: ContentType,
    override val status: HttpStatusCode? = null,
    override val contentLength: Long? = null
) : OutgoingContent.WriteChannelContent() {
    
    override suspend fun writeTo(channel: ByteWriteChannel) {
        channel.body()
    }
}

ReadChannelContent

Content that provides data through a ByteReadChannel for streaming reads.

/**
 * Content that provides a read channel
 */
abstract class OutgoingContent.ReadChannelContent : OutgoingContent() {
    /**
     * Create read channel for full content
     */
    abstract fun readFrom(): ByteReadChannel
    
    /**
     * Create read channel for content range
     * @param range byte range to read
     */
    open fun readFrom(range: LongRange): ByteReadChannel
}

JVM-specific Content Types

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

OutputStreamContent

/**
 * Content that writes to an OutputStream (JVM-specific)
 */
class OutputStreamContent(
    private val body: suspend OutputStream.() -> Unit,
    override val contentType: ContentType,
    override val status: HttpStatusCode? = null,
    override val contentLength: Long? = null
) : OutgoingContent.WriteChannelContent() {
    
    override suspend fun writeTo(channel: ByteWriteChannel)
}

WriterContent

/**
 * Content that writes to a Writer with charset handling (JVM-specific)
 */
class WriterContent(
    private val body: suspend Writer.() -> Unit,
    override val contentType: ContentType,
    override val status: HttpStatusCode? = null,
    override val contentLength: Long? = null
) : OutgoingContent.WriteChannelContent() {
    
    override suspend fun writeTo(channel: ByteWriteChannel)
}

URIFileContent

/**
 * Content served from URI/URL (JVM-specific)
 */
class URIFileContent(
    val uri: URI,
    override val contentType: ContentType = ContentType.defaultForFilePath(uri.path),
    override val contentLength: Long? = null
) : OutgoingContent.ReadChannelContent() {
    
    /**
     * Constructor from URL
     */
    constructor(
        url: URL, 
        contentType: ContentType = ContentType.defaultForFilePath(url.path)
    )
    
    override fun readFrom(): ByteReadChannel
}

NoContent

Content for responses without body (like HTTP 204).

/**
 * Content representing no content
 */
abstract class OutgoingContent.NoContent : OutgoingContent()

ProtocolUpgrade

Content for protocol upgrade responses (like WebSocket).

/**
 * Content for protocol upgrade
 */
abstract class OutgoingContent.ProtocolUpgrade : OutgoingContent() {
    override val status: HttpStatusCode = HttpStatusCode.SwitchingProtocols
    
    /**
     * Perform protocol upgrade
     */
    abstract suspend fun upgrade(
        input: ByteReadChannel,
        output: ByteWriteChannel,
        engineContext: CoroutineContext,
        userContext: CoroutineContext
    )
}

ContentWrapper

Base class for content wrappers that delegate to another content.

/**
 * Content wrapper that delegates to another content
 */
abstract class OutgoingContent.ContentWrapper(
    private val delegate: OutgoingContent
) : OutgoingContent() {
    
    /**
     * Create copy with different delegate
     */
    abstract fun copy(delegate: OutgoingContent): ContentWrapper
    
    /**
     * Get wrapped content
     */
    fun delegate(): OutgoingContent
    
    override val contentType: ContentType? get() = delegate.contentType
    override val contentLength: Long? get() = delegate.contentLength
    override val status: HttpStatusCode? get() = delegate.status
    override val headers: Headers? get() = delegate.headers
}

Content Compression

Utilities for compressing outgoing content.

/**
 * Compress content using specified encoder
 * @param encoder content encoder to use
 * @param coroutineContext context for compression
 * @return compressed content
 */
fun OutgoingContent.compressed(
    encoder: ContentEncoder,
    coroutineContext: CoroutineContext = EmptyCoroutineContext
): OutgoingContent

Content Caching

Caching options and utilities for outgoing content.

/**
 * Caching options for content
 */
data class CachingOptions(
    val cacheControl: CacheControl? = null,
    val expires: GMTDate? = null
)

/**
 * Get caching options from content
 */
val OutgoingContent.caching: CachingOptions?

/**
 * Set caching options for content
 */
fun OutgoingContent.setCaching(options: CachingOptions)

/**
 * Property key for caching options
 */
val cachingProperty: AttributeKey<CachingOptions>

Special Content Types

Special content types for specific use cases.

/**
 * Represents null/empty body
 */
object NullBody

Usage Examples:

import io.ktor.http.*
import io.ktor.http.content.*
import java.io.*
import java.net.URI

// Simple text content
val textResponse = TextContent(
    text = "Hello, World!",
    contentType = ContentType.Text.Plain.withCharset(Charsets.UTF_8),
    status = HttpStatusCode.OK
)

// Byte array content
val jsonBytes = """{"message": "Hello"}""".toByteArray()
val jsonResponse = ByteArrayContent(
    bytes = jsonBytes,
    contentType = ContentType.Application.Json,
    status = HttpStatusCode.OK
)

// JVM-specific: OutputStream content
val streamContent = OutputStreamContent(
    body = { outputStream ->
        outputStream.write("Hello from OutputStream".toByteArray())
        outputStream.flush()
    },
    contentType = ContentType.Text.Plain,
    status = HttpStatusCode.OK
)

// JVM-specific: Writer content with charset handling
val writerContent = WriterContent(
    body = { writer ->
        writer.write("Hello from Writer")
        writer.flush()
    },
    contentType = ContentType.Text.Html.withCharset(Charsets.UTF_8),
    status = HttpStatusCode.OK
)

// JVM-specific: File content from URI
val fileUri = URI("file:///path/to/document.pdf")
val fileContent = URIFileContent(
    uri = fileUri,
    contentType = ContentType.Application.Pdf
)

// Channel writer for streaming
val streamingContent = ChannelWriterContent(
    body = { channel ->
        channel.writeStringUtf8("Chunk 1\n")
        channel.flush()
        delay(100)
        channel.writeStringUtf8("Chunk 2\n")
        channel.flush()
    },
    contentType = ContentType.Text.Plain,
    contentLength = null // Unknown length for streaming
)

// Content with caching
val cachedContent = TextContent("Cached response", ContentType.Text.Plain)
cachedContent.setCaching(CachingOptions(
    cacheControl = CacheControl.MaxAge(maxAgeSeconds = 3600),
    expires = GMTDate() + 3600_000 // 1 hour from now
))

// Compressed content
val compressedContent = textResponse.compressed(
    encoder = GzipEncoder,
    coroutineContext = Dispatchers.IO
)

// Check content properties
println("Content type: ${textResponse.contentType}")
println("Content length: ${textResponse.contentLength}")
println("Status: ${textResponse.status}")
println("Is empty: ${textResponse.isEmpty()}")

// Access content data
when (val content = response.content) {
    is TextContent -> println("Text: ${content.text}")
    is ByteArrayContent -> println("Bytes: ${content.bytes().size}")
    is URIFileContent -> println("URI: ${content.uri}")
}

Types

All types are defined above in their respective capability sections.

Content Properties

/**
 * Property key for version list
 */
val versionListProperty: AttributeKey<List<Version>>

/**
 * Get versions from content
 */
val OutgoingContent.versions: List<Version>

/**
 * Set versions for content
 */
fun OutgoingContent.setVersions(versions: List<Version>)

Install with Tessl CLI

npx tessl i tessl/maven-io-ktor--ktor-http-jvm

docs

authentication.md

content-handling.md

content-types.md

cookie-management.md

headers-parameters.md

http-core-types.md

index.md

message-properties.md

multipart-data.md

url-encoding.md

url-handling.md

tile.json