NewYour coding agent can read the release notes before it upgrades.Set up the MCP server →
PyPI · #3282 most downloaded on PyPI
urllib3.future is a powerful HTTP 1.1, 2, and 3 client with both sync and async interfaces
Last release 6 days ago
22 Sep 2026
Ships fairly regularly
a new release about every 2 weeks
Nearly every release is documented
notes for 60 of the last 60 stable releases
1 version withdrawn
withdrawn after publishing
3 years old
174 releases · first in 2023
One column per quarter.
Further improved compatibility with some third party programs that accessed hazardous materials within http.client standard library.
Relaxed constraints around HTTPConnectionPool._new_conn private method in order to ensure a broader compatibility.
HTTPConnectionPool._new_conn private method in order to ensure a broader compatibility. (#122)Fixed unset tls_version within ConnectionInfo when using the legacy TLSv1 protocol.
tls_version within ConnectionInfo when using the legacy TLSv1 protocol.OP_NO_TLSv1_3 option that did not disable HTTP/3.assert_hostname=False parameter not forwarded to QUIC configuration.Fixed the ability to override properly the :authority special header via the legacy Host header.
:authority special header via the legacy Host header.Removed workaround for a bug that existed in qh3 < 1.0 with cryptography in a concurrent (thread) environment.
preemptive_quic_cache MutableMapping to exclude endpoints.
If your implementation discard the recently set key/entry it will prevent the connection from upgrading itself.Improve (large) data download performance by increasing the default blocksize.
Improve traffic_state_of function to improve the overall performance in a highly concurrent context.
traffic_state_of function to improve the overall performance in a highly concurrent context.Passing a ssl context containing manually loaded root certificates no longer is ignored with HTTP/3 over QUIC.
Overall performance improvement with HTTP/2 in a highly concurrent context.
Added support for jh2>=5,<6 instead of h2~=4.0 as a drop-in replacement. Expect a significant performance improvement with HTTP/2. We successfully red
jh2>=5,<6 instead of h2~=4.0 as a drop-in replacement.
Expect a significant performance improvement with HTTP/2. We successfully reduced our dependency footprint to the minimum.Added support for qh3 version v1
Removed warning about "unresponsive" pool of connection due to how it can confuse users.
Fixed a rare racing condition occurring on PyPy when using DNS-over-HTTPS leading to a socket.gaierror exception.
cert_reqs=0 aka. disabled TLS over TCP verification.Fixed an edge case with Response::read() confusing situation where passing a positive amount to read then passing None n-times would continuously retu
None n-times would continuously return cached data if the stream was closed (content consumed).expected that did not contain the "remaining" amount expected but rather
the total expected.Added Happy-Eyeballs support. This feature is disabled by default, you can enable it by passing happy_eyeballs=True into AsyncPoolManager, AsyncHTTPCo
happy_eyeballs=True
into AsyncPoolManager, AsyncHTTPConnectionPool or its synchronous counterparts.
See the documentation to learn more.Fixed SSL context cache construction that did not take key_password into account.
NotImplemented instead of raising NotImplementedError to avoid polluting the stack trace when trying to
initialize the external tls layer when not concerned (e.g. not http3 over QUIC).Fixed traffic police shutdown procedure to avoid killing needlessly a new connection or pool.
Overall performance improvements for both async and sync calls.
TrafficPolice internal caching for obj states of contained elements due to its inability to be up-to-date in some cases.qh3 library (HTTP/3 only).Overall performance improvements for both async and sync calls.
Fixed PyPy error when running asynchronous code on Windows after trying to create a datagram socket. This error is due to an incomplete implementation
get_response from either PoolManager or ConnectionPool with anything else than a ResponsePromise.Fixed blocking IO just after HTTP/3 is negotiated in an asynchronous context.
ConnectionInfo).Added full asynchronous support using asyncio. urllib3.future officially support asyncio as his asynchronous scheduler. The following public classes a
Added full asynchronous support using asyncio. urllib3.future officially support asyncio as his asynchronous scheduler. The following public classes are immediately available:
AsyncPoolManager, AsyncHTTPConnectionPool, AsyncHTTPSConnectionPool, AsyncProxyManager,
AsyncResolverDescription.
Finally, bellow functions are also available:
async_proxy_from_url, and async_connection_from_url.
Explore the documentation section about async to learn more about this awesome feature with detailed examples. No extra dependencies are required. We rely exclusively on the standard library.
Async SOCKS proxies are also supported at no additional costs with contrib.socks.AsyncSOCKSProxyManager.
Improved reliability with PoliceTraffic.borrow with type as indicator when heavily accessed by many threads.
Fixed an edge case where a simultaneous call to get_response() without a specific promise could lead to a non-thread safe operation.
get_response() without a specific promise could lead to a non-thread safe operation.Fixed missed clean-up of unused PoolKey stored in PoliceTraffic upon a full PoolManager.
PoliceTraffic upon a full PoolManager.Fixed missed cleanup of unused PoolKey stored in PoliceTraffic upon a full PoolManager.
Fixed a compatibility issue with boto3 when trying to send data (got an unexpected keyword argument). #79
boto3 when trying to send data (got an unexpected keyword argument). #79We are, effective immediately, deprecating RecentlyUsedContainer in favor of our internal PoliceTraffic that was used in PoolManager.
RecentlyUsedContainer
in favor of our internal PoliceTraffic that was used in PoolManager.Queue to manage the Connection in HTTPConnectionPool.
If you try to set HTTPConnectionPool.QueueCls it will raise a deprecation warning.
Starting today, we no longer accept implementation like queue.Queue because it
cannot fit the need of this complex HTTP client, especially with the multiplexing aspect.Fixed a rare case of HTTP/3 being disabled when forwarding a custom SSLContext created.
DEFAULT_CIPHERS constant in urllib3.util.ssl_ due to the demands.
It contains the Mozilla recommended cipher suite that was introduced in version 2.2.900.request_sent_latency that wasn't computed when request was stopped early (prior to sending the
complete body).Fixed an edge case where a HTTPS record was misinterpreted when using a DNS-over-HTTPS resolver.
Fixed an issue where a idle QUIC connection would not be recycled properly when expired.
-1 as the amt in HTTPResponse (read, or stream) as the strict equivalent of read1.
This allows you to fetch content as soon as it arrive._handle_chunk, _update_chunk_length from HTTPResponse.HTTPResponse that hung until the complete content was downloaded.Fixed an issue where setting None for a header value could cause an exception.
Fixed compatibility with older PyPy 3.7 interpreters when HTTP/3 (qh3) can be unavailable.
Fixed an issue where a stateless resolver (e.g. null resolver, in-memory resolver, ...) could not be recycled.
Fixed an issue where a stateless resolver (e.g. nullresolver) could not be recycled.
Fixed an issue where one would attempt to close a resolver multiple times.
Deprecated function util.connection.create_connection(..) in favor of newly added contrib.resolver that will host from now on that function within Bas…
Added issuer certificate extraction from SSLSocket with native calls with Python 3.10+ in ConnectionInfo.
Added support for DNS over TLS, DNS over HTTPS, DNS over QUIC, DNS over UDP, and local hosts-like DNS. PoolManager, and HTTPPoolManager constructor now expose an additional keyword argument, resolver=.... You can assign to it one of the presented protocols. Also, you may chain a list of resolvers, each can be limited to a list of host-pattern or not. The default is the system DNS. Our thread-safety promise covers this new feature.
You can now do the following: PoolManage(resolver="doh://dns.google") for example. Please take a look at the official documentation to learn about the full capabilities.
Support for SOCKS proxies is now provided by python-socks instead of PySocks due to being largely unmaintained within a reasonable period. This change is made completely transparent.
Added details in ConnectionInfo about detailed timings and other details.
established_latency is a timedelta that represents the amount of time consumed to get an ESTABLISHED network link.
resolution_latency is a timedelta that represents the amount of time consumed for the hostname resolution.
tls_handshake_latency is a timedelta that represents the amount of time consumed for the TLS handshake.
request_sent_latency is a timedelta that represents the amount of time consumed to encode and send the whole request through the socket.
Fixed a rare thread safety issue when using at least one HTTP/3 multiplexed connection.
Deprecated function util.connection.create_connection(..) in favor of newly added contrib.resolver that will host from now on that function within BaseResolver as a method. Users are encouraged to migrate as soon as possible.
Support for preemptively negotiating HTTP/3 over QUIC based on RFC 9460 via an HTTPS DNS record.
Added support for enforcing IPv6, and/or IPv4 using the keyword parameter socket_family that can be provided in
PoolManager, HTTP(S)ConnectionPool and HTTP(S)Connection. The three accepted values are socket.AF_UNSPEC
socket.AF_INET, and socket.AF_INET6. Respectively, allow all, ipv4 only, and ipv6 only. Anything else will raise
ValueError.
Added issuer certificate extraction from SSLSocket with native calls with Python 3.10+ in ConnectionInfo.
Added support for DNS over TLS, DNS over HTTPS, DNS over QUIC, DNS over UDP, and local hosts-like DNS. PoolManager, and HTTPPoolManager constructor now expose an additional keyword argument, resolver=.... You can assign to it one of the presented protocol. Also, you may chain a list of resolver, each resolver can be limited to a list of host-pattern or not. Default is the system DNS. This new feature is covered by our thread-safety promise.
You can now do the following: PoolManage(resolver="doh://dns.google") for example. Refer to the official documentation to learn about the full capabilities.
Support for SOCKS proxies is now provided by python-socks instead of PySocks due to being largely unmaintained within a reasonable period of time. This change is made completely transparent.
Added details in ConnectionInfo about detailed timings and others details. established_latency is a _timedelta_ that represent the amount of time consumed to get an ESTABLISHED network link. resolution_latency is a _timedelta_ that represent the amount of time consumed for the hostname resolution. tls_handshake_latency is a _timedelta_ that represent the amount of time consumed for the TLS handshake. request_sent_latency is a _timedelta_ that represent the amount of time consumed to encode and send the whole request through the socket.
Fixed a rare thread safety issue when using at least one HTTP/3 multiplexed connection.
Deprecated function util.connection.create_connection(..) in favor of newly added contrib.resolver that will host from now on that function within BaseResolver as a method. Users are encouraged to migrate as soon as possible.
Support for preemptively negotiating HTTP/3 over QUIC based on RFC 9460 via a HTTPS DNS record.
Added support for enforcing IPv6, and/or IPv4 using the keyword parameter socket_family that can be provided in PoolManager, HTTP(S)ConnectionPool and HTTP(S)Connection. The three accepted values are socket.AF_UNSPEC socket.AF_INET, and socket.AF_INET6. Respectively, allow all, ipv4 only, and ipv6 only. Anything else will raise ValueError.
Fixed an issue where specifying cert_reqs=ssl.CERT_NONE or assert_hostname was ignored when using HTTP/3 over QUIC.
cert_reqs=ssl.CERT_NONE or assert_hostname was ignored when using HTTP/3 over QUIC.Small performance improvement while in HTTP/1.1
Content-Type: text/plain; charset=utf-8 for safety, unless
you specify a Content-Type header yourself. The charset parameter will always be set to utf-8.
It is recommended that you pass bytes instead of a plain string. If a conflicting charset has been set that
does not refer to utf-8, a warning will be raised.urlopen, and request named on_upload_body that enables you to track
body upload progress for a single request. It takes 4 positional arguments, namely:
(total_sent: int, total_to_be_sent: int | None, is_completed: bool, any_error: bool)
total_to_be_sent may be set to None if we're unable to know in advance the total size (blind iterator/generator).ProtocolError was raised instead of expected IncompleteRead exception.PoolManager.
If the PoolManager is instantiated with num_pools=10, each (managed) subsequent pool will have maxsize=10.Disabled unsafe renegotiation option with TLS by default where applicable.
urllib3_future in addition to urllib3. This became increasingly needed as a significant number of projects require urllib3 and accidentally override this fork.Reverted relying on qh3 to dynamically retrieve the max concurrent streams allowed before connection saturation.
qh3 to dynamically retrieve the max concurrent streams allowed before connection saturation.Bumped minimum requirement for qh3 to version 0.14.0 in order to drop private calls in contrib.hface.protocols._qh3.
qh3 to version 0.14.0 in order to drop private calls in contrib.hface.protocols._qh3.parse_url function calls as it is costly.socket.recv to pull conn.blocksize bytes regardless of Response.read(amt=...).Fixed loss of a QUIC connection due to an inappropriate check in conn.is_connected.
conn.is_connected.Fixed concurrent/multiplexed request overflow in a full connection pool.
Improved overall performances in HTTP/2, and HTTP/3, with or without multiplexed.
Fixed QUIC connection not taking cert_data due to an accidental variable override.
cert_data due to an accidental variable override.Fixed several issues with multiplexing. (i) Fixed max concurrent streams in HTTP/2, and HTTP/3. (ii) Fixed tracking of unconsumed response prior to tr
EarlyResponse exception 'signal'.Fixed several issues with multiplexing. (i) Fixed max concurrent streams in HTTP/2, and HTTP/3. (ii) Fixed tracking of unconsumed response prior to try upgrade the connection (to HTTP/3). (iii) Fixed (always) releasing multiplexed connections into pool. (iv) Fixed request having body being interrupted by the EarlyResponse exception 'signal'.
Added support for in-memory client (intermediary) certificate to be used with mTLS. This feature compensates for the complete removal of pyOpenSSL. Un
Added support for in-memory client (intermediary) certificate to be used with mTLS.
This feature compensates for the complete removal of pyOpenSSL. Unfortunately, it is only
available on Linux, OpenBSD, and FreeBSD. Using newly added cert_data and key_data arguments
in HTTPSConnection and HTTPSPoolConnection you will be capable of passing the certificate along with
its key without getting nowhere near your filesystem.
MacOS and Windows are not concerned by this feature when using HTTP/1.1, and HTTP/2 with TLS over TCP.
Removed remnant SSLTransport.makefile as it was built to circumvent a legacy constraint when urllib3 depended upon
http.client.
Bumped minimum requirement for qh3 to version 0.13.0 in order to support in-memory client certificate (mTLS).
Symbolic complete detachment from http.client. Removed all references and imports to http.client. Farewell!
Changed the default ciphers in default SSLContext for an increased security level.
Rational: Earlier in v2.1.901 we initialized the SSLContext ciphers with the value DEFAULT but after much
consideration, after we saw that the associated ciphers (e.g. DEFAULT from OpenSSL) includes some weak suites
we decided to inject a rather safer and limited cipher suite. It is based on https://ssl-config.mozilla.org
Starting now, urllib3.future will match Mozilla cipher recommendations (intermediary) and will regularly update the suite.
Added support for multiplexed connection. HTTP/2 and HTTP/3 can benefit from this.
urllib3.future no longer blocks when urlopen(...) is invoked using multiplexed=True, and return
a ResponsePromise instead of a HTTPResponse. You may dispatch as many requests as the protocol
permits you (concurrent stream) and then retrieve the response(s) using the get_response(...).
get_response(...) can take up to one kwarg to specify the target promise, if none is specified, will retrieve
the first available response. multiplexed is set to False by default and will likely be the default for a long
time.
Here is an example:
from urllib3 import PoolManager
with PoolManager() as pm:
promise0 = pm.urlopen("GET", "https://pie.dev/delay/3", multiplexed=True)
# <ResponsePromise 'IOYTFooi0bCuaQ9mwl4HaA==' HTTP/2.0 Stream[1]>
promise1 = pm.urlopen("GET", "https://pie.dev/delay/1", multiplexed=True)
# <ResponsePromise 'U9xT9dPVGnozL4wzDbaA3w==' HTTP/2.0 Stream[3]>
response0 = pm.get_response()
# the second request arrived first
response0.json()["url"] # https://pie.dev/delay/1
# the first arrived last
response1 = pm.get_response()
response1.json()["url"] # https://pie.dev/delay/3
or you may do:
from urllib3 import PoolManager
with PoolManager() as pm:
promise0 = pm.urlopen("GET", "https://pie.dev/delay/3", multiplexed=True)
# <ResponsePromise 'IOYTFooi0bCuaQ9mwl4HaA==' HTTP/2.0 Stream[1]>
promise1 = pm.urlopen("GET", "https://pie.dev/delay/1", multiplexed=True)
# <ResponsePromise 'U9xT9dPVGnozL4wzDbaA3w==' HTTP/2.0 Stream[3]>
response0 = pm.get_response(promise=promise0)
# forcing retrieving promise0
response0.json()["url"] # https://pie.dev/delay/3
# then pick first available
response1 = pm.get_response()
response1.json()["url"] # https://pie.dev/delay/1
You may do multiplexing using PoolManager, and HTTPSPoolConnection. Connection upgrade
to HTTP/3 cannot be done until all in-flight requests are completed.
Be aware that a non-capable connection (e.g. HTTP/1.1) will just ignore the multiplexed=True setting
and act traditionally.
Connections are now released into their respective pool when the connection supports multiplexing (HTTP/2, HTTP/3) before the response has been consumed. This allows to have multiple responses half-consumed from a single connection.
Removed BaseHTTPConnection, and BaseHTTPSConnection. Rationale: The initial idea, as far as I understand it, was to create a HTTPSConnection per proto
BaseHTTPConnection, and BaseHTTPSConnection.
Rationale: The initial idea, as far as I understand it, was to create a HTTPSConnection per protocols, e.g.
HTTP/2, and HTTP/3. From the point of view of urllib3.future it was taken care of in contrib.hface
where the protocols state-machines are handled. We plan to always have a unified Connection class that
regroup all protocols for convenience. The private module urllib3._base_connection is renamed to urllib3._typing.
It brings a lot of simplification, which is welcomed.BaseHTTPResponse to a mere alias of HTTPResponse for the same reasoning as before. There is absolutely
no need whatsoever in the foreseeable future to ship urllib3.future with an alternative implementation of HTTPResponse.
It will be removed in a future major.RECENT_DATE and linked logic as it does not make sense to (i) maintain it (ii) the certificate verification
failure won't be avoided anyway, so it is a warning prior to an unavoidable error. The warning class SystemTimeWarning
will be removed in a future major.urllib3._typing now contain all of our definitions.qh3 in PyPy 3.11+ while pre-built wheels are unavailable.…are also stripped in the said case. Port of the security fix GHSA-g4mx-q9vg-27p4
content-encoding, content-language, content-location, content-type, content-length, digest, last-modified are
also stripped in the said case.
Port of the security fix GHSA-g4mx-q9vg-27p4_TYPE_BODY now accept Iterable[str] in addition to Iterable[bytes].Set DEFAULT (as OpenSSL default list) for ciphers in SSLContext if none is provided instead of Python default.
DEFAULT (as OpenSSL default list) for ciphers in SSLContext if none is provided instead of Python default.ProtocolError was raised instead of SSLError in the underlying QUIC layer state machine.User-Agent to urllib3.future/x.y.z.Content-Length header on request with an unknown body length.
This was present due to a bug in Traefik server. An investigation will be conducted and a relevant issue will be
addressed.Undeprecated 'ssl_version' option in create_urllib3_context.
Added cipher in ConnectionInfo when using HTTP/3 over QUIC.
Added issuer_certificate_der, issuer_certificate_dict into ConnectionInfo.
By default, it is set to None. This property is filled automatically on a QUIC connection.
It cannot be done automatically when using native Python capabilities.
Removed support for SecureTransport.
Removed support for PyOpenSSL.
This module is not deleted but rendered ineffective. An explicit warning still appears.
Improved automated exchange between the socket and the HTTP state machines.
Removed all dependencies in the secure extra.
Fixed disabling HTTP/3 over QUIC if specified settings were incompatible with TLS over QUIC.
Previously if ssl_context was set and specifying a list of ciphers it was discarded on upgrade.
Also, if ssl_maximum_version was set to TLS v1.2.
Now those parameters are correctly forwarded to the custom QUIC/TLS layer.
Fixed ConnectionInfo repr that did not shown the http_version property.
Undeprecated 'ssl_version' option in create_urllib3_context.
Undeprecated 'format_header_param_rfc2231'.
Removed warning about the 'strict' parameter.
Removed constant IS_PYOPENSSL and IS_SECURETRANSPORT from urllib3.utils.
Added raise warning when using environment variables SSLKEYLOGFILE, and QUICLOGDIR.
Added the Cookie header to the list of headers to strip from requests when redirecting to a different host. As before, different headers can be set via Retry.remove_headers_on_redirect.
Removed warning about ssl not being the OpenSSL backend. You are free to choose.
Users are encouraged to report issues if any to the jawah/urllib3.future repository. Support will be provided to the best of our abilities.
Added support for event StreamReset to raise a ProtocolError when received from either h2 or h3. (#28 __)
Added support for event StreamReset to raise a ProtocolError when received from either h2 or h3. (#28 <https://github.com/jawah/urllib3.future/issues/28>__)
Fixed a violation in our QUIC transmission due to sending multiple datagrams at once. (#26 <https://github.com/jawah/urllib3.future/issues/26>__)
Added public ConnectionInfo class that will be present in each HttpConnection instance.
Added public ConnectionInfo class that will be present in each HttpConnection instance.
Passing the kwarg on_post_connection that accept a callable with a single positional argument
in PoolManager.urlopen method will result in a call each time a connection is picked out
of the pool. The function will be passed a ConnectionInfo object.
The same argument (on_post_connection) can be passed down to the HTTPConnectionPool.urlopen method. (#23 <https://github.com/jawah/urllib3.future/issues/23>__)
#22 <https://github.com/jawah/urllib3.future/issues/22>__
Fixed HTTPSConnectionPool not accepting and forwarding ca_cert_data. (#20 __)
HTTPSConnectionPool not accepting and forwarding ca_cert_data. (#20 <https://github.com/jawah/urllib3.future/issues/20>__)Fixed assert_hostname behavior when HTTPSConnection targets HTTP/3 over QUIC (#8 __)
assert_hostname behavior when HTTPSConnection targets HTTP/3 over QUIC (#8 <https://github.com/jawah/urllib3.future/issues/8>__)Connection: keep-alive when it is
forbidden. (#16 <https://github.com/jawah/urllib3.future/issues/16>__)unpack_chunk workaround function in the send method when body is multipart/form-data (#17 <https://github.com/jawah/urllib3.future/issues/17>__)#18 <https://github.com/jawah/urllib3.future/issues/18>__)Added support for HTTP/1.1, HTTP/2 and HTTP/3 independently of httplib.
Added support for HTTP/1.1, HTTP/2 and HTTP/3 independently of httplib.
Currently urllib3 does not offer async http request and the backend is the http.client package shipped alongside Python. This implementation is not scheduled to improve, even less to support the latest protocols.
Without proxies, the negotiation is as follows:
http requests are always made using HTTP/1.1.
https requests are made with HTTP/2 if TLS-ALPN yield its support otherwise HTTP/1.1.
https requests may upgrade to HTTP/3 if the latest response contains a valid Alt-Svc header.
With proxies:
You may explicitly disable HTTP/2 or, and, HTTP/3 by passing disabled_svn={HttpVersion.h2} to your BaseHttpConnection instance.
Disabling HTTP/1.1 is forbidden and raises an error.
Note that a valid or accepted Alt-Svc header in urllib3 means looking for the "h3" (final specification) protocol and disallow switching hostname for security
reasons. (#1 <https://github.com/jawah/urllib3.future/issues/1>__)
Added BaseHTTPResponse to __all__ in __init__.py (#3078 <https://github.com/urllib3/urllib3/issues/3078>__)
Added experimental support for HTTP/1.1, HTTP/2 and HTTP/3 independently of httplib.
Currently urllib3 does not offer async http request and the backend is the http.client package shipped alongside Python. This implementation is not scheduled to improve, even less to support latest protocol.
Without proxies, the negotiation is as follow:
http requests are always made using HTTP/1.1.
https requests are made with HTTP/2 if TLS-ALPN yield its support otherwise HTTP/1.1.
https requests may upgrade to HTTP/3 if latest response contain a valid Alt-Svc header.
With proxies:
The initial proxy request is always issued using HTTP/1.1 regardless if its http or https.
Subsequents requests follow the previous section (Without proxies) at the sole exception that HTTP/3 upgrade is disabled.
You may explicitly disable HTTP/2 or, and, HTTP/3 by passing disabled_svn={HttpVersion.h2} to your BaseHttpConnection instance. Disabling HTTP/1.1 is forbidden and raise an error.
Note that a valid or accepted Alt-Svc header in urllib3 means looking for the "h3" (final specification) protocol and disallow switching hostname for security reasons. (#1)
Added BaseHTTPResponse to __all__ in __init__.py (#3078)
Your coding agent can read these notes before it upgrades. Set up the MCP server →