README

#Cookie

HTTP cookie parsing and serialization for MoonBit.

Cookies are small pieces of data that web servers send to browsers via Set-Cookie headers. The browser stores them and attaches them back on subsequent requests in the Cookie header. They are the standard mechanism for session management, user preferences, and tracking across HTTP requests.

#How Cookies Work

Cookies rely on a two-step exchange between server and browser:

1. Server sets a cookie — The server includes one or more Set-Cookie headers in an HTTP response. Each header carries a name-value pair plus optional attributes that control the cookie's lifetime, scope, and security:

HTTP/1.1 200 OK Set-Cookie: session_id=abc123; Path=/; Max-Age=3600; Secure; HttpOnly; SameSite=Lax

2. Browser sends it back — On every subsequent request to the same origin (subject to Path, Domain, and SameSite rules), the browser automatically attaches all matching cookies in a single Cookie header:

GET /api/profile HTTP/1.1 Cookie: session_id=abc123; theme=dark

The server never sees the attributes (Path, Secure, etc.) again — the browser uses them locally to decide whether to send the cookie, but only the name=value pairs travel back.

AttributePurpose
Max-AgeSeconds until the cookie expires. 0 deletes it immediately.
PathURL path prefix the cookie applies to (default: current path).
DomainWhich hosts receive the cookie (default: exact origin only).
SecureOnly send over HTTPS.
HttpOnlyHide from JavaScript (document.cookie), mitigating XSS.
SameSiteControls cross-site sending — see SameSite Options.

#Lifecycle

  1. Session cookies — no Max-Age or Expires: deleted when the browser closes.
  2. Persistent cookies — have a Max-Age (or Expires): survive across browser restarts until they expire.
  3. Deletion — the server sends Set-Cookie: name=; Max-Age=0 to ask the browser to remove a cookie.

This package provides:

  • CookieItem — a typed representation of an HTTP cookie with attributes like Path, Domain, Max-Age, Secure, HttpOnly, and SameSite.
  • parse_cookie — parses a raw cookie header string into a map of cookie items.
  • cookie_to_string — serializes an array of cookies back into a header string.

#Install

This package is included with bobzhang/crescent. Import it directly:

import { "bobzhang/crescent/cookie" ... }

#Creating Cookies

Use the CookieItem constructor to build a cookie with optional attributes:

///|
test "create a cookie with attributes" {
let cookie = @cookie.CookieItem(
name="session_id",
value="abc123",
max_age=3600,
path="/",
domain="example.com",
secure=true,
http_only=true,
same_site=Lax,
)
debug_inspect(
cookie,
content=(
#|{
#| name: "session_id",
#| value: "abc123",
#| max_age: Some(3600),
#| path: Some("/"),
#| domain: Some("example.com"),
#| secure: Some(true),
#| http_only: Some(true),
#| same_site: Some(Lax),
#|}
),
)
}

A minimal cookie only needs name and value:

///|
test "minimal cookie" {
let cookie = @cookie.CookieItem(name="theme", value="dark")
debug_inspect(
cookie.to_string(),
content=(
#|"theme=dark"
),
)
}

#Parsing Cookies

parse_cookie parses a raw Cookie header string into a Map[String, CookieItem]:

///|
test "parse a cookie header" {
let cookies = @cookie.parse_cookie("name=value; session=abc123")
debug_inspect(
cookies.get("name").map(fn(c) { c.value }),
content="Some(\"value\")",
)
debug_inspect(
cookies.get("session").map(fn(c) { c.value }),
content="Some(\"abc123\")",
)
}

It also recognizes Set-Cookie attributes like Path, Domain, Max-Age, Secure, HttpOnly, and SameSite:

///|
test "parse cookie with attributes" {
let cookies = @cookie.parse_cookie(
"token=xyz; Path=/api; Secure; HttpOnly; SameSite=Strict",
)
guard cookies.get("token") is Some(c) else { fail("expected token cookie") }
assert_eq(c.path, Some("/api"))
assert_eq(c.secure, Some(true))
assert_eq(c.http_only, Some(true))
assert_eq(c.same_site, Some(Strict))
}

#Serializing Multiple Cookies

cookie_to_string joins an array of cookies into a semicolon-separated string:

///|
test "serialize multiple cookies" {
let cookies = [
@cookie.CookieItem(name="a", value="1"),
CookieItem(name="b", value="2"),
]
debug_inspect(
@cookie.cookie_to_string(cookies),
content=(
#|"a=1;b=2"
),
)
}

#SameSite Options

The SameSiteOption enum controls cross-site request behavior:

VariantMeaning
LaxSent on top-level navigations and GET requests
StrictSent only on same-site requests
SameSiteNoneSent on all requests (requires Secure)

#
CookieItem

pub(all) struct CookieItem {
name : String
value : String
max_age : Int?
path : String?
domain : String?
secure : Bool?
http_only : Bool?
same_site : SameSiteOption?
} derive(Eq,
Debug
)

Represents an HTTP cookie with its name, value, and optional attributes.
impl Show for CookieItem

#
CookieItem::CookieItem

fn CookieItem::CookieItem(name~ : String, value~ : String, max_age? : Int, path? : String, domain? : String, secure? : Bool, http_only? : Bool, same_site? : SameSiteOption) -> CookieItem

Creates a new CookieItem with the given name, value, and optional attributes.

#
SameSiteOption

pub(all) enum SameSiteOption {
Lax
Strict
SameSiteNone
} derive(Eq,
Debug
)

The SameSite attribute for cookies, controlling cross-site request behavior.
fn cookie_to_string(cookie : Array[CookieItem]) -> String

Serializes an array of cookie items into a semicolon-separated string.
fn parse_cookie(cookie : StringView) -> Map[String, CookieItem]

Parses a raw cookie header string into a map of cookie names to CookieItem values.

Source Files