CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-io-ktor--ktor-client-core

Ktor HTTP Client Core - a multiplatform asynchronous HTTP client library for Kotlin providing comprehensive HTTP request/response handling with plugin architecture.

Pending
Overview
Eval results
Files

cookie-management.mddocs/

Cookie Management

HTTP cookie handling with multiple storage implementations, automatic cookie management, and comprehensive cookie processing capabilities.

Capabilities

Cookie Plugin Installation

Install and configure the HttpCookies plugin for automatic cookie management.

/**
 * HTTP Cookies plugin for automatic cookie handling
 */
object HttpCookies : HttpClientPlugin<HttpCookiesConfig, HttpCookiesConfig> {
    override val key: AttributeKey<HttpCookiesConfig>
    
    /**
     * Cookies configuration
     */
    class HttpCookiesConfig {
        /** Cookie storage implementation */
        var storage: CookiesStorage = AcceptAllCookiesStorage()
    }
}

Usage Examples:

val client = HttpClient {
    install(HttpCookies) {
        // Use default storage (accepts all cookies)
        storage = AcceptAllCookiesStorage()
    }
}

// Client will now automatically handle cookies
val response = client.get("https://example.com/login") {
    // Cookies from previous requests are automatically included
}

// Set-Cookie headers in responses are automatically processed and stored
val loginResponse = client.post("https://example.com/login") {
    setBody(FormDataContent(Parameters.build {
        append("username", "user")
        append("password", "pass")
    }))
}

// Session cookies are automatically included in subsequent requests
val profileResponse = client.get("https://example.com/profile")

Cookie Storage Interface

Core interface for cookie storage implementations.

/**
 * Cookie storage interface for managing HTTP cookies
 */
interface CookiesStorage {
    /**
     * Get cookies for a specific URL
     * @param requestUrl Target URL
     * @returns List of applicable cookies
     */
    suspend fun get(requestUrl: Url): List<Cookie>
    
    /**
     * Add a cookie from a response
     * @param requestUrl Original request URL
     * @param cookie Cookie to store
     */
    suspend fun addCookie(requestUrl: Url, cookie: Cookie)
    
    /**
     * Remove all cookies
     */
    suspend fun close(): Unit = Unit
}

Built-in Storage Implementations

Ready-to-use cookie storage implementations for different use cases.

/**
 * Storage that accepts and stores all cookies
 */
class AcceptAllCookiesStorage : CookiesStorage {
    override suspend fun get(requestUrl: Url): List<Cookie>
    override suspend fun addCookie(requestUrl: Url, cookie: Cookie)
    override suspend fun close()
}

/**
 * Storage with predefined constant cookies
 */
class ConstantCookiesStorage(
    private val cookies: List<Cookie>
) : CookiesStorage {
    override suspend fun get(requestUrl: Url): List<Cookie>
    override suspend fun addCookie(requestUrl: Url, cookie: Cookie)
}

/**
 * Memory-based cookie storage with size limits
 */
class MemoryCookiesStorage(
    private val maxCookies: Int = 1000
) : CookiesStorage {
    override suspend fun get(requestUrl: Url): List<Cookie>
    override suspend fun addCookie(requestUrl: Url, cookie: Cookie)
    override suspend fun close()
}

Usage Examples:

// Accept all cookies (default)
val clientAcceptAll = HttpClient {
    install(HttpCookies) {
        storage = AcceptAllCookiesStorage()
    }
}

// Use constant predefined cookies
val constantCookies = listOf(
    Cookie("api_key", "abc123", domain = "api.example.com"),
    Cookie("client_id", "mobile_app", domain = "api.example.com")
)

val clientConstant = HttpClient {
    install(HttpCookies) {
        storage = ConstantCookiesStorage(constantCookies)
    }
}

// Memory storage with size limit
val clientMemory = HttpClient {
    install(HttpCookies) {
        storage = MemoryCookiesStorage(maxCookies = 500)
    }
}

Cookie Access Functions

Functions for accessing and managing cookies programmatically.

/**
 * Get cookies for a specific URL
 * @param urlString Target URL
 * @returns List of cookies applicable to the URL
 */
suspend fun HttpClient.cookies(urlString: String): List<Cookie>

/**
 * Get cookies for a specific URL object
 * @param url Target URL
 * @returns List of cookies applicable to the URL
 */
suspend fun HttpClient.cookies(url: Url): List<Cookie>

/**
 * Add a cookie manually
 * @param urlString URL to associate the cookie with
 * @param cookie Cookie to add
 */
suspend fun HttpClient.addCookie(urlString: String, cookie: Cookie)

/**
 * Clear all cookies from storage
 */
suspend fun HttpClient.clearCookies()

Usage Examples:

val client = HttpClient {
    install(HttpCookies)
}

// Make initial request that sets cookies
client.get("https://example.com/login")

// Get cookies for a URL
val cookies = client.cookies("https://example.com")
cookies.forEach { cookie ->
    println("Cookie: ${cookie.name}=${cookie.value}")
    println("Domain: ${cookie.domain}")
    println("Path: ${cookie.path}")
    println("Expires: ${cookie.expires}")
    println("HttpOnly: ${cookie.httpOnly}")
    println("Secure: ${cookie.secure}")
    println("---")
}

