http.headers
import http.headers
httplifts part of this module out to its own top level; each name below is shown with the path that reaches it. Anything still spelledhttp.headers.*needsimport http.headers.
Headers: a case-insensitive, order-preserving multimap, because HTTP
header names do not compare case-sensitively and some headers may
legitimately appear more than once.
The validation functions enforce what a name and a value may contain, which is what keeps a header value carrying a newline from splitting one response into two.
Functions
is_valid_name()
http.headers.is_valid_name(name) -> bool
Whether name is a syntactically valid HTTP field name, i.e. a
non-empty RFC 9110 token.
Parameters
name(string)
Returns bool
is_valid_value()
http.headers.is_valid_value(value) -> bool
Whether value is a legal HTTP field value.
The rule that actually matters here is that a value may not contain CR,
LF, or NUL. Letting any of those through is response splitting: a value
carrying \r\n ends the field early and lets whoever supplied it inject
headers, or a whole second response, into the stream.
Leading and trailing whitespace is not part of the value and is stripped before the check rather than rejected.
Parameters
value(string)
Returns bool
canonical_name()
http.headers.canonical_name(name: string) -> string
The conventional spelling of a field name, e.g. 'content-type' becomes
'Content-Type' and 'etag' becomes 'ETag'.
Field names are case-insensitive on the wire, so this is purely cosmetic
- but it is the casing every other HTTP implementation emits, and some badly written clients do compare case-sensitively.
Parameters
name(string)
Returns string
parse()
http.headers.parse(block: string, strict: ?bool) -> Headers
Parses a raw header block - everything between a start line and the
blank line that ends the head - into a Headers.
Obsolete line folding (a continuation line starting with a space) is rejected outright rather than unfolded: RFC 9112 §5.2 deprecated it, and treating it as data is the safer reading given how differently intermediaries handle it.
Parameters
block(string) — the header lines, without the trailing blank linestrict(?bool) — whentrue(the default), a field appearing more than once that is defined to appear at most once raises instead of being folded
Returns Headers
Raises ProtocolError on a malformed field, a folded line, or a
duplicated singleton field
is_never_folded()
http.headers.is_never_folded(name: string) -> bool
Whether a field with this name must be repeated rather than folded into one comma-separated value when written out.
Parameters
name(string)
Returns bool
Classes
Headers
class http.Headers
An ordered, case-insensitive, multi-value collection of HTTP header fields.
Field names are matched without regard to case, so
headers.get('content-type') and headers.get('Content-Type') are the
same lookup, while the spelling a field was first added under is what
gets written back out. Insertion order is preserved.
A field may legally appear more than once. set() replaces every
occurrence, add() appends another one, get() returns the first, and
get_all() returns them all:
var h = http.Headers()
h.set('Accept', 'text/html')
h.add('Accept', 'application/json')
h.get('accept') # 'text/html'
h.get_all('accept') # ['text/html', 'application/json']
Every name and value is validated on the way in. A name that isn’t a token, or a value carrying CR, LF or NUL, raises rather than being quietly sanitised, because a value that can inject a newline is a response-splitting bug wherever it eventually lands.
- printable — has a
@to_string(), soechoandprint()show something useful - serializable — has a
@to_json(), so it can be handed straight tojson.encode()
Constructor
http.Headers(fields)
Builds a Headers collection, optionally seeded from a dictionary of
name -> value (or name -> [value, ...]) pairs.
Parameters
fields(?dict)
Headers.get()
http.Headers.get(name: string, fallback) -> any
The first value recorded for name, or fallback (default nil) when
the field is absent.
Parameters
name(string)fallback(?any)
Returns any
Headers.get_all()
http.Headers.get_all(name: string) -> list
Every value recorded for name, in the order they were added, or an
empty list when the field is absent.
Parameters
name(string)
Returns list
Headers.get_joined()
http.Headers.get_joined(name: string, fallback) -> any
All values for name joined with ', ' - the form RFC 9110 §5.3
defines as equivalent to repeating the field - or fallback when the
field is absent.
Never use this for Set-Cookie; commas are legal inside a cookie value
and joining them corrupts the result. get_all() is the right call
there.
Parameters
name(string)fallback(?any)
Returns any
Headers.set()
http.Headers.set(name: string, value)
Replaces every value of name with value. The name keeps whatever
spelling it is given here.
Parameters
name(string)value(string|number|bool)
Returns — Headers: this same instance, for chaining
Raises ProtocolError if the name is not a token or the value
contains CR, LF, or NUL
Headers.add()
http.Headers.add(name: string, value)
Records another value for name, keeping any already there.
Parameters
name(string)value(string|number|bool)
Returns — Headers: this same instance, for chaining
Raises ProtocolError if the name is not a token or the value
contains CR, LF, or NUL
Headers.set_default()
http.Headers.set_default(name: string, value)
Sets name to value only if the field is not already present. Used
throughout this module for defaults a caller is free to override -
Date, Server, User-Agent and friends.
Parameters
name(string)value(string|number|bool)
Returns — Headers: this same instance, for chaining
Headers.remove()
http.Headers.remove(name: string)
Removes every value of name. Removing an absent field does nothing
rather than failing.
Parameters
name(string)
Returns — Headers: this same instance, for chaining
Headers.contains()
http.Headers.contains(name: string) -> bool
Whether name is present at all.
Parameters
name(string)
Returns bool
Headers.contains_token()
http.Headers.contains_token(name: string, token: string) -> bool
Whether name is present and one of its comma-separated tokens equals
token, compared case-insensitively.
This is the correct way to ask about the list-valued fields that drive
protocol decisions - Connection: keep-alive, Upgrade,
Transfer-Encoding: gzip, chunked - where a naive substring test would
happily match keep-alive-ish and a naive equality test would miss the
second token entirely.
Parameters
name(string)token(string)
Returns bool
Headers.tokens()
http.Headers.tokens(name: string) -> list
Every comma-separated token across every occurrence of name,
lowercased and trimmed, in order. Empty elements are dropped, as RFC
9110 §5.6.1 permits.
Parameters
name(string)
Returns list
Headers.extend()
http.Headers.extend(other)
Copies every field from other into this collection, replacing fields
of the same name. other may be another Headers or a plain dictionary
whose values are strings or lists of strings.
Parameters
other(Headers|dict)
Returns — Headers: this same instance, for chaining
Headers.each()
http.Headers.each(callback)
Calls callback(name, value) once per field occurrence, in insertion
order - so a field present three times triggers three calls, which is
exactly what writing the block back out needs.
Parameters
callback(function(2))
Headers.names()
http.Headers.names() -> list
The field names present, in insertion order and in the spelling they were added under.
Returns list
Headers.length()
http.Headers.length() -> number
The number of distinct field names present. A field repeated three times counts once.
Returns number
Headers.is_empty()
http.Headers.is_empty() -> bool
Whether there are no fields at all.
Returns bool
Headers.size()
http.Headers.size() -> number
The number of bytes this block would occupy once serialised, counting
the ': ' and CRLF around every value. Servers use this to enforce a
header-size limit as fields arrive.
Returns number
Headers.clear()
http.Headers.clear()
Drops every field. Cheaper than building a new instance when a connection is being reused for the next message.
Returns — Headers: this same instance, for chaining
Headers.clone()
http.Headers.clone() -> Headers
An independent copy. Mutating the copy never affects the original.
Returns Headers
Headers.canonicalize()
http.Headers.canonicalize()
Rewrites every field name to its conventional casing, e.g.
content-type to Content-Type. Purely cosmetic; names remain
case-insensitive either way.
Returns — Headers: this same instance, for chaining
Headers.strip_hop_by_hop()
http.Headers.strip_hop_by_hop()
Removes the hop-by-hop fields listed in RFC 9110 §7.6.1, which describe
one connection rather than the message itself and must never be
forwarded on to another connection. The set includes anything named by
this message’s own Connection field, which is how an endpoint declares
an extra hop-by-hop field.
A reverse proxy that forgets this is how a client-supplied
Transfer-Encoding reaches an upstream that frames it differently - the
classic smuggling setup.
Returns — Headers: this same instance, for chaining
Headers.to_wire()
http.Headers.to_wire() -> string
Serialises the block in wire format: Name: value\r\n per occurrence,
with no terminating blank line (the caller decides where the block ends,
since a trailer section ends differently to a head).
Returns string
Headers.to_dict()
http.Headers.to_dict() -> dict
The block as a plain dictionary of name -> value, folding repeated
fields into a list. Handy for logging and for handing headers to code
that has no reason to know about this class.
Returns dict
Headers.to_string()
http.Headers.to_string()
2026, Richard Ore and Zuri contributors