Cookie Jar
aioduct supports automatic cookie management through a CookieJar. When enabled, cookies from Set-Cookie response headers are stored and automatically sent in subsequent requests to the same domain.
Enabling Cookies
Create a CookieJar and pass it to the client builder:
#![allow(unused)]
fn main() {
use aioduct::{TokioClient, CookieJar};
let jar = CookieJar::new();
let client = TokioClient::builder()
.cookie_jar(jar)
.build()?;
}
How It Works
- When a response contains
Set-Cookieheaders, the jar stores each cookie keyed by domain - On subsequent requests, matching cookies are sent in the
Cookieheader - Cookies with the
Secureflag are only sent over HTTPS - If a response sets a cookie with the same name, it replaces the existing one
- Cookies with
Max-Age=0or a pastExpiresdate are removed from the jar - The
Pathattribute is respected — cookies are only sent for matching request paths - Domain matching supports subdomains — a cookie for
example.comis sent tosub.example.com
Example: Session-Based API
use aioduct::{TokioClient, CookieJar};
#[tokio::main]
async fn main() -> Result<(), aioduct::Error> {
let client = TokioClient::builder()
.cookie_jar(CookieJar::new())
.build()?;
// Login — server sets session cookie
client
.post("http://example.com/login")?
.form(&[("user", "alice"), ("pass", "secret")])
.send()
.await?;
// Subsequent requests automatically include the session cookie
let resp = client
.get("http://example.com/dashboard")?
.send()
.await?;
println!("{}", resp.text().await?);
Ok(())
}
Clearing Cookies
#![allow(unused)]
fn main() {
use aioduct::CookieJar;
let jar = CookieJar::new();
// ... use jar with client ...
jar.clear(); // remove all stored cookies
}
Without Cookie Jar
By default, no cookie jar is configured. Responses with Set-Cookie headers are ignored, and no Cookie header is sent automatically. You can still manage cookies manually via header_str("cookie", "...").
Inspecting Cookies
The CookieJar and Cookie types are public, allowing inspection of stored cookies:
#![allow(unused)]
fn main() {
use aioduct::CookieJar;
let jar = CookieJar::new();
// ... use jar with client ...
for cookie in jar.cookies() {
println!("{} = {}", cookie.name(), cookie.value());
if let Some(domain) = cookie.domain() {
println!(" domain: {domain}");
}
if let Some(path) = cookie.path() {
println!(" path: {path}");
}
println!(" secure: {}", cookie.secure());
println!(" http_only: {}", cookie.http_only());
}
}
Cookie Accessors
| Method | Return Type | Description |
|---|---|---|
name() | &str | Cookie name |
value() | &str | Cookie value |
domain() | Option<&str> | Domain attribute (defaults to request domain) |
path() | Option<&str> | Path attribute |
secure() | bool | Whether the cookie requires HTTPS |
http_only() | bool | Whether the cookie is HTTP-only |
same_site() | Option<&SameSite> | SameSite attribute (Strict, Lax, or None) |
SameSite Cookies
aioduct parses the SameSite attribute from Set-Cookie headers per the RFC 6265bis draft:
Strict— cookie is only sent in first-party context (same-site requests)Lax— cookie is sent on top-level navigations and same-site requests (browser default)None— cookie is sent in all contexts (requiresSecureflag)
#![allow(unused)]
fn main() {
use aioduct::cookie::SameSite;
use aioduct::CookieJar;
let jar = CookieJar::new();
// ... use jar with client ...
for cookie in jar.cookies() {
match cookie.same_site() {
Some(SameSite::Strict) => println!("{}: strict", cookie.name()),
Some(SameSite::Lax) => println!("{}: lax", cookie.name()),
Some(SameSite::None) => println!("{}: none", cookie.name()),
None => println!("{}: not set", cookie.name()),
}
}
}
Cookie Prefixes
aioduct enforces cookie prefix validation per RFC 6265bis:
__Host-— requiresSecure, exact domain match (noDomainattribute pointing elsewhere), andPath=/__Secure-— requiresSecureflag
Cookies that fail prefix validation are silently rejected.
Cookie Attributes
Domain Matching
Cookies use RFC-compliant domain matching with subdomain support:
- A cookie stored for
example.commatches requests toexample.comandsub.example.com - A cookie stored for
sub.example.comdoes not matchexample.comorother.example.com - Leading dots in the
Domainattribute are stripped (Domain=.example.combecomesexample.com)
Path Scoping
When a Set-Cookie header includes a Path attribute, the cookie is only sent for requests whose path starts with the cookie’s path:
Set-Cookie: token=abc; Path=/api
/api— cookie sent/api/users— cookie sent/— cookie not sent/other— cookie not sent
Expiration
Cookies are expired and removed from the jar when:
Max-Age=0or a negative value is received- An
Expiresdate in the past is received (RFC 7231 date format:Wed, 21 Oct 2015 07:28:00 GMT)
Expired cookies are never stored; setting Max-Age=0 on an existing cookie removes it.