CtrlK
BlogDocsLog inGet started
Tessl Logo

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

Ktor HTTP Client Core for tvOS ARM64 - multiplatform asynchronous HTTP client library with coroutines support

Pending
Overview
Eval results
Files

cookies.mddocs/

Cookies Support

The Ktor HTTP Client Core provides comprehensive cookie management functionality through the HttpCookies plugin. This allows automatic handling of HTTP cookies across requests with configurable storage backends and support for custom cookie storage implementations.

Core Cookie API

HttpCookies Plugin

The main plugin for cookie management that automatically handles cookie storage and retrieval.

object HttpCookies : HttpClientPlugin<HttpCookies.Config, HttpCookies> {
    class Config {
        var storage: CookiesStorage = AcceptAllCookiesStorage()
        
        fun default()
        fun storage(storage: CookiesStorage)
    }
}

CookiesStorage Interface

Base interface for implementing custom cookie storage backends.

interface CookiesStorage {
    suspend fun get(requestUrl: Url): List<Cookie>
    suspend fun addCookie(requestUrl: Url, cookie: Cookie)
    fun close()
}

Built-in Storage Implementations

AcceptAllCookiesStorage

Default storage implementation that accepts and stores all cookies with in-memory storage.

class AcceptAllCookiesStorage : CookiesStorage {
    override suspend fun get(requestUrl: Url): List<Cookie>
    override suspend fun addCookie(requestUrl: Url, cookie: Cookie)
    override fun close()
}

ConstantCookiesStorage

Read-only storage implementation that provides a fixed set of cookies for all requests.

class ConstantCookiesStorage(
    private val cookies: List<Cookie>
) : CookiesStorage {
    constructor(vararg cookies: Cookie)
    
    override suspend fun get(requestUrl: Url): List<Cookie>
    override suspend fun addCookie(requestUrl: Url, cookie: Cookie)
    override fun close()
}

Cookie Data Types

Cookie Class

Represents an HTTP cookie with all its attributes.

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()
) {
    fun copy(
        name: String = this.name,
        value: String = this.value,
        encoding: CookieEncoding = this.encoding,
        maxAge: Int = this.maxAge,
        expires: GMTDate? = this.expires,
        domain: String? = this.domain,
        path: String? = this.path,
        secure: Boolean = this.secure,
        httpOnly: Boolean = this.httpOnly,
        extensions: Map<String, String?> = this.extensions
    ): Cookie
}

enum class CookieEncoding {
    URI_ENCODING,
    DQUOTES,
    RAW
}

Basic Usage

Simple Cookie Handling

val client = HttpClient {
    install(HttpCookies)
}

// First request - server sets cookies
val loginResponse = client.post("https://example.com/login") {
    setBody("username=john&password=secret")
    contentType(ContentType.Application.FormUrlEncoded)
}

// Subsequent requests automatically include cookies
val profileResponse = client.get("https://example.com/profile")
// Cookies from login are automatically sent

client.close()

Custom Storage Configuration

val client = HttpClient {
    install(HttpCookies) {
        storage = AcceptAllCookiesStorage()
    }
}

// Or with constant cookies
val client2 = HttpClient {
    install(HttpCookies) {
        storage = ConstantCookiesStorage(
            Cookie("session_id", "abc123"),
            Cookie("user_pref", "dark_mode")
        )
    }
}

Manual Cookie Management

val cookieStorage = AcceptAllCookiesStorage()

val client = HttpClient {
    install(HttpCookies) {
        storage = cookieStorage
    }
}

// Add cookies manually
cookieStorage.addCookie(
    Url("https://example.com"),
    Cookie(
        name = "auth_token",
        value = "bearer_xyz789",
        domain = "example.com",
        path = "/api",
        secure = true,
        httpOnly = true,
        maxAge = 3600 // 1 hour
    )
)

// Cookies will be included in matching requests
val response = client.get("https://example.com/api/data")

Advanced Cookie Features

Cookie Attributes

val secureCookie = Cookie(
    name = "secure_session",
    value = "encrypted_data",
    domain = ".example.com",        // Available to all subdomains
    path = "/secure",               // Only for /secure paths
    secure = true,                  // HTTPS only
    httpOnly = true,                // No JavaScript access
    maxAge = 7200,                  // 2 hours lifetime
    extensions = mapOf(
        "SameSite" to "Strict"      // CSRF protection
    )
)

Domain and Path Matching

Cookies are automatically filtered based on domain and path matching rules:

val client = HttpClient {
    install(HttpCookies) {
        storage = AcceptAllCookiesStorage()
    }
}

// Set cookies with different scopes
client.get("https://api.example.com/login") // May set cookies for .example.com
client.get("https://app.example.com/dashboard") // Gets cookies for .example.com
client.get("https://other.com/data") // No cookies from example.com

Cookie Encoding

val encodedCookie = Cookie(
    name = "special_chars",
    value = "hello world & more!",
    encoding = CookieEncoding.URI_ENCODING // URL-encodes special characters
)

val quotedCookie = Cookie(
    name = "quoted_value",
    value = "contains spaces",
    encoding = CookieEncoding.DQUOTES // Wraps in double quotes
)

