Ktor HTTP Client Core - a multiplatform asynchronous HTTP client library for Kotlin providing comprehensive HTTP request/response handling with plugin architecture.
—
HTTP cookie handling with multiple storage implementations, automatic cookie management, and comprehensive cookie processing capabilities.
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")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
}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)
}
}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()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)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
}
}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") }
}/**
* 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