or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

authentication.mdcontent-multipart.mdcontent-types.mdcookies.mdheaders-parameters.mdhttp-protocol.mdindex.mdurl-handling.md
tile.json

headers-parameters.mddocs/

Headers and Parameters

Type-safe HTTP header and parameter handling with case-insensitive access, validation, and comprehensive builder patterns for managing HTTP headers and URL query parameters.

StringValues Interface

Base interface for both headers and parameters providing common functionality for key-value collections.

interface StringValues {
    operator fun get(name: String): String?
    fun getAll(name: String): List<String>?
    fun names(): Set<String>
    fun isEmpty(): Boolean
    fun entries(): Set<Map.Entry<String, List<String>>>
    fun forEach(body: (String, List<String>) -> Unit)
    
    companion object {
        val Empty: StringValues
    }
}

HTTP Headers

Headers Interface

interface Headers : StringValues {
    operator fun get(name: String): String?
    fun getAll(name: String): List<String>?
    fun contains(name: String): Boolean
    fun contains(name: String, value: String): Boolean
    
    companion object {
        val Empty: Headers
    }
}

Headers Construction

// Factory functions
fun headersOf(): Headers
fun headersOf(vararg pairs: Pair<String, String>): Headers
fun headersOf(vararg pairs: Pair<String, List<String>>): Headers
fun headersOf(map: Map<String, String>): Headers
fun headersOf(map: Map<String, List<String>>): Headers

// Builder DSL
fun headers(builder: HeadersBuilder.() -> Unit): Headers

HeadersBuilder Class

class HeadersBuilder : StringValuesBuilder {
    fun append(name: String, value: String)
    fun append(name: String, values: List<String>)
    fun appendAll(stringValues: StringValues)
    fun appendAll(other: Headers)
    fun appendMissing(stringValues: StringValues)
    fun appendMissing(other: Headers)
    fun set(name: String, value: String)
    fun set(name: String, values: List<String>)
    fun remove(name: String): List<String>
    fun removeKeysWithNoEntries()
    fun clear()
    fun build(): Headers
}

Standard HTTP Headers

object HttpHeaders {
    // Request Headers
    const val Accept: String = "Accept"
    const val AcceptCharset: String = "Accept-Charset"
    const val AcceptEncoding: String = "Accept-Encoding"
    const val AcceptLanguage: String = "Accept-Language"
    const val AcceptRanges: String = "Accept-Ranges"
    const val Authorization: String = "Authorization"
    const val CacheControl: String = "Cache-Control"
    const val Connection: String = "Connection"
    const val ContentEncoding: String = "Content-Encoding"
    const val ContentLength: String = "Content-Length"
    const val ContentType: String = "Content-Type"
    const val Cookie: String = "Cookie"
    const val Host: String = "Host"
    const val IfMatch: String = "If-Match"
    const val IfModifiedSince: String = "If-Modified-Since"
    const val IfNoneMatch: String = "If-None-Match"
    const val IfRange: String = "If-Range"
    const val IfUnmodifiedSince: String = "If-Unmodified-Since"
    const val Origin: String = "Origin"
    const val Range: String = "Range"
    const val Referer: String = "Referer"
    const val UserAgent: String = "User-Agent"
    
    // Response Headers
    const val AcceptPatch: String = "Accept-Patch"
    const val AccessControlAllowCredentials: String = "Access-Control-Allow-Credentials"
    const val AccessControlAllowHeaders: String = "Access-Control-Allow-Headers"
    const val AccessControlAllowMethods: String = "Access-Control-Allow-Methods"
    const val AccessControlAllowOrigin: String = "Access-Control-Allow-Origin"
    const val AccessControlExposeHeaders: String = "Access-Control-Expose-Headers"
    const val AccessControlMaxAge: String = "Access-Control-Max-Age"
    const val Age: String = "Age"
    const val Allow: String = "Allow"
    const val ContentDisposition: String = "Content-Disposition"
    const val ContentRange: String = "Content-Range"
    const val ETag: String = "ETag"
    const val Expires: String = "Expires"
    const val LastModified: String = "Last-Modified"
    const val Link: String = "Link"
    const val Location: String = "Location"
    const val Server: String = "Server"
    const val SetCookie: String = "Set-Cookie"
    const val Vary: String = "Vary"
    const val WWWAuthenticate: String = "WWW-Authenticate"
    
    // Header validation
    fun isUnsafe(header: String): Boolean
    fun checkHeaderName(name: String)
    fun checkHeaderValue(value: String)
    val UnsafeHeadersList: List<String>
}

URL Parameters

Parameters Interface

interface Parameters : StringValues {
    operator fun get(name: String): String?
    fun getAll(name: String): List<String>?
    
    companion object {
        val Empty: Parameters
    }
}

Parameters Construction

// Factory functions
fun parametersOf(): Parameters
fun parametersOf(vararg pairs: Pair<String, String>): Parameters
fun parametersOf(vararg pairs: Pair<String, List<String>>): Parameters
fun parametersOf(map: Map<String, String>): Parameters
fun parametersOf(map: Map<String, List<String>>): Parameters

// Builder DSL
fun parameters(builder: ParametersBuilder.() -> Unit): Parameters

ParametersBuilder Class

interface ParametersBuilder : StringValuesBuilder {
    fun append(name: String, value: String)
    fun append(name: String, values: List<String>)
    fun appendAll(stringValues: StringValues)
    fun appendAll(other: Parameters)
    fun appendMissing(stringValues: StringValues)
    fun appendMissing(other: Parameters)
    fun set(name: String, value: String)
    fun set(name: String, values: List<String>)
    fun remove(name: String): List<String>
    fun removeKeysWithNoEntries()
    fun clear()
    fun build(): Parameters
}

URL-Encoded Parameters

