Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

http.headers

import http.headers

http lifts part of this module out to its own top level; each name below is shown with the path that reaches it. Anything still spelled http.headers.* needs import 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 line
  • strict (?bool) — when true (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(), so echo and print() show something useful
  • serializable — has a @to_json(), so it can be handed straight to json.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