Repository navigation
Releases
v2.16.0
Highlights
πͺ Faster requests with large cookie jars
Building the Cookie header no longer scans every cookie in the jar. The client reuses its jar instead of copying it on every request and redirect (#1284), only looks up the domains that can match the request host, and skips the expired cookie sweep until a cookie is due (#1285). With 1,000 cookies across 500 domains, building the Cookie header is about 18 times faster.
Cookies from different domains are now sent from the least to the most specific domain, for example .example.org before sub.example.org, instead of in the order the domains were added. Cookies with longer paths still come first.
httpx2
Changed
- Look up only the cookie domains that match the request host, and skip the expired cookie sweep until a cookie is due. With 1,000 cookies across 500 domains, building the
Cookieheader is about 18 times faster. Cookies from different domains are now sent from the least to the most specific domain (#1285).
Fixed
- Reuse the client cookie jar instead of copying it on every request and redirect. A custom policy set with
client.cookies.jar.set_policy()now applies to outgoing requests (#1284).
httpcore2
No changes since 2.15.1. Version bumped to stay in lockstep with httpx2.
Full Changelog: v2.15.1...v2.16.0
v2.15.1
Highlights
π Flat CPU usage for long-lived clients on Linux
On Linux, the default SSL context is now configured once instead of on every handshake (#1253). With OpenSSL older than 3.4, each handshake added a duplicate certificate lookup path, so CPU usage per request grew over the lifetime of a reused client. Certificate verification is unchanged, and Windows and macOS still use truststore.
httpx2
Fixed
- Configure the default SSL context once on Linux, instead of on every handshake. With OpenSSL older than 3.4, CPU usage grew over the lifetime of a reused client (#1253).
httpcore2
Fixed
- Configure the default SSL context once on Linux, instead of on every handshake. With OpenSSL older than 3.4, CPU usage grew over the lifetime of a reused client (#1253).
Full Changelog: v2.15.0...v2.15.1
v2.15.0
Highlights
π Python 3.11+ required
httpx2 and httpcore2 no longer support Python 3.10 (#1274). There are no other changes in this release.
httpx2
Removed
- Drop support for Python 3.10 (#1274).
httpcore2
Removed
- Drop support for Python 3.10 (#1274).
Full Changelog: v2.14.0...v2.15.0
v2.14.0
Highlights
π CIDR ranges in NO_PROXY
NO_PROXY and mounts now match IP CIDR ranges like 192.168.0.0/16 and [fe80::]/10, so any address in the range bypasses the proxy (#1165). Bracketed IPv6 addresses like [::1]:8080 are accepted, and unparseable NO_PROXY entries are ignored instead of failing client creation (#1267).
π FIPS-enforced Python support
httpx2 now imports on FIPS-enforced Python builds without hashlib.md5. DigestAuth raises ProtocolError only when the server asks for an unavailable algorithm (#1130).
π Sturdier connections and WebSocket shutdown
HTTP/2 reads no longer block when a server lowers SETTINGS_MAX_CONCURRENT_STREAMS mid-flight (#1217), and writing after a peer closes TLS without close_notify raises WriteError (#1263). Sync WebSocket sessions no longer hang on exit with a full event queue (#1123), and ASGI WebSocket reads after app shutdown no longer leak anyio exceptions (#1233).
httpx2
Added
- Match IP CIDR ranges, like
192.168.0.0/16and[fe80::]/10, inNO_PROXYandmounts. Requests to any address in the range now bypass the proxy; previously only the network address itself did (#1165). - Accept bracketed IPv6 addresses, like
[::1]and[::1]:8080, inNO_PROXY(#1267).
Changed
- Raise
InvalidURLfor amountskey with an IP host followed by anything other than a valid CIDR prefix, likeall://10.0.0.0/33(#1165).
Fixed
- Ignore
NO_PROXYentries that cannot be parsed, instead of raisingInvalidURLwhen the client is created (#1267). - Import
httpx2on FIPS-enforced Python builds withouthashlib.md5.DigestAuthraisesProtocolErrorwhen the server asks for an unavailable algorithm (#1130). - Handle reads after an ASGI WebSocket app shuts down, instead of leaking
anyioexceptions (#1233). - Stop the sync WebSocket session from hanging on exit when its event queue is full (#1123).
httpcore2
Fixed
- Keep
CONNECTand absolute-form proxy targets when the request sets thetargetextension (#1262). - Stop blocking reads when an HTTP/2 server lowers
SETTINGS_MAX_CONCURRENT_STREAMSwhile requests are in flight (#1217). - Raise
WriteErrorinstead ofanyio.EndOfStreamwhen writing after the peer closes a TLS connection withoutclose_notify(#1263).
Full Changelog: v2.13.1...v2.14.0
v2.13.1
Highlights
π€ Accurate file upload lengths
Passing a file as content= now calculates Content-Length from its remaining bytes, respecting the current file position (#1214).
π Reliable proxy TLS and HTTP/2 negotiation
TLS hostname overrides now apply inside HTTP proxy tunnels without affecting the proxy's own TLS connection (#1223). HTTP/2 is advertised first when enabled, and HTTP/1.1 is omitted when disabled (#1155).
π§Ή Clean WebSocket shutdown
The sync WebSocket keepalive thread now exits cleanly when a ping races with connection shutdown (#1228).
httpx2
Fixed
- Calculate
Content-Lengthfrom the remaining bytes when a file is passed ascontent=, respecting its current position (#1214). - Stop the sync WebSocket keepalive thread cleanly when a ping races with connection shutdown (#1228).
httpcore2
Fixed
- Honor the
sni_hostnameextension for TLS inside HTTP proxy tunnels without applying it to the proxy's TLS connection (#1223). - Prefer HTTP/2 during TLS protocol negotiation when enabled, and stop advertising HTTP/1.1 when it is disabled (#1155).
Full Changelog: v2.13.0...v2.13.1
v2.13.0
Highlights
π Reliable TLS verification controls
The CLI --no-verify flag now disables TLS certificate verification as intended, and --verify provides an explicit counterpart (#1140, #1186).
π§Ή Safer async stream cleanup
Stopping a streamed response early no longer risks a nested async generator finalization error (#1204).
httpx2
Changed
- Require
brotlicffi1.2.0.2 or later for thebrotliextra on non-CPython implementations in #1179
Fixed
- Make the
--no-verifyCLI flag disable TLS certificate verification and add an explicit--verifycounterpart in #1140 and #1186 - Avoid nested async generator finalization errors when streamed responses are abandoned early in #1204
httpcore2
Changed
- Require Trio 0.34.0 or later for the
trioextra in #1179
Fixed
- Avoid nested async generator finalization errors when streamed responses are abandoned early in #1204
Full Changelog: v2.12.0...v2.13.0
v2.12.0
Highlights
π‘οΈ Bounded response decompression
httpx2 now decodes gzip, deflate, Brotli, and Zstandard responses incrementally. Each decode step emits at most 1 MiB, so streaming a highly compressed response no longer requires materializing an entire inflated network chunk in memory (#1126).
π¦ Shared Zstandard API
Python 3.13 and earlier now use backports.zstd, which provides the same bounded incremental decompression API as compression.zstd on Python 3.14 and later (#1146).
httpx2
Changed
Fixed
- Bound peak memory while streaming compressed responses and close response streams when decoding fails by @Kludex in #1126
httpcore2
No changes since 2.11.0. Version bumped to stay in lockstep with httpx2.
Full Changelog: v2.11.0...v2.12.0
v2.11.0
Highlights
π Public origin API
httpx2 now includes an immutable and hashable Origin value object, available through URL.origin. It provides normalized scheme, host, and effective port comparisons without including URL paths, queries, fragments, or credentials (#1134).
π οΈ Request compatibility and validation
- Explicit
Transfer-Encodingheaders now take precedence over body-derivedContent-Lengthheaders (#1137). - Deprecated status code aliases are available again (#1135).
- Multipart part headers are validated before serialization (#1142).
httpx2
Added
Changed
Fixed
- Restore deprecated status code aliases by @Kludex in #1135
- Extract HTTP/2 release notes from changelog headings correctly by @Kludex in #1136
- Respect explicit
Transfer-Encodingheaders and expose buffered request body lengths to WSGI applications by @Kludex in #1137 - Validate multipart part header names and values before serialization by @Kludex in #1142
httpcore2
Changed
- Cache sniffio availability instead of importing it on every synchronization call by @mbeijen in #1132
Full Changelog: v2.10.0...v2.11.0
v2.10.0
Highlights
π Performance and memory improvements
- Sending large HTTP/2 request bodies no longer copies the body quadratically - sending a 256 MiB body went from ~36s to under 0.1s (#1127).
- SSE parsing is up to 35x faster on highly fragmented streams (#1117).
- Cookie extraction is now skipped for responses without a
Set-Cookieheader, making typical requests roughly 8% faster (#1107).
πΈοΈ WebAssembly / Emscripten support
httpx2 now runs on Pyodide / Emscripten, using a JavaScript fetch-based transport defined in httpx2-jsfetch (#1119, #1114). Thanks @hoodmane!
httpx2
Added
- Add support for running on WebAssembly / Emscripten via Pyodide by @hoodmane in #1119
- Add
max_event_sizeto cap SSE event buffering by @Kludex in #1071 - Add RFC 9110 status code constants by @mbeijen in #1069
- Add support for Python 3.15 by @hugovk in #1090
Changed
- Improve SSE chunk buffering performance by @Kludex in #1117
- Skip cookie extraction without
Set-Cookieby @Kludex in #1107 - Return
str | Noneinstead ofAnyfromHeaders.getby @ItsDrike in #1121
Fixed
- Enforce WebSocket max message size across fragments by @Kludex in #1085
- Ignore unsolicited and duplicate Pong frames by @Kludex in #1122
httpcore2
Added
Changed
Fixed
- Propagate the original exception instead of raising
KeyErrorwhen an HTTP/2 stream fails by @yhay81 in #1093 - Start TLS for the
wssscheme in SOCKS5 proxy connections by @Kludex in #1104
π New Contributors
- @ccbest made their first contribution in #1096
- @dependabot[bot] made their first contribution in #1103
- @bagowix made their first contribution in #1111
- @aldbr made their first contribution in #1108
- @dsfaccini made their first contribution in #1110
- @yhay81 made their first contribution in #1093
- @laisbsc made their first contribution in #1092
- @hoodmane made their first contribution in #1114
- @ItsDrike made their first contribution in #1121
Full Changelog: v2.9.1...v2.10.0