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

import http.request

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.request.* needs import http.request.

HttpRequest: one inbound request, with its method, target, headers and body, plus the query string and route parameters already parsed.

The query-string functions are separate because they are useful on their own: build_query_string() is what constructs a URL to request, not only what reads one.

Functions

parse_query_string()

http.parse_query_string(text) -> dict

Decodes an application/x-www-form-urlencoded string - a query string, or a form body - into name -> [value, ...].

+ decodes to a space and %xx to the byte it names, both of which apply to names as well as values. A parameter with no = maps to an empty string rather than to nil, matching what every server-side form API does with ?debug.

Parameters

  • text (?string)

Returns dict

build_query_string()

http.build_query_string(parameters: dict) -> string

Encodes parameters as an application/x-www-form-urlencoded string. Values may be lists, in which case the name repeats.

Parameters

  • parameters (dict)

Returns string

Classes

HttpRequest

class http.HttpRequest

An HTTP request, in both directions.

On the server side an instance arrives fully parsed: method, path, query, headers, cookies and body are all populated, with form(), json_body() and files() decoding the body on first use according to its Content-Type.

On the client side, HttpClient builds one of these for every request it sends, so anything you can inspect on the server you can also set before sending.

  • 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()

Fields

FieldTypeDescription
methodstringThe request method, uppercased: 'GET', 'POST', and so on.
targetstringThe request target exactly as it appeared on the request line, before any decoding - '/search?q=a%20b'.
pathstringThe path, percent-decoded and with its . and .. segments resolved.
query_stringstringThe query string, without the leading ?, or ''.
querydictThe decoded query parameters, as name -> [value, ...].
versionstringThe protocol version: '1.0', '1.1', '2' or '3'.
headersHeadersThe request header fields.
cookiesdictThe cookies the client sent, as name -> value.
paramsdictPath parameters captured by the route that matched, e.g. id for a route registered as /users/:id.
bodybytesThe request body.
remote_address?stringThe address of the peer at the other end of the socket.
secureboolWhether the request arrived over TLS.
schemestringThe scheme the request was made with: 'http' or 'https'.
authority?stringThe authority the request was addressed to, from HTTP/2’s :authority or HTTP/1.1’s Host header, port…
contextdictFree-form storage for whatever middleware wants to attach to a request - a resolved user, a request id, a…
body_reader?BodyReaderThe reader for the body, when the route asked to stream it rather than have it materialised.

Constructor

http.HttpRequest(method, target, headers)

Parameters

  • method (?string)
  • target (?string)
  • headers (?Headers)

HttpRequest.set_target()

http.HttpRequest.set_target(target: string)

Sets the request target and re-derives path, query_string and query from it.

The path is percent-decoded and then normalised, in that order. Doing it the other way round is the classic traversal hole: %2e%2e%2f looks like an ordinary segment until it is decoded.

Parameters

  • target (string)

HttpRequest.header()

http.HttpRequest.header(name: string, fallback) -> any

A request header value, or fallback when absent.

Parameters

  • name (string)
  • fallback (?any)

Returns any

HttpRequest.query_param()

http.HttpRequest.query_param(name: string, fallback) -> any

The first value of the query parameter name, or fallback.

Parameters

  • name (string)
  • fallback (?any)

Returns any

HttpRequest.param()

http.HttpRequest.param(name: string, fallback) -> any

A path parameter captured by the matched route, or fallback.

Parameters

  • name (string)
  • fallback (?any)

Returns any

HttpRequest.cookie()

http.HttpRequest.cookie(name: string, fallback) -> any

A cookie value, or fallback.

Parameters

  • name (string)
  • fallback (?any)

Returns any

HttpRequest.session()

http.HttpRequest.session() -> Session

This request’s session.

The session is put here by http.session.session(), so a server that never registered that middleware has none, and asking for one says so rather than handing back nil for a handler to misread as an empty session.

request.session().set('account', account.id)

Returns Session

Raises SessionError if the session middleware is not registered

HttpRequest.content_type()

http.HttpRequest.content_type() -> ?string

The media type of the body, without parameters, or nil.

Returns ?string

HttpRequest.content_length()

http.HttpRequest.content_length() -> number

The declared body length, or -1 when the request carries no Content-Length (which for a chunked body it will not).

Returns number

HttpRequest.text()

http.HttpRequest.text() -> string

The body decoded as UTF-8 text.

Returns string

HttpRequest.json_body()

http.HttpRequest.json_body() -> any

The body parsed as JSON.

Parses once and caches, so calling this in both a middleware and a handler costs one parse.

Returns any

Raises HttpError if the body is not valid JSON

HttpRequest.form()

http.HttpRequest.form() -> dict

The submitted form fields, as name -> value, from either an application/x-www-form-urlencoded or a multipart/form-data body. A body of neither type gives an empty dictionary rather than raising.

Repeated names keep their first value here; use form_all() when a field can legitimately repeat.

Returns dict

HttpRequest.form_all()

http.HttpRequest.form_all() -> dict

The submitted form fields as name -> [value, ...], keeping every value of a repeated name.

Returns dict

HttpRequest.form_field()

http.HttpRequest.form_field(name: string, fallback) -> any

A single form field’s first value, or fallback.

Parameters

  • name (string)
  • fallback (?any)

Returns any

HttpRequest.files()

http.HttpRequest.files() -> dict

The files uploaded in a multipart/form-data body, as name -> [UploadedFile, ...]. Empty for any other body type.

Returns dict

HttpRequest.file()

http.HttpRequest.file(name: string) -> ?UploadedFile

The first file uploaded under name, or nil.

