Repository navigation
Releases
Releases · rasuvaeff/pinned-http-client
v1.0.0
v0.3.0
- BC: a host that does not resolve throws the new
ResolutionFailed
(NetworkExceptionInterface) instead ofRequestRefusedwith
Refusal::Unresolvable(the case is removed). The system resolver cannot
tell NXDOMAIN from SERVFAIL or a timeout, so the failure may be temporary
and callers that retry network failures now retry it (found by the
cska-one pilot: link previews of a briefly unresolvable host were parked
for a week as permanent).
v0.2.0
- Security:
send($request, ['stream' => true])silently undid the
pinning in 0.1.0: Guzzle's default client hands streamed requests to its
stream handler, which ignoresCURLOPT_RESOLVEand resolves the name again
(DNS rebinding). Caller-suppliedcurloptions (CURLOPT_FOLLOWLOCATION,
CURLOPT_CONNECT_TO,CURLOPT_PROXY, …), a per-requesthandlerand an
injected Guzzle client could bypass it too, and the default client used
proxies from the environment. All of these paths are gone, each with a
real-connection test. - BC: the client builds its own transport (cURL handler only). Removed:
theguzzle:constructor parameter andsend($request, $options); use
sendRequest(). The resolver is aResolverinterface instead of a
Closure(resolver: new MyResolver()). - BC:
PinningFailedis replaced by an abstractClientException
(ClientExceptionInterface,getRequest()) withRequestRefused
(RequestExceptionInterface,$reasonof the newRefusalenum),
TransferFailed(NetworkExceptionInterface),ResponseTooLargeand
TooManyRedirects. Only Guzzle transfer exceptions are wrapped; anything
else propagates. Refusal messages changed wording, still without addresses. maxBodyBytes(defaultPinnedClient::DEFAULT_MAX_BODY_BYTES, 10 MiB;
nullfor none): the decompressed body is bounded, the transfer cut at
the limit.withMaxBodyBytes(),withTimeouts(); timeouts and the limit
are validated.proxy:— an explicit, opt-in proxy; environment proxies are never used.RedirectFollower: follows redirects through the pinned client (every
hop re-checked), 303/301/302-POST → GET, credentials dropped across
origins,maxRedirects(default 5).SystemResolver(the default): IPv4 throughgethostbynamel()plus IPv6
AAAA records — 0.1.0 was IPv4-only.PublicAddressesalso refuses::/96(IPv4-compatible),::ffff:0:0:0/96
(SIIT) and the3fff::/20documentation range.- Requires
guzzlehttp/psr7^2.7 directly. - CI: property regression corpus restored and saved around the coverage run;
the real-connection tests fail instead of passing empty when the test
server cannot start.
v0.1.0
PinnedClient: PSR-18 client that resolves the host, checks every address with anAddressPolicyand pins the connection to the checked addresses (CURLOPT_RESOLVE); no redirects, only http(s),send()takes extra Guzzle options that cannot override the pinning.PublicAddresses: the default policy (private, loopback, link-local, CGNAT, documentation, multicast and reserved ranges refused; IPv4 inside IPv6 judged as the embedded IPv4).PinningFailed: aNetworkExceptionInterfacecarrying the request and the cause.