// Add cookie manually
val customCookie = Cookie(
    name = "custom_setting",
    value = "enabled",
    domain = "example.com",
    path = "/",
    httpOnly = false,
    secure = true
)
client.addCookie("https://example.com", customCookie)

// Clear all cookies
client.clearCookies()

Cookie Data Class

Comprehensive cookie representation with all standard cookie attributes.

/**
 * HTTP cookie representation
 */
data class Cookie(
    /** Cookie name */
    val name: String,
    
    /** Cookie value */
    val value: String,
    
    /** Cookie encoding (default: UTF-8) */
    val encoding: CookieEncoding = CookieEncoding.URI_ENCODING,
    
    /** Maximum age in seconds */
    val maxAge: Int = 0,
    
    /** Expiration date */
    val expires: GMTDate? = null,
    
    /** Domain scope */
    val domain: String? = null,
    
    /** Path scope */
    val path: String? = null,
    
    /** Secure flag (HTTPS only) */
    val secure: Boolean = false,
    
    /** HttpOnly flag (no JavaScript access) */
    val httpOnly: Boolean = false,
    
    /** SameSite attribute */
    val sameSite: SameSite? = null,
    
    /** Additional cookie extensions */
    val extensions: Map<String, String?> = emptyMap()
) {
    companion object {
        /**
         * Parse cookie from Set-Cookie header value
         * @param cookieHeader Set-Cookie header value
         * @returns Parsed Cookie object
         */
        fun parse(cookieHeader: String): Cookie
        
        /**
         * Create session cookie (no expiration)
         * @param name Cookie name
         * @param value Cookie value
         * @param domain Optional domain
         * @param path Optional path
         * @returns Session cookie
         */
        fun session(name: String, value: String, domain: String? = null, path: String? = null): Cookie
        
        /**
         * Create secure cookie with common security settings
         * @param name Cookie name
         * @param value Cookie value
         * @param domain Cookie domain
         * @returns Secure cookie with HttpOnly and Secure flags
         */
        fun secure(name: String, value: String, domain: String): Cookie
    }
}

/**
 * Cookie encoding options
 */
enum class CookieEncoding {
    /** URI encoding */
    URI_ENCODING,
    
    /** Base64 encoding */
    BASE64_ENCODING,
    
    /** DQuotes encoding */
    DQUOTES,
    
    /** Raw encoding (no encoding) */
    RAW
}

/**
 * SameSite cookie attribute
 */
enum class SameSite {
    /** Strict SameSite policy */
    Strict,
    
    /** Lax SameSite policy */
    Lax,
    
    /** None SameSite policy (requires Secure) */
    None
}

Usage Examples:

// Create various types of cookies
val sessionCookie = Cookie.session("session_id", "abc123", domain = "example.com")

val securityCookie = Cookie.secure("csrf_token", "xyz789", "example.com")

val customCookie = Cookie(
    name = "preferences",
    value = "theme=dark&lang=en",
    domain = "example.com",
    path = "/",
    maxAge = 3600, // 1 hour
    secure = true,
    httpOnly = false,
    sameSite = SameSite.Lax,
    extensions = mapOf("Priority" to "High")
)

// Parse cookie from header
val headerValue = "sessionid=abc123; Path=/; Domain=.example.com; Secure; HttpOnly"
val parsedCookie = Cookie.parse(headerValue)

// Use cookies with client
val client = HttpClient {
    install(HttpCookies)
}

client.addCookie("https://example.com", sessionCookie)
client.addCookie("https://example.com", securityCookie)
client.addCookie("https://example.com", customCookie)

Custom Cookie Storage

Create custom cookie storage implementations for specific requirements.

/**
 * Example: File-based cookie storage
 */
class FileCookiesStorage(
    private val file: File
) : CookiesStorage {
    private val cookies = mutableListOf<Cookie>()
    
    init {
        loadCookiesFromFile()
    }
    
    override suspend fun get(requestUrl: Url): List<Cookie> {
        return cookies.filter { cookie ->
            cookieMatchesUrl(cookie, requestUrl)
        }
    }
    
    override suspend fun addCookie(requestUrl: Url, cookie: Cookie) {
        // Remove existing cookie with same name and domain
        cookies.removeAll { it.name == cookie.name && it.domain == cookie.domain }
        
        // Add new cookie if not expired
        if (!isCookieExpired(cookie)) {
            cookies.add(cookie)
            saveCookiesToFile()
        }
    }
    
    override suspend fun close() {
        saveCookiesToFile()
    }
    
    private fun loadCookiesFromFile() {
        // Implementation for loading cookies from file
    }
    
    private fun saveCookiesToFile() {
        // Implementation for saving cookies to file
    }
    
    private fun cookieMatchesUrl(cookie: Cookie, url: Url): Boolean {
        // Implementation for matching cookie to URL
        return true
    }
    
    private fun isCookieExpired(cookie: Cookie): Boolean {
        // Implementation for checking cookie expiration
        return false
    }
}