Parameters

  • name (string)

Returns ?UploadedFile

HttpRequest.input()

http.HttpRequest.input(source: ?string) -> dict

The request’s input as one dictionary, ready to hand to a validator.

With no argument, three sources are merged, each overriding the one before it:

  1. route parameters, from the pattern that matched 2. query string parameters 3. the body - a JSON object’s keys, or the submitted form fields

Pass source to take exactly one of them instead: 'params', 'query' or 'body'.

A query or form field is a list on the wire, since a name may legally repeat. A name carrying exactly one value is flattened to that value here, so a rule expecting a string sees a string; a name carrying several stays a list. A field that must always be a list, however many values arrived, is better read through form_all() or query directly.

Uploaded files are not included - nothing a schema can say about a file is expressible as a rule over its bytes. Reach them with file() and check them by hand.

A JSON body that is not an object (an array, a bare string) contributes nothing, since there are no names to merge; read it with json_body() instead.

Parameters

  • source (?string) — 'params', 'query', 'body', or 'all' (the default)

Returns dict

Raises ValueError if source names something else

HttpRequest.validate()

http.HttpRequest.validate(schema, source: ?string)

Validates the request’s input against schema and returns the data that was validated.

schema is anything with a check_or_raise() method - a validate.Schema in practice:

import validate

var create_user = validate.schema({
  name:  validate.required().string().max_length(100),
  email: validate.required().string().email(),
})

server.post('/users', @(request, response) {
  var data = request.validate(create_user)
  response.json(create_account(data), 201)
})

Failure raises the schema’s own error - validate.ValidationError

  • carrying an errors list of { field, message }. Catch it to turn it into whatever your API answers with:
catch {
  var data = request.validate(create_user)
  response.json(create_account(data), 201)
} as error {
  response.json({ errors: create_user.group_errors(error.errors) }, 422)
}

Parameters

  • schema (Schema)
  • source (?string) — as input(); defaults to 'all'

Returns — dict: the input that was validated

Raises ValidationError when the input does not satisfy the schema

Raises TypeError if schema is not an object that can validate

Note: This deliberately does not import the validate module. Any object exposing check_or_raise(data) works, and a server that never validates anything never pays to load it.

HttpRequest.host()

http.HttpRequest.host() -> ?string

The host the request was addressed to, without any port.

Returns ?string

HttpRequest.port()

http.HttpRequest.port() -> number

The port the request was addressed to, from the authority, or the scheme’s default when the authority named none.

Returns number

HttpRequest.url()

http.HttpRequest.url() -> string

The full absolute URL this request names.

Returns string

HttpRequest.client_ip()

http.HttpRequest.client_ip(trust_proxy: ?bool, trusted: ?list) -> ?string

The originating client’s IP address.

Directly served, that is simply the peer’s address. Behind a reverse proxy the peer is the proxy, and the real client is in X-Forwarded-For or RFC 7239’s Forwarded - but those are request headers, which is to say anyone can write anything in them.

So they are only consulted when trust_proxy says to, and the value taken is the rightmost entry that is not itself one of trusted, walking in from the proxy end. Taking the leftmost entry - the common shortcut - hands an attacker whatever client IP they care to claim, which matters the moment an IP is used for rate limiting, allowlisting or audit.

Parameters

  • trust_proxy (?bool) — whether to consult forwarding headers at all; defaults to false
  • trusted (?list) — proxy addresses to skip over when walking the chain

Returns ?string

HttpRequest.accepts()

http.HttpRequest.accepts(type: string) -> bool

Whether the client would accept a response of media type type, per its Accept header. A request with no Accept accepts anything.

Parameters

  • type (string)

Returns bool

HttpRequest.wants_json()

http.HttpRequest.wants_json() -> bool

Whether the client would rather have JSON than HTML - the usual way to decide whether an error should be rendered as a page or returned as an object.

Returns bool

HttpRequest.bearer_token()

http.HttpRequest.bearer_token() -> ?string

The token from an Authorization: Bearer ... header, or nil when there is no such header or it carries a different scheme.

Returns ?string

HttpRequest.is_ajax()

http.HttpRequest.is_ajax() -> bool

Whether the request was made by client-side script, as reported by the X-Requested-With header that the major JavaScript libraries set.

Returns bool

HttpRequest.is_upgrade()

http.HttpRequest.is_upgrade(protocol: ?string) -> bool

Whether the request asks to switch to another protocol - a WebSocket handshake, or an HTTP/2 upgrade.

Parameters

  • protocol (?string) — check for one specific protocol

Returns bool

HttpRequest.expects_continue()

http.HttpRequest.expects_continue() -> bool

Whether the client asked the server to acknowledge before it sends the body (Expect: 100-continue).

Returns bool

HttpRequest.is_safe()

http.HttpRequest.is_safe() -> bool

Whether this method is defined to be safe: read-only, with no side effects the client is responsible for (RFC 9110 §9.2.1).

Returns bool

HttpRequest.is_idempotent()

http.HttpRequest.is_idempotent() -> bool

Whether this method is idempotent - repeating it has the same effect as making it once (RFC 9110 §9.2.2). This is what decides whether a client may retry a request after a connection failure.

Returns bool

HttpRequest.to_wire()

http.HttpRequest.to_wire() -> string

The full request head in wire format, as it would be sent on an HTTP/1.1 connection. Useful for logging and for debugging what actually went out.

Returns string

HttpRequest.to_string()

http.HttpRequest.to_string()

HttpRequest.to_json()

http.HttpRequest.to_json()

2026, Richard Ore and Zuri contributors