roadrunner_req (roadrunner v0.1.0)
View SourcePure accessors over the request() map.
Decouples handler code from the underlying map shape — handlers should
prefer these functions over direct maps:get/2 so the request
representation can evolve without breaking them.
The request/0 type is canonical here. The shared HTTP primitives
re-exported alongside it (headers/0, version/0, status/0,
redirect_status/0) are aliases of the definitions in
roadrunner_http.
Summary
Types
Body-read envelope attached to the request in body_buffering => manual mode. read_body/1,2 consumes from it; the conn owns the
recv closure and tracks how much remains.
Framework-internal h1-parser hot-path optimization carried on the
request map's cached_decisions field. Handlers should ignore both
the field and this type — they're absent on h2 requests and on
manually-built request maps. Populated by the h1 parser at
request-read time and consumed by framework code to skip
per-request header re-lowercasing on the dispatch hot path.
The parsed request map handlers receive.
Functions
Return the router-captured bindings for this request as a
#{Name => Value} map of binaries.
Return the buffered request body bytes as seen by the handler.
Return the leftmost client identifier from the Forwarded header
(RFC 7239) or, if absent, from X-Forwarded-For. Returns undefined
when neither header is set or the Forwarded header has no for=
parameter.
Return whether the request carries a non-empty body.
Return whether Name is present in the request headers.
Look up a single header value by name. Returns undefined if absent.
Return the full ordered list of {Name, Value} header pairs.
Return the request method (uppercase ASCII binary).
Return whether the request method matches the given binary.
Parse the Cookie request header into a list of {Name, Value} pairs
via roadrunner_cookie:parse/1.
Parse the query string portion of the request target into a list of
{Key, Value} pairs (or {Key, true} for bare flags) via
roadrunner_qs:parse/1.
Return the path component of the request-target.
Return the TCP peer ({IpAddress, Port}) for the connection that
delivered this request.
Return the raw query string portion of the request-target, without the
leading ?. Empty binary when no ? is present (or nothing follows it).
Read the request body in one shot. Works in both auto and manual
body-buffering modes
Read the request body, optionally bounded by length.
Read the next decoded HTTP chunk from a chunked-encoded request body.
Read and parse a form-encoded request body. Inspects the request's
Content-Type and dispatches
Return the per-request correlation token attached by roadrunner_conn.
Return the connection scheme — http for plain TCP, https for TLS.
Return the opaque per-route handler state attached at compile time.
Return the HTTP version tuple ({1,0} or {1,1}).
Types
-type body_reader() :: #{framing := none | chunked | {content_length, non_neg_integer()}, buffered := binary(), bytes_read := non_neg_integer(), pending := binary(), done := boolean(), recv := fun(() -> {ok, binary()} | {error, term()}), max := non_neg_integer()}.
Body-read envelope attached to the request in body_buffering => manual mode. read_body/1,2 consumes from it; the conn owns the
recv closure and tracks how much remains.
pending holds decoded body bytes that have been parsed off the
wire but not yet handed to the caller — used for chunked framing
to absorb a chunk's payload across multiple length-bounded calls.
done flips true once the size-0 last chunk is parsed.
-type cached_decisions() :: #{is_chunked := boolean(), has_transfer_encoding := boolean(), expects_continue := boolean(), connection_lower := binary(), content_length := none | {ok, non_neg_integer()} | {error, bad_content_length}, has_host := boolean()}.
Framework-internal h1-parser hot-path optimization carried on the
request map's cached_decisions field. Handlers should ignore both
the field and this type — they're absent on h2 requests and on
manually-built request maps. Populated by the h1 parser at
request-read time and consumed by framework code to skip
per-request header re-lowercasing on the dispatch hot path.
-type headers() :: roadrunner_http:headers().
-type request() :: #{method := binary(), target := binary(), version := version(), headers := headers(), cached_decisions => cached_decisions(), body => iodata(), bindings => roadrunner_router:bindings(), peer => {inet:ip_address(), inet:port_number()} | undefined, scheme => http | https, state => term(), body_reader => body_reader(), request_id => binary(), listener_name => atom()}.
The parsed request map handlers receive.
Required fields are present on every request the framework
delivers; optional fields are populated by the framework when
applicable (e.g. body in body_buffering => auto mode,
bindings for routed dispatch, request_id for telemetry).
The same shape flows through both the h1 and h2 paths — h2's
roadrunner_http2_request synthesizes a request matching this
type from frames + pseudo-headers, so handlers don't have to
care which protocol delivered the bytes.
-type version() :: roadrunner_http:version().
Functions
-spec bindings(request()) -> roadrunner_router:bindings().
Return the router-captured bindings for this request as a
#{Name => Value} map of binaries.
roadrunner_conn populates this from roadrunner_router:match/2 before
invoking the handler. Empty map when the listener is in single-handler
mode (no router) or the matched route has no :param segments.
Return the buffered request body bytes as seen by the handler.
The connection process embeds whatever bytes followed the header block
under the body map key before invoking the handler. Auto-mode delivers
the full body as iodata() (an iolist of recv chunks for multi-chunk
bodies, a single binary otherwise) so handlers that only need
iolist_size/1 or gen_tcp:send/2 skip a flatten. Handlers requiring
a flat binary call iolist_to_binary/1 themselves.
Returns <<>> when the request has no body field (e.g. when a request
map is constructed manually outside the connection pipeline).
Return the leftmost client identifier from the Forwarded header
(RFC 7239) or, if absent, from X-Forwarded-For. Returns undefined
when neither header is set or the Forwarded header has no for=
parameter.
The returned binary is whatever the proxy chose to put there — for
RFC 7239 that's typically an IP literal (192.0.2.60) or a quoted
IPv6+port ([2001:db8::1]:4711); for X-Forwarded-For it's
conventionally just the IP. The caller decides how to parse it.
No trust list is enforced. Anyone who can speak to the listener directly can spoof these headers — only call this when the deploy sits behind a trusted reverse proxy that strips/overwrites them.
Return whether the request carries a non-empty body.
Returns false for both an absent body field and an empty body.
Handlers can use this as a short-circuit before doing any body-aware
work. Uses iolist_size/1 so the check is O(length of iolist), not
O(total bytes).
Return whether Name is present in the request headers.
Lookup is case-insensitive on Name — same convention as header/2.
Look up a single header value by name. Returns undefined if absent.
The lookup is case-insensitive on Name — the parser already
lowercases header names on the wire, so any-case input is normalized
before searching.
Return the full ordered list of {Name, Value} header pairs.
Return the request method (uppercase ASCII binary).
Return whether the request method matches the given binary.
Comparison is byte-exact and case-sensitive — the parser already
enforces uppercase methods on the wire, so callers should pass
uppercase too (~"GET", ~"POST", etc.).
Parse the Cookie request header into a list of {Name, Value} pairs
via roadrunner_cookie:parse/1.
Returns [] when the request carries no Cookie header.
Parse the query string portion of the request target into a list of
{Key, Value} pairs (or {Key, true} for bare flags) via
roadrunner_qs:parse/1.
Returns [] when the target has no query component.
Return the path component of the request-target.
If the target contains a ? query separator, only the bytes before it
are returned. The path is not percent-decoded — that's the
router's job.
-spec peer(request()) -> {inet:ip_address(), inet:port_number()} | undefined.
Return the TCP peer ({IpAddress, Port}) for the connection that
delivered this request.
roadrunner_conn populates this from inet:peername/1 once per
connection. Returns undefined when the request map has no peer
field (e.g. constructed manually outside the connection pipeline) or
when the OS call failed at accept time.
Return the raw query string portion of the request-target, without the
leading ?. Empty binary when no ? is present (or nothing follows it).
For decoded {Key, Value} pairs, pipe through roadrunner_qs:parse/1.
Read the request body in one shot. Works in both auto and manual
body-buffering modes:
- auto (default): the conn already buffered the body before
invoking the handler — this returns the buffered bytes unchanged.
Reqis returned as-is. - manual: the conn parked the body on the socket. This drains it
and returns the bytes. The returned
Req2carries the updated body-read state — to enable keep-alive on the same connection in manual mode, handReq2back via the 4-tuple handler return shape{Status, Headers, Body, Req2}so the conn can drain whatever the handler skipped.
-spec read_body(request(), #{length => non_neg_integer()}) -> {ok, iodata(), request()} | {more, iodata(), request()} | {error, term()}.
Read the request body, optionally bounded by length.
Opts may contain length => non_neg_integer(). If absent, behaves
like read_body/1 (drain to end). When set, returns up to Length
bytes per call:
{ok, Bytes, Req2}— body is fully drained (no more bytes left).{more, Bytes, Req2}— more bytes remain; call again withReq2.
Works for both content-length and chunked framing — chunked bodies
are streamed transparently across chunk boundaries up to Length
bytes per call.
In auto mode the body is already buffered, so length has no
effect — the buffered bytes are returned in one shot.
-spec read_body_chunked(request()) -> {ok, iodata(), request()} | {more, iodata(), request()} | {error, term()}.
Read the next decoded HTTP chunk from a chunked-encoded request body.
Mirrors cowboy's chunk-at-a-time read pattern: each call returns one
chunk's payload. {more, Bytes, Req2} means more chunks remain;
{ok, <<>>, Req2} signals end-of-body (the size-0 last chunk has
been seen).
For non-chunked framing (auto mode, content-length, or no body),
read_body_chunked/1 falls through to read_body/1's behavior — the
buffered body comes back in one shot. The "chunk boundary" concept
only applies to wire-level chunked transfer encoding.
Threading is the same as read_body/1,2: hand Req2 back to the
conn via the {Response, Req2} handler return shape so any unread
chunks get drained for keep-alive.
-spec read_form(request()) -> {ok, urlencoded, [{binary(), binary() | true}], request()} | {ok, multipart, [roadrunner_multipart:part()], request()} | {error, no_content_type | unsupported_content_type | no_boundary | term()}.
Read and parse a form-encoded request body. Inspects the request's
Content-Type and dispatches:
application/x-www-form-urlencoded[; …]→{ok, urlencoded, [{Name, Value | true}], Req2}. Values are percent-decoded (and+→ space) perroadrunner_qs:parse/1. Bare flags come back as{Name, true}.multipart/form-data; boundary=…→{ok, multipart, [Part], Req2}where eachPartis the map returned byroadrunner_multipart:parse/2(#{headers, body}).{error, no_boundary}if the boundary parameter is missing.
Other content types return {error, unsupported_content_type};
absent Content-Type returns {error, no_content_type}. Reads the
body via read_body/1 (so works in both auto and manual
buffering modes), and threads Req2 back so trailing body bytes
get drained on keep-alive.
Return the per-request correlation token attached by roadrunner_conn.
16 lowercase hex chars (8 bytes of CSPRNG output), unique per request
even on the same keep-alive connection. Mirrored into the conn
process's logger metadata, so any ?LOG_* call in middleware or
the handler is automatically annotated with the same id.
undefined for manually-constructed request maps used in tests.
-spec scheme(request()) -> http | https.
Return the connection scheme — http for plain TCP, https for TLS.
roadrunner_conn sets this once per connection from the transport tag.
Defaults to http for request maps constructed manually outside the
connection pipeline.
Return the opaque per-route handler state attached at compile time.
Sources, listed by route shape:
- 3-tuple
{Path, Handler, State}or map#{path, handler, state}list entry. - Listener single-handler
{Module, State}tuple or#{handler, state, ...}map.
Returns undefined for shapes that don't carry state (2-tuple route,
bare-atom single-handler, map without a state key).
Return the HTTP version tuple ({1,0} or {1,1}).