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

cookies.mddocs/

Cookies

Complete cookie support including parsing Set-Cookie and Cookie headers, cookie encoding strategies, cookie attribute handling, and comprehensive cookie management utilities.

Cookie Class

Cookie Structure

data class Cookie(
    val name: String,
    val value: String,
    val encoding: CookieEncoding = CookieEncoding.URI_ENCODING,
    val maxAge: Int = 0,
    val expires: GMTDate? = null,
    val domain: String? = null,
    val path: String? = null,
    val secure: Boolean = false,
    val httpOnly: Boolean = false,
    val extensions: Map<String, String?> = emptyMap()
)

Cookie properties:

  • name: Cookie name (required)
  • value: Cookie value (required)
  • encoding: How the cookie value should be encoded
  • maxAge: Maximum age in seconds (0 = session cookie)
  • expires: Explicit expiration date (optional)
  • domain: Domain scope for the cookie
  • path: Path scope for the cookie
  • secure: Whether cookie should only be sent over HTTPS
  • httpOnly: Whether cookie should be inaccessible to JavaScript
  • extensions: Additional custom cookie attributes

Cookie Encoding Strategies

CookieEncoding Enum

enum class CookieEncoding {
    RAW,            // No encoding applied
    DQUOTES,        // Double-quote wrapping when needed
    URI_ENCODING,   // Percent-encoding (default)
    BASE64_ENCODING // Base64 encoding
}

Cookie Parsing Functions

Server-Side Cookie Parsing

fun parseServerSetCookieHeader(cookiesHeader: String): Cookie

Parses a single Set-Cookie header value into a Cookie object.

Client-Side Cookie Parsing

fun parseClientCookiesHeader(cookiesHeader: String): List<Cookie>

Parses a Cookie header value (multiple cookies) into a list of Cookie objects.

Cookie Rendering Functions

Set-Cookie Header Generation

fun renderSetCookieHeader(cookie: Cookie): String

Generates a Set-Cookie header value from a Cookie object.

Cookie Header Generation

fun renderCookieHeader(cookies: List<Cookie>): String

Generates a Cookie header value from a list of Cookie objects.

Cookie Value Encoding

Encoding and Decoding Functions

fun encodeCookieValue(value: String, encoding: CookieEncoding): String
fun decodeCookieValue(value: String, encoding: CookieEncoding): String

Manually encode and decode cookie values using specific encoding strategies.

Usage Examples

Basic Cookie Creation

// Simple session cookie
val sessionCookie = Cookie(
    name = "JSESSIONID",
    value = "ABC123DEF456"
)

// Persistent cookie with expiration
val rememberMeCookie = Cookie(
    name = "remember_token",
    value = "user123_token456",
    maxAge = 30 * 24 * 60 * 60, // 30 days
    secure = true,
    httpOnly = true
)

// Cookie with domain and path restrictions
val trackingCookie = Cookie(
    name = "tracking_id",
    value = "track_12345",
    domain = ".example.com",
    path = "/app",
    maxAge = 365 * 24 * 60 * 60 // 1 year
)

Cookie Encoding Examples

// Different encoding strategies
val rawCookie = Cookie(
    name = "raw_data",
    value = "simple_value",
    encoding = CookieEncoding.RAW
)

val quotedCookie = Cookie(
    name = "quoted_data", 
    value = "value with spaces",
    encoding = CookieEncoding.DQUOTES
)

val uriEncodedCookie = Cookie(
    name = "uri_data",
    value = "value/with/special&chars=here",
    encoding = CookieEncoding.URI_ENCODING
)

val base64Cookie = Cookie(
    name = "b64_data",
    value = "complex data with unicode: 🍪",
    encoding = CookieEncoding.BASE64_ENCODING
)

// Render as Set-Cookie headers
println(renderSetCookieHeader(rawCookie))
// raw_data=simple_value

println(renderSetCookieHeader(quotedCookie))
// quoted_data="value with spaces"

println(renderSetCookieHeader(uriEncodedCookie))
// uri_data=value%2Fwith%2Fspecial%26chars%3Dhere

println(renderSetCookieHeader(base64Cookie))
// b64_data=Y29tcGxleCBkYXRhIHdpdGggdW5pY29kZTogIPCfjYo=

Cookie Attributes

// Cookie with all security attributes
val secureCookie = Cookie(
    name = "secure_session",
    value = "encrypted_session_data",
    maxAge = 3600, // 1 hour
    domain = "secure.example.com",
    path = "/api",
    secure = true,
    httpOnly = true
)