val rawCookie = Cookie(
    name = "raw_value", 
    value = "no-encoding-needed",
    encoding = CookieEncoding.RAW // No encoding applied
)

Custom Storage Implementation

Thread-Safe Cookie Storage

class ThreadSafeCookieStorage : CookiesStorage {
    private val cookies = mutableMapOf<String, MutableList<Cookie>>()
    private val mutex = Mutex()
    
    override suspend fun get(requestUrl: Url): List<Cookie> = mutex.withLock {
        val host = requestUrl.host
        return cookies[host]?.filter { cookie ->
            // Apply domain and path matching logic
            matchesDomain(cookie.domain, host) && 
            matchesPath(cookie.path, requestUrl.encodedPath)
        } ?: emptyList()
    }
    
    override suspend fun addCookie(requestUrl: Url, cookie: Cookie) = mutex.withLock {
        val host = requestUrl.host
        cookies.getOrPut(host) { mutableListOf() }.add(cookie)
    }
    
    override fun close() {
        // Cleanup resources
    }
    
    private fun matchesDomain(cookieDomain: String?, requestHost: String): Boolean {
        // Implement domain matching rules
        return cookieDomain == null || requestHost.endsWith(cookieDomain)
    }
    
    private fun matchesPath(cookiePath: String?, requestPath: String): Boolean {
        // Implement path matching rules  
        return cookiePath == null || requestPath.startsWith(cookiePath)
    }
}

Persistent Cookie Storage

class FileCookieStorage(private val file: File) : CookiesStorage {
    private val cookies = mutableMapOf<String, MutableList<Cookie>>()
    
    init {
        loadCookies()
    }
    
    override suspend fun get(requestUrl: Url): List<Cookie> {
        return cookies[requestUrl.host] ?: emptyList()
    }
    
    override suspend fun addCookie(requestUrl: Url, cookie: Cookie) {
        cookies.getOrPut(requestUrl.host) { mutableListOf() }.add(cookie)
        saveCookies()
    }
    
    override fun close() {
        saveCookies()
    }
    
    private fun loadCookies() {
        if (file.exists()) {
            // Load cookies from file (implementation dependent)
        }
    }
    
    private fun saveCookies() {
        // Save cookies to file (implementation dependent)
    }
}

Cookie Security

Secure Cookie Practices

val client = HttpClient {
    install(HttpCookies) {
        storage = AcceptAllCookiesStorage()
    }
}

// Always use secure cookies for sensitive data
val secureCookie = Cookie(
    name = "auth_session",
    value = "encrypted_token",
    secure = true,      // Only send over HTTPS
    httpOnly = true,    // Prevent XSS attacks
    extensions = mapOf(
        "SameSite" to "Strict"  // Prevent CSRF attacks
    )
)

Cookie Filtering

class FilteringCookieStorage(
    private val delegate: CookiesStorage,
    private val allowedDomains: Set<String>
) : CookiesStorage {
    
    override suspend fun get(requestUrl: Url): List<Cookie> {
        return if (requestUrl.host in allowedDomains) {
            delegate.get(requestUrl)
        } else {
            emptyList()
        }
    }
    
    override suspend fun addCookie(requestUrl: Url, cookie: Cookie) {
        if (requestUrl.host in allowedDomains) {
            delegate.addCookie(requestUrl, cookie)
        }
    }
    
    override fun close() = delegate.close()
}

val client = HttpClient {
    install(HttpCookies) {
        storage = FilteringCookieStorage(
            AcceptAllCookiesStorage(),
            setOf("api.example.com", "secure.example.com")
        )
    }
}

Cookie Inspection and Debugging

Accessing Cookie Storage

val cookieStorage = AcceptAllCookiesStorage()

val client = HttpClient {
    install(HttpCookies) {
        storage = cookieStorage
    }
}

// Make requests that set cookies
client.get("https://example.com/login")

// Inspect stored cookies
val storedCookies = cookieStorage.get(Url("https://example.com"))
println("Stored cookies: ${storedCookies.joinToString { "${it.name}=${it.value}" }}")

Request Cookie Inspection

val client = HttpClient {
    install(HttpCookies)
    
    install(HttpSend) {
        intercept { request ->
            // Log cookies being sent
            val cookieHeader = request.headers["Cookie"]
            println("Sending cookies: $cookieHeader")
            
            execute(request)
        }
    }
}

Best Practices

  1. Use secure cookies: Always set secure and httpOnly flags for sensitive cookies
  2. Implement proper storage: Use persistent storage for long-lived applications
  3. Handle cookie expiration: Check and clean up expired cookies regularly
  4. Domain validation: Validate cookie domains to prevent security issues
  5. Thread safety: Ensure custom storage implementations are thread-safe
  6. Memory management: Be mindful of memory usage in long-running applications with many cookies
  7. CSRF protection: Use SameSite attribute for additional security
  8. Cookie size limits: Be aware of cookie size limitations (typically 4KB per cookie)

Install with Tessl CLI

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

docs

builtin-plugins.md

caching.md

cookies.md

engine-configuration.md

forms.md

http-client.md

index.md

plugin-system.md

request-building.md

response-handling.md

response-observation.md

utilities.md

websockets.md

tile.json