Fetch controls outbound HTTP requests
link-fetch is the one HTTP client Link's own calls go out on: to the
account service, to a relay, to a service of Link's. Every call gets
the same rules, and only typed data crosses the wire. What an agent
fetches (a page, a model) doesn't go through it.
The rules every call gets
Client is the client calls go out on, built by a Builder that says
what it allows, and it carries these rules to each call (Request).
Its user agent and timeouts
Link's user agent, lnk/<version> (USER_AGENT), and timeouts:
TIMEOUT, 30 seconds for a whole call, connecting to the last byte of
its answer, unless the caller says another, and CONNECT_TIMEOUT, 10
seconds to connect.
No redirects
A redirect is an error (Error::Redirected): one would carry a
credential, or a call, somewhere else.
https:// only
Or http:// to this machine (is_this_machine), a relay or a service
of one's own for development: anywhere else a credential would cross
the network in the clear (Error::Insecure). A plain http:// call
goes through no proxy, and its name is never asked of DNS: localhost
and the names under it are this machine's loopback addresses
(Loopback), so a network's DNS can't send it elsewhere.
An answer's size capped
MAX_ANSWER, 1 MiB, or the call's own Request::limit, read so: a
longer one is an error, never read whole first. Streamed reads an
answer as a stream instead.
Typed both ways
A request's body is a Serialize type, an answer a Deserialize type
(Request::answer), and every answer is closed: a field its type
doesn't name is refused as deny_unknown_fields would, whether or not
the type says so. An answer that doesn't parse is an error naming the
route (Error::Unexpected), never a guess.
Errors map once
401 to signed out (Error::SignedOut), 429 to try again later
(Error::Later, with its Retry-After), a 5xx to the service's fault
(Error::Failed), any other refusal with what it said
(Error::Refused). None prints a credential, a query string or a
value the answer held: a route is named without a secret (Route).
Credentials as Secrets
Credentials go in as Secrets (Request::bearer, Request::basic),
into headers marked sensitive; nothing here prints one.
Where a call may go
HttpsUrl and SendUrl are the URLs a setting names, checked as it's
read: this machine's addresses and public ones, and how a host is
found (Loopback).
blocking
The same client, for a program that doesn't run on a runtime of its
own (a command, a sync service): every call made as Client makes it,
on a runtime this client keeps, and waited for. The same rules hold,
the same errors come back. Like reqwest's own, it can't be called from
a task on another runtime.
The audit
Every folder runs it over its own code, from a test of its own
(cargo test -p link-fetch --test clients for this one): an HTTP
client is built only in link-fetch, or where the folder's list says
why (a model's provider, what an agent fetches, a test's fixture). A
new one fails until it's made a Client or listed, which a review
sees.
What it finds
In code that isn't a test's (a file under a tests/ folder, or from a
#[cfg(test)] module on), however it's laid out over lines: reqwest's
client made (Client::new(), ::builder(), ::default(), the
blocking ones too) or its ClientBuilder named at all, by reqwest's
path, by a name a use of reqwest brought in, or through the crate
renamed (use reqwest as http).
What it can't see
Being a reading of the text and not of Rust's names: a client made in a
macro's expansion, through another crate that re-exports reqwest or
wraps its client, through a type alias (type Http = reqwest::Client),
or by Default::default() where only the type says what it is. A
review sees those.
clients.toml
The list is TOML: [clients] maps a file, relative to the folder, to
why its client isn't one of Link's own calls.
Why it works this way
Why Link's calls share one client, and read answers closed, is on Fetch Decisions.