class UrlDecodedParametersBuilder : ParametersBuilder {
    constructor(capacity: Int = 8)
    
    // Specialized for URL-encoded form data
    fun appendAll(encodedQueryString: String)
    fun appendAll(encodedQueryString: String, decode: Boolean)
}

fun parseQueryString(query: String, decode: Boolean = true): Parameters

Usage Examples

Working with Headers

// Create headers using factory functions
val simpleHeaders = headersOf(
    "Content-Type" to "application/json",
    "User-Agent" to "MyApp/1.0"
)

// Create headers with multiple values
val complexHeaders = headersOf(
    "Accept" to listOf("application/json", "application/xml"),
    "Cache-Control" to listOf("no-cache", "no-store")
)

// Using headers builder
val builtHeaders = headers {
    append(HttpHeaders.ContentType, "text/html")
    append(HttpHeaders.ContentLength, "1234")
    append(HttpHeaders.CacheControl, "max-age=3600")
    append(HttpHeaders.CacheControl, "public") // Multiple values
}

// Accessing header values
val contentType = headers[HttpHeaders.ContentType]
val allCacheControls = headers.getAll(HttpHeaders.CacheControl)
val hasContentLength = headers.contains(HttpHeaders.ContentLength)

Headers Builder Operations

val builder = HeadersBuilder()

// Adding headers
builder.append("X-Custom-Header", "value1")
builder.append("X-Custom-Header", "value2") // Multiple values
builder.set("Content-Type", "application/json") // Replace existing

// Adding from other sources
val existingHeaders = headersOf("Authorization" to "Bearer token123")
builder.appendAll(existingHeaders)

// Conditional adding
builder.appendMissing(headersOf("User-Agent" to "DefaultAgent"))

// Removing headers
builder.remove("X-Debug-Header")
builder.removeKeysWithNoEntries()

val finalHeaders = builder.build()

Working with Parameters

// Create parameters
val queryParams = parametersOf(
    "page" to "1",
    "limit" to "10",
    "sort" to listOf("name", "date")
)

// Using parameters builder
val searchParams = parameters {
    append("q", "kotlin")
    append("type", "library")
    append("category", "web")
    append("category", "mobile") // Multiple categories
}

// Accessing parameter values
val page = queryParams["page"]
val categories = queryParams.getAll("category")
val isEmpty = queryParams.isEmpty()

// URL-encoded parameters from query string
val parsedParams = parseQueryString("q=kotlin%20http&page=1&sort=name&sort=date")
println(parsedParams["q"]) // "kotlin http"
println(parsedParams.getAll("sort")) // ["name", "date"]

URL-Encoded Parameters Builder

val urlBuilder = UrlDecodedParametersBuilder()

// Parse from query string
urlBuilder.appendAll("name=John%20Doe&age=25&skills=kotlin&skills=android")

// Add additional parameters
urlBuilder.append("location", "Remote")
urlBuilder.set("verified", "true")

val parameters = urlBuilder.build()
println(parameters["name"]) // "John Doe"
println(parameters.getAll("skills")) // ["kotlin", "android"]

Iterating Over Collections

// Iterate over headers
headers.forEach { name, values ->
    println("$name: ${values.joinToString(", ")}")
}

// Get all header names
val headerNames = headers.names()
println("Headers present: $headerNames")

// Get all entries
val headerEntries = headers.entries()
headerEntries.forEach { (name, values) ->
    values.forEach { value ->
        println("$name: $value")
    }
}

// Same operations work for parameters
parameters.forEach { name, values ->
    println("Parameter $name: ${values.joinToString(", ")}")
}

Header Validation

// Check for unsafe headers
val headerName = "Host"
if (HttpHeaders.isUnsafe(headerName)) {
    println("$headerName is considered unsafe")
}

// Validate header names and values
try {
    HttpHeaders.checkHeaderName("Invalid Header Name!") // Throws exception
} catch (e: IllegalHeaderNameException) {
    println("Invalid header name: ${e.message}")
}

try {
    HttpHeaders.checkHeaderValue("Header value with\r\n injection") // Throws exception
} catch (e: IllegalHeaderValueException) {
    println("Invalid header value: ${e.message}")
}

// Get list of unsafe headers
val unsafeHeaders = HttpHeaders.UnsafeHeadersList
println("Unsafe headers: $unsafeHeaders")

Advanced Usage Patterns

// Merging headers from multiple sources
fun mergeHeaders(vararg headerSets: Headers): Headers {
    return headers {
        headerSets.forEach { headerSet ->
            appendAll(headerSet)
        }
    }
}

// Filtering headers
fun filterHeaders(headers: Headers, predicate: (String) -> Boolean): Headers {
    return headers {
        headers.entries().forEach { (name, values) ->
            if (predicate(name)) {
                values.forEach { value ->
                    append(name, value)
                }
            }
        }
    }
}

// Converting parameters to query string
fun parametersToQueryString(parameters: Parameters): String {
    return parameters.entries().joinToString("&") { (name, values) ->
        values.joinToString("&") { value ->
            "${name.encodeURLQueryComponent()}=${value.encodeURLQueryComponent()}"
        }
    }
}

// Usage examples
val corsHeaders = headersOf(
    HttpHeaders.AccessControlAllowOrigin to "*",
    HttpHeaders.AccessControlAllowMethods to "GET, POST, PUT, DELETE"
)

val authHeaders = headersOf(
    HttpHeaders.Authorization to "Bearer token123",
    HttpHeaders.UserAgent to "MyApp/2.0"
)

val combinedHeaders = mergeHeaders(corsHeaders, authHeaders)
val publicHeaders = filterHeaders(combinedHeaders) { name ->
    !name.equals(HttpHeaders.Authorization, ignoreCase = true)
}