/**
 * Example: Database-backed cookie storage
 */
class DatabaseCookiesStorage(
    private val database: Database
) : CookiesStorage {
    override suspend fun get(requestUrl: Url): List<Cookie> {
        // Query database for cookies matching URL
        return database.queryCookies(requestUrl)
    }
    
    override suspend fun addCookie(requestUrl: Url, cookie: Cookie) {
        // Store cookie in database
        database.storeCookie(requestUrl, cookie)
    }
    
    override suspend fun close() {
        database.close()
    }
}

Usage Examples:

// Use file-based storage
val fileStorage = FileCookiesStorage(File("cookies.json"))
val clientFile = HttpClient {
    install(HttpCookies) {
        storage = fileStorage
    }
}

// Use database storage
val dbStorage = DatabaseCookiesStorage(createDatabase())
val clientDb = HttpClient {
    install(HttpCookies) {
        storage = dbStorage
    }
}

// Custom storage with filtering
class FilteredCookiesStorage(
    private val delegate: CookiesStorage,
    private val allowedDomains: Set<String>
) : CookiesStorage {
    override suspend fun get(requestUrl: Url): List<Cookie> {
        return delegate.get(requestUrl).filter { cookie ->
            cookie.domain in allowedDomains
        }
    }
    
    override suspend fun addCookie(requestUrl: Url, cookie: Cookie) {
        if (cookie.domain in allowedDomains) {
            delegate.addCookie(requestUrl, cookie)
        }
    }
    
    override suspend fun close() {
        delegate.close()
    }
}

val filteredStorage = FilteredCookiesStorage(
    AcceptAllCookiesStorage(),
    setOf("example.com", "api.example.com")
)

val clientFiltered = HttpClient {
    install(HttpCookies) {
        storage = filteredStorage
    }
}

Cookie Debugging and Inspection

Utilities for debugging and inspecting cookie behavior.

/**
 * Cookie debugging utilities
 */
object CookieDebugUtils {
    /**
     * Print all cookies for a URL
     * @param client HttpClient instance
     * @param url Target URL
     */
    suspend fun printCookies(client: HttpClient, url: String) {
        val cookies = client.cookies(url)
        println("Cookies for $url:")
        cookies.forEach { cookie ->
            println("  ${cookie.name}=${cookie.value} (domain=${cookie.domain}, path=${cookie.path})")
        }
    }
    
    /**
     * Validate cookie attributes
     * @param cookie Cookie to validate
     * @returns List of validation issues
     */
    fun validateCookie(cookie: Cookie): List<String> {
        val issues = mutableListOf<String>()
        
        if (cookie.name.isBlank()) {
            issues.add("Cookie name cannot be blank")
        }
        
        if (cookie.secure && cookie.sameSite == SameSite.None) {
            issues.add("SameSite=None requires Secure flag")
        }
        
        return issues
    }
}

Usage Examples:

val client = HttpClient {
    install(HttpCookies)
}

// Make some requests to accumulate cookies
client.get("https://example.com")
client.post("https://example.com/login") { /* login data */ }

// Debug cookies
CookieDebugUtils.printCookies(client, "https://example.com")

// Validate a cookie
val cookie = Cookie(
    name = "test",
    value = "value",
    secure = false,
    sameSite = SameSite.None
)

val issues = CookieDebugUtils.validateCookie(cookie)
if (issues.isNotEmpty()) {
    println("Cookie validation issues:")
    issues.forEach { println("  - $it") }
}

Types

Cookie Types

/**
 * GMT date for cookie expiration
 */
data class GMTDate(
    val timestamp: Long,
    val seconds: Int,
    val minutes: Int,
    val hours: Int,
    val dayOfMonth: Int,
    val month: Month,
    val year: Int,
    val dayOfWeek: DayOfWeek,
    val dayOfYear: Int
) {
    companion object {
        fun now(): GMTDate
        fun parse(dateString: String): GMTDate
        fun fromTimestamp(timestamp: Long): GMTDate
    }
    
    fun toEpochMilliseconds(): Long
    fun plus(duration: Duration): GMTDate
    fun minus(duration: Duration): GMTDate
}

/**
 * URL representation for cookie matching
 */
interface Url {
    val protocol: URLProtocol
    val host: String
    val port: Int
    val pathSegments: List<String>
    val parameters: Parameters
    val fragment: String
    val user: String?
    val password: String?
    
    fun buildString(): String
}

/**
 * URL protocol enumeration
 */
data class URLProtocol(
    val name: String,
    val defaultPort: Int
) {
    companion object {
        val HTTP: URLProtocol
        val HTTPS: URLProtocol
        val WS: URLProtocol
        val WSS: URLProtocol
    }
}

Install with Tessl CLI

npx tessl i tessl/maven-io-ktor--ktor-client-core

docs

client-configuration.md

cookie-management.md

forms-and-uploads.md

http-caching.md

http-requests.md

index.md

plugin-system.md

response-handling.md

server-sent-events.md

websockets.md

tile.json