Expand description
The outbound HTTP policy (kernel spec §7.1; gateway spec §4, §5.7): every
request hennery itself sends to the network — the gateway’s proxy, its
OAuth calls, Web Push — goes through an EgressClient.
- Built once, cloned freely.
Egress::newbuilds itsreqwestclients once: one perAllowance, and a second, internal-only one for plainhttpunderAllowance::InternalNetwork.EgressandEgressClientare cheap to clone (reqwest::Clientis anArcinside) and share connection pools with their clones. The two allowances never share a pool: a pooled connection skips the resolver, so a public-only request must never ride one an internal-network request opened. - No way around the check. The only way to send is
EgressClient::sendorEgressClient::send_streaming, which runcheck_urlon the request’s URL first. Thereqwest::Clientinside is never handed out. A caller holding anhttp::Request(for example, rmcp’sOAuthHttpClient) converts it withRequest::try_fromand sends it here. - The URL check (
check_url):https, or plainhttpto loopback (a loopback literal orlocalhost); underAllowance::InternalNetworkalso plainhttpto an internal address or a name (plan 8b-ii, below). No credentials in the URL; an IP-literal host must be public underAllowance::PublicOnly. reqwest never asks the resolver about a literal, so this check is the only one a literal gets.url::Urlhas already normalised the odd IPv4 spellings (2130706433,0x7f.1,0177.0.0.1,127.1) to the address they name. - Names are resolved by hennery (the system resolver) and, under
PublicOnly, refused when any address is not public — not filtered — so one record pointing inward refuses the name. The connection then goes only to the addresses that were checked.localhostis never looked up: it is127.0.0.1and::1(RFC 6761), so plainhttpto it stays on this machine whatever the resolver or hosts file says. - Public (
is_public): IPv4 outside the special-purpose ranges (this network and0.0.0.0, RFC 1918, CGNAT, loopback, link-local including169.254.169.254, IETF protocol assignments, the documentation and benchmarking ranges, 6to4 relay anycast, multicast, reserved and broadcast); IPv6 inside global unicast2000::/3and outside its special ranges (2001::/23with Teredo and benchmarking, documentation2001:db8::/32and3fff::/20, 6to42002::/16). So::,::1, IPv4-mapped::ffff:0:0/96, NAT6464:ff9b::/96and64:ff9b:1::/48, unique-localfc00::/7, link-localfe80::/10and multicastff00::/8are never public. - Plain
httpinside the internal network (plan 8b-ii, the operator’s decision of 2026-10-02): only underAllowance::InternalNetwork, and only to internal addresses — RFC 1918, loopback and unique-local IPv6, except AWS’s metadata addressfd00:ec2::254. A public address stayshttpsonly even then, and so do the addresses that are neither: link-local and that metadata address (cloud metadata services answer plainhttpthere), CGNAT (it may be the carrier’s network), documentation, multicast,0.0.0.0, IPv4-mapped, NAT64, 6to4 and Teredo (they may lead to a public host). A literal is checked by the URL check; a name goes through a third client, used for nothing but plainhttpunderInternalNetwork, whose resolver refuses the name if any address is not internal. - Never a proxy from the environment (
HTTP_PROXY,HTTPS_PROXY,ALL_PROXY): it would take the checked connection elsewhere and hand it the request. Never a followed redirect: a 3xx is the caller’s answer. - Timeouts (
Timeouts): a connect timeout on every connection.EgressClient::sendbounds the whole exchange, body included, by the request’s own timeout or elseTimeouts::request.EgressClient::send_streamingbounds only the wait for the response head the same way; the caller reads the body for as long as it wants and decides for itself when a stream has been idle too long. A body that fails while it is read (send’s deadline included) fails with areqwest::ErrorfromResponse, not anEgressError: strip its URL withwithout_url()before logging it. - Errors (
EgressError) never carry the URL (its path or query can hold a secret), so they are safe to log. - Per-caller limits (
Limiter): a counter of permits per caller key (the gateway’s is the connection), refusing past its cap withBusyinstead of queueing. A caller keeps one for concurrent requests and one for open streams; the gateway answersBusywith 503.
Modules§
- header
- What a caller needs to build a request and read its answer, so it depends on the kernel, not on reqwest. HTTP header types
Structs§
- Busy
- A caller is over its cap.
- Egress
- The policy’s clients: one per
Allowance, and the internal-network one with a second, for plainhttp. - Egress
Client - Sends requests under one
Allowance; see the module docs. - Limiter
- At most
cappermits held at once per caller key. Clones share the counts. Only keys holding a permit are tracked, so the table is bounded by what is in flight. - Method
- What a caller needs to build a request and read its answer, so it depends on the kernel, not on reqwest. The Request Method (VERB)
- Permit
- One of a
Limiter’s permits; dropping it releases it. - Request
- What a caller needs to build a request and read its answer, so it
depends on the kernel, not on reqwest.
A request which can be executed with
Client::execute(). - Response
- What a caller needs to build a request and read its answer, so it
depends on the kernel, not on reqwest.
A Response to a submitted
Request. - Status
Code - What a caller needs to build a request and read its answer, so it
depends on the kernel, not on reqwest.
An HTTP status code (
status-codein RFC 9110 et al.). - Timeouts
- The policy’s timeouts.
- Url
- What a caller needs to build a request and read its answer, so it depends on the kernel, not on reqwest. A parsed URL record.
Enums§
- Allowance
- Whether a request may reach non-public addresses.
- Body
Error - Why
read_cappeddid not return a body. - Egress
Error - A request that did not get a response.
- Refused
- Why the policy refused a request.
Functions§
- check_
url - The URL check every request passes before it is sent; see the module docs. A name is checked later, by the resolver, once it has addresses.
- is_
https_ or_ loopback https, or plainhttpto loopback: the scheme rule for OAuth’s URLs (gateway spec §4, §5.7), which stays this even for a connection marked “internal network”, whose clientcheck_urllets send plainhttpto internal addresses (plan 8b-ii). The OAuth caller checks it itself before sending (plan 8f).- is_
public - Whether
addris a public address; see the module docs. - read_
capped response’s body, refused pastmaxbytes: a declared length over it is refused before anything is read, and the read stops at the first chunk past it.EgressClient::sendbounds a request’s time, not its size; this is the size (the egress plan’s O3), for every caller that reads a whole body (OAuth’s documents and token responses, plan 8f).