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.util

import http

http exposes this as http.util, so import http is enough and the names are called as http.util.*. import http.util reaches the same definitions directly.

The small, exact pieces of the HTTP specifications that several parts of the module need: date formatting, percent-encoding, quoted strings, header parameter lists, path normalisation and authorization headers.

secure_equals() and random_token() are here because they are used where timing matters: comparing a token in constant time, and generating one that cannot be guessed.

Functions

find_bytes()

http.util.find_bytes(haystack, needle, from) -> number

Finds the first occurrence of the byte sequence needle in haystack, at or after from, or -1 when it does not occur.

The built-in bytes.index_of() searches for a single byte, which is not enough for the delimiters HTTP is full of - CRLF, the blank line ending a head, a multipart boundary. This finds candidate positions with that fast single-byte search and only then compares the rest.

Parameters

  • haystack (bytes)
  • needle (bytes)
  • from (?number)

Returns number

to_hex()

http.util.to_hex(n: number) -> string

n as lowercase hexadecimal, with no 0x prefix and no padding.

Parameters

  • n (number)

Returns string

format_date()

http.util.format_date(timestamp) -> string

Formats a Unix timestamp as an IMF-fixdate, the one date format RFC 9110 §5.6.7 requires every HTTP sender to produce: Sun, 06 Nov 1994 08:49:37 GMT.

Always UTC, always fixed-width, never localised. The two obsolete formats are accepted by parse_date() but never emitted.

Parameters

  • timestamp (?number) — seconds since the epoch; defaults to now

Returns string

parse_date()

http.util.parse_date(text: string)

Parses any of the three date formats RFC 9110 §5.6.7 requires a recipient to accept, and returns the Unix timestamp.

The two obsolete ones (RFC 850’s Sunday, 06-Nov-94 08:49:37 GMT and asctime’s Sun Nov 6 08:49:37 1994) still appear in the wild from old servers and caches, so a client that only understands IMF-fixdate will silently mishandle their Expires and Last-Modified.

Two-digit years follow the usual rule: a year that would place the date more than fifty years in the future is read as the previous century.

Parameters

  • text (string)

Returns — ?number: the timestamp, or nil if the date is unparseable

parse_parameters()

http.util.parse_parameters(value: string)

Splits a header value that carries parameters - a media type, a Content-Disposition, a challenge - into its leading value and a dictionary of lowercased parameter names to values.

Quoted strings are unquoted and their backslash escapes resolved. RFC 5987 extended parameters (filename*=UTF-8''na%C3%AFve.txt) are decoded and take precedence over the plain form of the same name, which is what lets a non-ASCII upload filename survive.

parse_parameters('text/html; charset=utf-8')
# ['text/html', {charset: 'utf-8'}]

Parameters

  • value (string)

Returns — list: [value, parameters]

unquote()

http.util.unquote(value: string) -> string

Removes the surrounding double quotes from a header value and resolves its backslash escapes. A value that isn’t quoted comes back unchanged.

Parameters

  • value (string)

Returns string

quote()

http.util.quote(value: string) -> string

Wraps value in double quotes, escaping any quote or backslash it contains, so it can be used as an RFC 9110 quoted-string.

Parameters

  • value (string)

Returns string

percent_decode()

http.util.percent_decode(text: string, plus_as_space: ?bool) -> string

Percent-decodes a URI component, turning + into a space only when plus_as_space is set - which is right for a query string or a form body, and wrong for a path, where + is a literal plus.

Invalid escapes are left as-is rather than raising: a malformed % in a path is a 404 waiting to happen, not a reason to drop the connection.

Parameters

  • text (string)
  • plus_as_space (?bool)

Returns string

percent_encode()

http.util.percent_encode(text: string) -> string

Percent-encodes every character of text that is not an RFC 3986 unreserved character, over the UTF-8 encoding of the input.

Parameters

  • text (string)

Returns string

normalize_path()

http.util.normalize_path(path: string)

Resolves the . and .. segments of a path and collapses repeated slashes, returning a path that cannot climb above /.

This is the check that stands between a static file handler and GET /static/../../etc/passwd, and it has to happen after percent-decoding, since %2e%2e%2f is the same request written to survive a naive check.

Parameters

  • path (string)

Returns — string: always starting with /

secure_equals()

http.util.secure_equals(a, b) -> bool

Compares two strings without leaking, through how long the comparison takes, where they first differ.

Use this for anything an attacker can submit repeatedly and tune - a session token, an API key, an HMAC - where a byte-at-a-time comparison hands over the secret one guess at a time.

Parameters

  • a (string)
  • b (string)

Returns bool

random_token()

http.util.random_token(length) -> string

A random lowercase-hex token of length characters, drawn from the platform’s cryptographically secure generator.

Used for multipart boundaries, WebSocket keys, and anywhere else this module needs a value an attacker must not be able to predict.

Parameters

  • length (?number) — defaults to 32

Returns string

parse_basic()

http.util.parse_basic(header)

Parses an HTTP Basic Authorization field value into a username and password.

The scheme name is matched case-insensitively, as RFC 9110 §11.1 requires. A header that is not a well-formed Basic credential - wrong scheme, undecodable base64, no colon in the decoded pair - comes back as nil rather than raising, since a malformed credential is a 401, not a crash.

Parameters

  • header (?string)

Returns — ?list: [username, password], or nil

parse_bearer()

http.util.parse_bearer(header)

Parses a Bearer Authorization field value into its token.

Parameters

  • header (?string)

Returns — ?string: the token, or nil when the header is absent or is not a bearer credential

is_valid_method()

http.util.is_valid_method(value) -> bool

Whether value is a valid HTTP method: a non-empty token, per RFC 9110 §9. Methods are case-sensitive, so no normalisation happens here.

Parameters

  • value (string)

Returns bool


2026, Richard Ore and Zuri contributors