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
—
HTTP message property extraction and manipulation with JVM-specific Date support, providing convenient access to common HTTP headers with proper type conversion.
Base interface for HTTP messages (requests and responses) providing header access.
/**
* Base interface for HTTP messages
*/
interface HttpMessage {
/**
* HTTP headers for this message
*/
val headers: Headers
}
/**
* Base interface for HTTP message builders
*/
interface HttpMessageBuilder {
/**
* Mutable HTTP headers for this message
*/
val headers: HeadersBuilder
}Functions for extracting common HTTP message properties with proper type conversion.
/**
* Get Content-Type header value
* @return ContentType instance or null if not present
*/
fun HttpMessage.contentType(): ContentType?
/**
* Get Content-Type header value from builder
* @return ContentType instance or null if not present
*/
fun HttpMessageBuilder.contentType(): ContentType?
/**
* Set Content-Type header
* @param contentType content type to set
*/
fun HttpMessageBuilder.contentType(contentType: ContentType)
/**
* Get Content-Length header value
* @return content length as Long or null if not present
*/
fun HttpMessage.contentLength(): Long?
/**
* Get Content-Length header value from builder
* @return content length as Long or null if not present
*/
fun HttpMessageBuilder.contentLength(): Long?
/**
* Get charset from Content-Type header
* @return Charset instance or null if not specified
*/
fun HttpMessage.charset(): Charset?
/**
* Get charset from Content-Type header in builder
* @return Charset instance or null if not specified
*/
fun HttpMessageBuilder.charset(): Charset?
/**
* Get ETag header value
* @return ETag value or null if not present
*/
fun HttpMessage.etag(): String?
/**
* Get ETag header value from builder
* @return ETag value or null if not present
*/
fun HttpMessageBuilder.etag(): String?
/**
* Set If-None-Match header
* @param etag ETag value to set
*/
fun HttpMessageBuilder.ifNoneMatch(etag: String)
/**
* Set max age cache control
* @param seconds max age in seconds
*/
fun HttpMessageBuilder.maxAge(seconds: Int)
/**
* Set User-Agent header
* @param userAgent user agent string
*/
fun HttpMessageBuilder.userAgent(userAgent: String)Functions for working with Cache-Control headers and caching directives.
/**
* Get Cache-Control directives
* @return List of CacheControl instances
*/
fun HttpMessage.cacheControl(): List<CacheControl>
/**
* Get Vary header values
* @return List of header names that affect caching
*/
fun HttpMessage.vary(): List<String>
/**
* Get Vary header values from builder
* @return List of header names that affect caching
*/
fun HttpMessageBuilder.vary(): List<String>Functions for accessing cookies in HTTP messages.
/**
* Get Set-Cookie header values (response)
* @return List of Cookie instances from Set-Cookie headers
*/
fun HttpMessage.setCookie(): List<Cookie>
/**
* Get cookies from Cookie header (request)
* @return List of Cookie instances from Cookie header
*/
fun HttpMessageBuilder.cookies(): List<Cookie>JVM-specific functions using java.util.Date for date-related HTTP headers.
/**
* Get Date header value (JVM-specific)
* @return Date instance or null if not present
*/
fun HttpMessage.date(): Date?
/**
* Get Last-Modified header value (JVM-specific)
* @return Date instance or null if not present
*/
fun HttpMessage.lastModified(): Date?
/**
* Get Last-Modified header value from builder (JVM-specific)
* @return Date instance or null if not present
*/
fun HttpMessageBuilder.lastModified(): Date?
/**
* Get Expires header value (JVM-specific)
* @return Date instance or null if not present
*/
fun HttpMessage.expires(): Date?
/**
* Get Expires header value from builder (JVM-specific)
* @return Date instance or null if not present
*/
fun HttpMessageBuilder.expires(): Date?
/**
* Set If-Modified-Since header (JVM-specific)
* @param date date to set
*/
fun HttpMessageBuilder.ifModifiedSince(date: Date)Utility functions for common response properties.
/**
* Set ETag header in response
* @param value ETag value to set
*/
fun HeadersBuilder.etag(value: String)Usage Examples:
import io.ktor.http.*
import java.util.*
import java.nio.charset.Charset
// Working with HttpMessage (typically from request/response)
class ExampleHttpMessage(override val headers: Headers) : HttpMessage
val headers = headers {
append(HttpHeaders.ContentType, "application/json; charset=utf-8")
append(HttpHeaders.ContentLength, "1024")
append(HttpHeaders.ETag, "\"12345\"")
append(HttpHeaders.CacheControl, "max-age=3600, public")
append(HttpHeaders.LastModified, "Wed, 21 Oct 2015 07:28:00 GMT")
}
val message = ExampleHttpMessage(headers)
// Extract common properties
val contentType = message.contentType()
println("Content-Type: $contentType") // application/json
val contentLength = message.contentLength()
println("Content-Length: $contentLength") // 1024
val charset = message.charset()
println("Charset: $charset") // UTF-8
val etag = message.etag()
println("ETag: $etag") // "12345"
// JVM-specific date properties
val lastModified = message.lastModified()
println("Last-Modified: $lastModified") // Wed Oct 21 07:28:00 GMT 2015
val date = message.date() // null if not present
val expires = message.expires() // null if not present
// Cache control
val cacheDirectives = message.cacheControl()
cacheDirectives.forEach { directive ->
when (directive) {
is CacheControl.MaxAge -> println("Max-Age: ${directive.maxAgeSeconds}")
is CacheControl.NoCache -> println("No-Cache")
is CacheControl.NoStore -> println("No-Store")
}
}
// Working with HttpMessageBuilder (typically when building requests/responses)
class ExampleMessageBuilder(override val headers: HeadersBuilder) : HttpMessageBuilder
val builder = ExampleMessageBuilder(HeadersBuilder())
// Set properties using builder functions
builder.contentType(ContentType.Application.Json.withCharset(Charsets.UTF_8))
builder.userAgent("MyApp/1.0")
builder.maxAge(3600)
builder.ifNoneMatch("\"etag-value\"")
// JVM-specific date setting
val now = Date()
builder.ifModifiedSince(now)
// Access properties from builder
val builderContentType = builder.contentType()
val builderCharset = builder.charset()
// Cookie handling in messages
val cookieHeaders = headers {
append(HttpHeaders.SetCookie, "sessionId=abc123; HttpOnly; Secure")
append(HttpHeaders.SetCookie, "theme=dark; Path=/; Max-Age=86400")
}
val messageWithCookies = ExampleHttpMessage(cookieHeaders)
val cookies = messageWithCookies.setCookie()
cookies.forEach { cookie ->
println("Cookie: ${cookie.name}=${cookie.value}")
if (cookie.httpOnly) println(" HttpOnly")
if (cookie.secure) println(" Secure")
}
// Vary header handling
val varyHeaders = headers {
append(HttpHeaders.Vary, "Accept-Encoding, User-Agent")
}
val varyMessage = ExampleHttpMessage(varyHeaders)
val varyValues = varyMessage.vary()
println("Varies on: ${varyValues.joinToString()}") // Accept-Encoding, User-Agent
// Utility functions for response building
val responseHeaders = HeadersBuilder()
responseHeaders.etag("\"resource-version-123\"")
responseHeaders.append(HttpHeaders.CacheControl, "private, max-age=300")
// Common patterns for request processing
fun processRequest(request: HttpMessage): String {
val acceptedType = request.contentType()
val contentLength = request.contentLength()
val userCharset = request.charset()
return when {
acceptedType?.match(ContentType.Application.Json) == true -> "Processing JSON"
acceptedType?.match(ContentType.Application.FormUrlEncoded) == true -> "Processing form data"
contentLength != null && contentLength > 1_000_000 -> "Content too large"
else -> "Processing generic content"
}
}
// Common patterns for response building
fun buildCacheableResponse(builder: HttpMessageBuilder, content: String, etag: String) {
builder.contentType(ContentType.Text.Html.withCharset(Charsets.UTF_8))
builder.ifNoneMatch(etag)
builder.maxAge(3600) // 1 hour
// Set response headers
builder.headers.apply {
etag(etag)
append(HttpHeaders.Vary, "Accept-Encoding")
}
}
// Conditional request handling
fun handleConditionalRequest(request: HttpMessage, resourceETag: String, lastModified: Date): Boolean {
val requestETag = request.etag()
val ifModifiedSince = request.lastModified()
// Check if resource has been modified
val etagMatches = requestETag == resourceETag
val notModifiedSince = ifModifiedSince?.let { it >= lastModified } ?: false
return etagMatches || notModifiedSince
}
// Content negotiation
fun negotiateContentType(request: HttpMessage): ContentType {
val acceptHeader = request.headers[HttpHeaders.Accept]
return when {
acceptHeader?.contains("application/json") == true -> ContentType.Application.Json
acceptHeader?.contains("text/html") == true -> ContentType.Text.Html
acceptHeader?.contains("application/xml") == true -> ContentType.Application.Xml
else -> ContentType.Text.Plain
}
}All types are defined above in their respective capability sections.
Install with Tessl CLI
npx tessl i tessl/maven-io-ktor--ktor-http-jvm