http.util
import http
httpexposes this ashttp.util, soimport httpis enough and the names are called ashttp.util.*.import http.utilreaches 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