// Cookie with custom extensions
val customCookie = Cookie(
    name = "custom_cookie",
    value = "data",
    extensions = mapOf(
        "SameSite" to "Strict",
        "Priority" to "High",
        "CustomAttribute" to null // attribute without value
    )
)

val customHeader = renderSetCookieHeader(customCookie)
println(customHeader)
// custom_cookie=data; SameSite=Strict; Priority=High; CustomAttribute

Parsing Set-Cookie Headers

// Parse various Set-Cookie header formats
val setCookieHeaders = listOf(
    "session_id=ABC123; Max-Age=3600; Path=/; Secure; HttpOnly",
    "preferences=theme:dark,lang:en; Domain=.example.com; Max-Age=2592000",
    "tracking=\"visitor_12345\"; Expires=Wed, 21 Oct 2024 07:28:00 GMT; Path=/",
    "minimal=value",
    "complex=data; Max-Age=86400; Domain=.site.com; Path=/app; Secure; HttpOnly; SameSite=Strict"
)

setCookieHeaders.forEach { header ->
    val cookie = parseServerSetCookieHeader(header)
    println("Parsed: ${cookie.name}=${cookie.value}")
    println("  Max-Age: ${cookie.maxAge}")
    println("  Domain: ${cookie.domain}")
    println("  Path: ${cookie.path}")
    println("  Secure: ${cookie.secure}")
    println("  HttpOnly: ${cookie.httpOnly}")
    println("  Extensions: ${cookie.extensions}")
    println()
}

Parsing Cookie Request Headers

// Parse Cookie header from client requests
val cookieHeaderValues = listOf(
    "session_id=ABC123; user_pref=theme:dark; tracking=visitor_12345",
    "single_cookie=value",
    "empty_value=; another=test",
    "complex=\"quoted value\"; simple=unquoted"
)

cookieHeaderValues.forEach { header ->
    val cookies = parseClientCookiesHeader(header)
    println("Parsed ${cookies.size} cookies from: $header")
    cookies.forEach { cookie ->
        println("  ${cookie.name} = ${cookie.value}")
    }
    println()
}

Cookie Management Utilities

// Helper functions for cookie management
class CookieManager {
    private val cookies = mutableMapOf<String, Cookie>()
    
    fun setCookie(cookie: Cookie) {
        cookies[cookie.name] = cookie
    }
    
    fun getCookie(name: String): Cookie? {
        return cookies[name]
    }
    
    fun removeCookie(name: String) {
        cookies.remove(name)
    }
    
    fun getAllCookies(): List<Cookie> {
        return cookies.values.toList()
    }
    
    fun clearExpiredCookies() {
        val now = System.currentTimeMillis()
        cookies.entries.removeAll { (_, cookie) ->
            cookie.expires?.let { expires ->
                expires.timestamp < now
            } ?: false
        }
    }
    
    fun generateCookieHeader(): String {
        return renderCookieHeader(getAllCookies())
    }
    
    fun generateSetCookieHeaders(): List<String> {
        return getAllCookies().map { renderSetCookieHeader(it) }
    }
}

// Usage
val manager = CookieManager()

manager.setCookie(Cookie("session", "ABC123", maxAge = 3600))
manager.setCookie(Cookie("theme", "dark", maxAge = 86400))
manager.setCookie(Cookie("lang", "en", maxAge = 86400))

val cookieHeader = manager.generateCookieHeader()
println("Cookie: $cookieHeader")
// Cookie: session=ABC123; theme=dark; lang=en

val setCookieHeaders = manager.generateSetCookieHeaders()
setCookieHeaders.forEach { header ->
    println("Set-Cookie: $header")
}

Advanced Cookie Patterns

// Cookie factory functions
object CookieFactory {
    fun createSessionCookie(name: String, value: String): Cookie {
        return Cookie(
            name = name,
            value = value,
            httpOnly = true,
            secure = true,
            encoding = CookieEncoding.URI_ENCODING
        )
    }
    
    fun createPersistentCookie(
        name: String, 
        value: String, 
        daysToExpire: Int
    ): Cookie {
        return Cookie(
            name = name,
            value = value,
            maxAge = daysToExpire * 24 * 60 * 60,
            httpOnly = true,
            secure = true,
            encoding = CookieEncoding.URI_ENCODING
        )
    }
    
