Repository navigation
What's Changed
- Do not write the transport cache from a reconnecting dial by @Mootjelh in #270
- reworked and restructured examples by @bogdanfinn in #271
- Key the transport cache by the port the scheme implies by @Mootjelh in #272
- CONNECT headers follow the given order by @Mootjelh in #274
- feat: add WithCertificatePinner option for custom certificate validation by @tahafatih in #278
- Expose HTTP/2 ReadIdleTimeout and PingTimeout in TransportOptions by @titwn in #282
- feat: generate the Chrome trust anchors from the Chrome Root Store by @nihiloid in #277
- Add CI for the tests by @ayn2op in #286
- Expose WebSocket over the shared library (wsConnect / wsRead / wsWrite / wsClose / wsStats) by @marinionroids in #284
- Bound the HTTP/2 transport's redial by the client timeout by @datawisebets in #287
- fix(transport): handle non-ASCII hosts and stale stashed connections by @roachadam in #291
- fix(proxy): bound proxy dials by the request context and timeout by @roachadam in #292
- Bump andybalholm/brotli to v1.2.7 (CVE-2026-111497) by @pxCaptcha in #293
- Add ResponseHeaderTimeout to TransportOptions by @pagpeter in #294
- Add the trust_anchors extension to Chrome 150 profiles by @reverseSHA256 in #297
- Percent-encode invalid bytes in request URLs before they hit the wire by @reverseSHA256 in #298
- Add Chrome 154 and Chrome 154 PSK profiles with sorted trust anchors by @nihiloid in #301
- Add Safari 27.2 desktop TLS and HTTP/2 profile by @reverseSHA256 in #299
New Contributors
- @tahafatih made their first contribution in #278
- @titwn made their first contribution in #282
- @ayn2op made their first contribution in #286
- @marinionroids made their first contribution in #284
- @datawisebets made their first contribution in #287
- @roachadam made their first contribution in #291
- @pxCaptcha made their first contribution in #293
- @pagpeter made their first contribution in #294
- @reverseSHA256 made their first contribution in #297
There was no separate release for 1.17.x, so this release covers everything since 1.16.0.
Breaking Changes
- Go 1.27 or newer is required (tls-client, fhttp, utls, quic-go-utls and websocket).
- The license changed to BSD-3-Clause. The advertising clause of the previous BSD-4-Clause license no longer applies.
HttpClienthas a new methodClose(). Custom implementations and mocks of the interface have to add it.- The default
Accept-Encodingnow includes zstd:gzip, deflate, br, zstd. - HTTP/1.1 responses are now decompressed automatically based on
Content-Encoding, also when you setAccept-Encodingyourself (as HTTP/2 already did). CallingDecompressBodyon such a response is a no-op. If you read the compressed bytes yourself, setDisableCompression: truein theTransportOptions. chrome_150andchrome_150_PSKnow send the trust_anchors extension and match real Chrome 150 (JA4t13d1517h2_8daaf6152771_cb7bf5808d99).chrome_150is the default profile, so the default fingerprint changes.- HTTP/3: every profile except Firefox sends
SETTINGS_MAX_FIELD_SECTION_SIZEagain (a regression in 1.16.0).
New Features
WithCertificatePinnerfor custom certificate validation (subject, SAN, issuer, ...). It takes precedence overWithCertificatePinning.TransportOptions.ReadIdleTimeoutandPingTimeoutfor HTTP/2 health check PINGs, which keep idle connections open.TransportOptions.ResponseHeaderTimeoutlimits the wait for response headers over HTTP/1.1 and HTTP/2.HttpClient.Close()releases all transports, including the UDP sockets of HTTP/3, whichCloseIdleConnections()keeps open.- WebSocket option
WithEnableCompression()(permessage-deflate). - New package
trust_anchors, generated from the Chrome Root Store.profiles.BuildTrustAnchorsPayloadis deprecated, usetrust_anchors.BuildPayload. - Invalid bytes in URL queries (spaces, control characters, non-ASCII) are percent-encoded before sending, as browsers do.
Content-Length,Transfer-EncodingandTrailerare written under the spelling you used in the request headers.- CONNECT headers follow
http.HeaderOrderKeyregardless of case, and are sorted alphabetically without one.
New Profiles
- Chrome 154 (chrome_154) & Chrome 154 PSK (chrome_154_PSK), with sorted trust anchors like real Chrome 154+
- Safari 27.2 desktop (safari_27_2), contributed
Shared Library & Standalone API
- WebSocket support:
wsConnect,wsRead,wsWrite,wsClose,wsStatsin the shared library, and/api/ws/connect,/api/ws/read,/api/ws/write,/api/ws/close,/api/ws/statsin the standalone API - New
transportOptionsfieldsreadIdleTimeout,pingTimeoutandresponseHeaderTimeout - Clients of requests without
sessionIdare now closed after the request.destroySession/destroyAlland/api/free-session//api/free-allclose the clients of the freed sessions. Before, every one of them leaked a UDP socket and several goroutines when HTTP/3 was used.
Bug Fixes
- HTTP/3 transports of lost or failed protocol races are closed, and the winning transport is reused instead of building a new one
- Proxy dials (HTTP, HTTPS, SOCKS4, SOCKS5) and the CONNECT request are bounded by the client timeout and the request context. A stalled proxy no longer hangs the client.
WithTimeoutSeconds(0)no longer makes every request through an HTTP proxy fail immediately- HTTPS proxies now respect
WithDialerandWithLocalAddr - HTTP/2 redials are bounded by the client timeout (
DefaultTimeoutSecondswhen the timeout is 0) - Hosts with non-ASCII characters (IDN) work, and a stale stashed connection no longer causes a panic and a deadlocked client
- The transport cache is keyed by the port the scheme implies, which fixes https → http redirects
- Reconnecting dials no longer write the transport cache (data race)
- No empty
User-Agent:line is sent on HTTP/1.1 when the header is set to nil or "" - Deflate bodies are decompressed when they are read, and closing an HTTP/2 response body is idempotent
- An HTTP/2 connection that serves only one request now works when its first stream ID is not 1
- brotli bumped to v1.2.7 (CVE-2026-111497)
Dependencies
- utls v1.8.2-barnius (rebased on upstream), fhttp v0.7.3, quic-go-utls v1.0.13-utls, websocket v1.5.9-barnius
Known Issues
Both only affect clients that actually use HTTP/3, so a client without WithProtocolRacing() is unaffected.
- Only chrome_144, chrome_144_PSK, firefox_147, firefox_147_PSK and firefox_148 carry their own HTTP/3 settings. Every other profile sends a minimal SETTINGS frame that does not match the browser it imitates, and its two settings go out in random order per connection. TLS and HTTP/2 fingerprints are unaffected. Use one of those five profiles, or set WithDisableHttp3() if the HTTP/3 fingerprint matters.
- Both racing legs share one *http.Request, which is a data race on the header map. It shows up once many requests race at the same time and can crash the process. Prefer WithDisableHttp3() for high concurrent volume.
Full Changelog: v1.16.0...v1.18.1