http.cookies
cpython 3.14 @ ab2d84fe1023/Lib/http/cookies.py
RFC 2109 HTTP cookie header parser and serializer. The module centres on two classes:
Morsel, which holds a single parsed cookie with its RFC-defined attributes, and
SimpleCookie, a dict-like container of Morsel objects that can parse a raw
Cookie: or Set-Cookie: header and regenerate it with correct quoting.
Map
| Lines | Symbol | Role |
|---|---|---|
| 1-60 | Morsel | One cookie: key, value, coded_value plus RFC-defined attributes |
| 60-250 | BaseCookie, SimpleCookie | Dict-like container; load() parses headers, output() serializes |
| 250-280 | CookieError | Raised on parse failure or illegal Morsel attribute |
| 280-350 | _quote, _unquote | RFC 2109 safe-char quoting and unquoting helpers |
| 350-400 | _getdate, _CookiePattern | Expiry date formatter and pre-compiled tokenizer regex |
Reading
Morsel attributes and legal keys
Morsel._reserved is a frozenset of the attribute names RFC 2109 defines. Attempting
to set an attribute not in that set raises CookieError. The coded_value attribute
stores the wire representation (quoted if necessary) while value stores the decoded
Python string. They diverge whenever _quote has to escape characters.
from http.cookies import Morsel, CookieError
m = Morsel()
m.set("session", "abc 123", '"abc 123"') # key, raw value, coded value
print(m.key) # session
print(m.value) # abc 123
print(m.coded_value) # "abc 123"
m["path"] = "/api"
m["httponly"] = True
m["samesite"] = "Lax"
try:
m["invalid_attr"] = "boom"
except CookieError as exc:
print(exc) # Illegal key 'invalid_attr'
OutputString() serialises one Set-Cookie: line. It iterates _reserved in a
deterministic order, skipping attributes whose value is the empty string or False.
SimpleCookie parse and output
SimpleCookie.load() accepts either a raw header string or a pre-split dict.
When given a string it calls _BaseCookie__parse_string, which runs _CookiePattern
in a finditer loop to extract (key, val) pairs in O(n) time.
from http.cookies import SimpleCookie
raw = 'csrftoken=abc123; sessionid="xyz"; Path=/; HttpOnly; SameSite=Lax'
sc = SimpleCookie()
sc.load(raw)
for name, morsel in sc.items():
print(name, "->", morsel.value, "| path:", morsel["path"])
# Regenerate the header
header = sc.output(header="Set-Cookie:")
print(header)
output() calls Morsel.OutputString() for each morsel and joins lines with \r\n.
js_output() produces a <script> block that sets cookies via document.cookie for
situations where the header cannot be set server-side.
Quoting rules
_quote uses _LegalChars (all printable ASCII minus the fourteen RFC-reserved
punctuation characters) as its safe set. Any value containing a character outside that
set is wrapped in double quotes. Backslash and double-quote inside a quoted value are
backslash-escaped to produce valid RFC 2109 quoted-string tokens.
from http.cookies import SimpleCookie
sc = SimpleCookie()
sc["token"] = "hello world" # space forces quoting
sc["plain"] = "helloworld" # stays unquoted
print(sc["token"].coded_value) # "hello world"
print(sc["plain"].coded_value) # helloworld
_unquote reverses the process: it strips surrounding " if present, then replaces
\\ and \" escapes with their literal characters using a small substitution table.
gopy mirror
Not yet ported. The planned location is module/http_cookies/ following gopy's flat
module layout. Key work items:
Morselstruct with a fixed attribute map validated against the reserved-key set.SimpleCookiebacked by an ordered map to preserve insertion order on output._CookiePatterntranslated to a compiledregexp.Regexpwith named groups._quote/_unquoteported as Go functions operating on[]bytefor efficiency.
CPython 3.14 changes
Morsel._reservedgained"samesite"as a first-class key (previously callers had to set it via the attribute dict directly with no validation)._quotenow rejects ASCII control characters (0x00-0x1f, 0x7f) even inside quoted strings, aligning with the stricter interpretation in RFC 6265.SimpleCookie.load()emits aDeprecationWarningwhen it silently drops malformed tokens; a future version will raiseCookieErrorinstead.