    fun createTrackingCookie(
        trackingId: String,
        domain: String
    ): Cookie {
        return Cookie(
            name = "tracking_id",
            value = trackingId,
            domain = domain,
            path = "/",
            maxAge = 365 * 24 * 60 * 60, // 1 year
            secure = true,
            extensions = mapOf("SameSite" to "Lax")
        )
    }
    
    fun createDeleteCookie(name: String, domain: String? = null, path: String? = null): Cookie {
        return Cookie(
            name = name,
            value = "",
            maxAge = 0,
            expires = GMTDate(0), // Set to epoch
            domain = domain,
            path = path
        )
    }
}

// Usage examples
val sessionCookie = CookieFactory.createSessionCookie("PHPSESSID", "s3cr3t_s3ss10n")
val rememberCookie = CookieFactory.createPersistentCookie("remember_me", "user123", 30)
val trackingCookie = CookieFactory.createTrackingCookie("track_abc123", ".example.com")
val deleteCookie = CookieFactory.createDeleteCookie("old_session", ".example.com", "/")

Cookie Security Best Practices

// Security-focused cookie creation
fun createSecureCookie(
    name: String,
    value: String,
    maxAgeSeconds: Int = 3600,
    domain: String? = null,
    path: String = "/"
): Cookie {
    return Cookie(
        name = name,
        value = value,
        maxAge = maxAgeSeconds,
        domain = domain,
        path = path,
        secure = true,      // HTTPS only
        httpOnly = true,    // No JavaScript access
        encoding = CookieEncoding.URI_ENCODING,
        extensions = mapOf(
            "SameSite" to "Strict" // CSRF protection
        )
    )
}

// JWT cookie handling
fun createJwtCookie(token: String): Cookie {
    return createSecureCookie(
        name = "jwt_token",
        value = token,
        maxAgeSeconds = 15 * 60, // 15 minutes
        extensions = mapOf(
            "SameSite" to "Strict",
            "Priority" to "High"
        )
    )
}

// CSRF token cookie
fun createCsrfCookie(token: String): Cookie {
    return Cookie(
        name = "csrf_token",
        value = token,
        secure = true,
        httpOnly = false, // Accessible to JavaScript for CSRF headers
        maxAge = 3600,
        extensions = mapOf("SameSite" to "Strict")
    )
}

Cookie Value Encoding Examples

// Manual encoding/decoding
val originalValue = "user data with spaces & special chars = here"

// Try different encodings
val rawEncoded = encodeCookieValue(originalValue, CookieEncoding.RAW)
val uriEncoded = encodeCookieValue(originalValue, CookieEncoding.URI_ENCODING)  
val base64Encoded = encodeCookieValue(originalValue, CookieEncoding.BASE64_ENCODING)
val quotedEncoded = encodeCookieValue(originalValue, CookieEncoding.DQUOTES)

println("Original: $originalValue")
println("Raw: $rawEncoded")
println("URI: $uriEncoded")
println("Base64: $base64Encoded")
println("Quoted: $quotedEncoded")

// Decode back
val uriDecoded = decodeCookieValue(uriEncoded, CookieEncoding.URI_ENCODING)
val base64Decoded = decodeCookieValue(base64Encoded, CookieEncoding.BASE64_ENCODING)

println("URI decoded: $uriDecoded")
println("Base64 decoded: $base64Decoded")
println("Matches original: ${originalValue == uriDecoded}")

Error Handling

// Safe cookie parsing
fun parseCookieSafe(header: String): List<Cookie> {
    return try {
        parseClientCookiesHeader(header)
    } catch (e: Exception) {
        println("Failed to parse cookie header: ${e.message}")
        emptyList()
    }
}

fun parseSetCookieSafe(header: String): Cookie? {
    return try {
        parseServerSetCookieHeader(header)
    } catch (e: Exception) {
        println("Failed to parse Set-Cookie header: ${e.message}")
        null
    }
}

// Validate cookie values
fun isValidCookieName(name: String): Boolean {
    return name.isNotBlank() && !name.contains(Regex("[\\s,;=]"))
}

fun isValidCookieValue(value: String, encoding: CookieEncoding): Boolean {
    return try {
        val encoded = encodeCookieValue(value, encoding)
        val decoded = decodeCookieValue(encoded, encoding)
        decoded == value
    } catch (e: Exception) {
        false
    }
}

// Usage
val validName = isValidCookieName("session_id") // true
val invalidName = isValidCookieName("session id") // false (space)

val validValue = isValidCookieValue("simple_value", CookieEncoding.URI_ENCODING) // true
val complexValue = isValidCookieValue("value with unicode 🍪", CookieEncoding.BASE64_ENCODING) // true