Script 'mail_helper' called by obssrc
Hello community,
here is the log from the commit of package python-httpcore for openSUSE:Factory
checked in at 2022-03-02 18:20:19
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-httpcore (Old)
and /work/SRC/openSUSE:Factory/.python-httpcore.new.1958 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-httpcore"
Wed Mar 2 18:20:19 2022 rev:5 rq:958238 version:0.14.7
Changes:
--------
--- /work/SRC/openSUSE:Factory/python-httpcore/python-httpcore.changes
2022-02-14 22:35:57.141379478 +0100
+++
/work/SRC/openSUSE:Factory/.python-httpcore.new.1958/python-httpcore.changes
2022-03-02 18:20:29.484654648 +0100
@@ -1,0 +2,9 @@
+Mon Feb 21 10:54:40 UTC 2022 - Michael Str??der <[email protected]>
+
+- update to 0.14.7:
+ * Requests which raise a PoolTimeout need to be removed from the pool queue.
+ * Fix AttributeError that happened when Socks5Connection were terminated.
+ * Fix SOCKS support for `http://` URLs.
+ * Resolve race condition around exceptions during streaming a response.
+
+-------------------------------------------------------------------
Old:
----
httpcore-0.14.5.tar.gz
New:
----
httpcore-0.14.7.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-httpcore.spec ++++++
--- /var/tmp/diff_new_pack.M5LSLd/_old 2022-03-02 18:20:31.184654708 +0100
+++ /var/tmp/diff_new_pack.M5LSLd/_new 2022-03-02 18:20:31.188654708 +0100
@@ -27,7 +27,7 @@
%endif
%define skip_python2 1
Name: python-httpcore%{psuffix}
-Version: 0.14.5
+Version: 0.14.7
Release: 0
Summary: Minimal low-level Python HTTP client
License: BSD-3-Clause
++++++ httpcore-0.14.5.tar.gz -> httpcore-0.14.7.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/httpcore-0.14.5/.github/stale.yml
new/httpcore-0.14.7/.github/stale.yml
--- old/httpcore-0.14.5/.github/stale.yml 1970-01-01 01:00:00.000000000
+0100
+++ new/httpcore-0.14.7/.github/stale.yml 2022-02-04 13:16:06.000000000
+0100
@@ -0,0 +1,11 @@
+# Number of days of inactivity before an issue becomes stale
+daysUntilStale: 30
+# Number of days of inactivity before a stale issue is closed
+daysUntilClose: 7
+# Comment to post when marking an issue as stale. Set to `false` to disable
+markComment: >
+ This issue has been automatically marked as stale because it has not had
+ recent activity. It will be closed if no further activity occurs. Thank you
+ for your contributions.
+# Comment to post when closing a stale issue. Set to `false` to disable
+closeComment: false
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/httpcore-0.14.5/.github/workflows/publish.yml
new/httpcore-0.14.7/.github/workflows/publish.yml
--- old/httpcore-0.14.5/.github/workflows/publish.yml 2022-01-18
12:44:32.000000000 +0100
+++ new/httpcore-0.14.7/.github/workflows/publish.yml 2022-02-04
13:16:06.000000000 +0100
@@ -1,4 +1,3 @@
----
name: Publish
on:
@@ -11,6 +10,9 @@
name: "Publish release"
runs-on: "ubuntu-latest"
+ environment:
+ name: deploy
+
steps:
- uses: "actions/checkout@v2"
- uses: "actions/setup-python@v1"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/httpcore-0.14.5/CHANGELOG.md
new/httpcore-0.14.7/CHANGELOG.md
--- old/httpcore-0.14.5/CHANGELOG.md 2022-01-18 12:44:32.000000000 +0100
+++ new/httpcore-0.14.7/CHANGELOG.md 2022-02-04 13:16:06.000000000 +0100
@@ -4,6 +4,16 @@
The format is based on [Keep a
Changelog](https://keepachangelog.com/en/1.0.0/).
+## 0.14.7 (February 4th, 2022)
+
+- Requests which raise a PoolTimeout need to be removed from the pool queue.
(#502)
+- Fix AttributeError that happened when Socks5Connection were terminated.
(#501)
+
+## 0.14.6 (February 1st, 2022)
+
+- Fix SOCKS support for `http://` URLs. (#492)
+- Resolve race condition around exceptions during streaming a response. (#491)
+
## 0.14.5 (January 18th, 2022)
- SOCKS proxy support. (#478)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/httpcore-0.14.5/README.md
new/httpcore-0.14.7/README.md
--- old/httpcore-0.14.5/README.md 2022-01-18 12:44:32.000000000 +0100
+++ new/httpcore-0.14.7/README.md 2022-02-04 13:16:06.000000000 +0100
@@ -18,25 +18,31 @@
* Sending HTTP requests.
* Thread-safe / task-safe connection pooling.
-* HTTP(S) proxy support.
+* HTTP(S) proxy & SOCKS proxy support.
* Supports HTTP/1.1 and HTTP/2.
* Provides both sync and async interfaces.
* Async backend support for `asyncio` and `trio`.
## Installation
-For HTTP/1.1 only support, install with...
+For HTTP/1.1 only support, install with:
```shell
$ pip install httpcore
```
-For HTTP/1.1 and HTTP/2 support, install with...
+For HTTP/1.1 and HTTP/2 support, install with:
```shell
$ pip install httpcore[http2]
```
+For SOCKS proxy support, install with:
+
+```shell
+$ pip install httpcore[socks]
+```
+
# Sending requests
Send an HTTP request:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/httpcore-0.14.5/docs/proxies.md
new/httpcore-0.14.7/docs/proxies.md
--- old/httpcore-0.14.5/docs/proxies.md 2022-01-18 12:44:32.000000000 +0100
+++ new/httpcore-0.14.7/docs/proxies.md 2022-02-04 13:16:06.000000000 +0100
@@ -33,7 +33,7 @@
# A `Proxy-Authorization` header will be included on the initial proxy
connection.
proxy = httpcore.HTTPProxy(
proxy_url="http://127.0.0.1:8080/",
- proxy_auth=("<username", "password")
+ proxy_auth=("<username>", "<password>")
)
```
@@ -58,7 +58,7 @@
## SOCKS proxy support
-The `httpcore` package also supports proxies using the SOCKS protocol.
+The `httpcore` package also supports proxies using the SOCKS5 protocol.
Make sure to install the optional dependancy using `pip install
httpcore[socks]`.
@@ -68,7 +68,7 @@
import httpcore
# Note that the SOCKS port is 1080.
-proxy = httpcore.SOCKSProxy(proxy_url="socks://127.0.0.1:1080/")
+proxy = httpcore.SOCKSProxy(proxy_url="socks5://127.0.0.1:1080/")
r = proxy.request("GET", "https://www.example.com/")
```
@@ -78,8 +78,8 @@
import httpcore
proxy = httpcore.SOCKSProxy(
- proxy_url="socks://127.0.0.1:8080/",
- proxy_auth=("<username", "password")
+ proxy_url="socks5://127.0.0.1:8080/",
+ proxy_auth=("<username>", "<password>")
)
r = proxy.request("GET", "https://www.example.com/")
```
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/httpcore-0.14.5/httpcore/__init__.py
new/httpcore-0.14.7/httpcore/__init__.py
--- old/httpcore-0.14.5/httpcore/__init__.py 2022-01-18 12:44:32.000000000
+0100
+++ new/httpcore-0.14.7/httpcore/__init__.py 2022-02-04 13:16:06.000000000
+0100
@@ -82,7 +82,7 @@
"WriteError",
]
-__version__ = "0.14.5"
+__version__ = "0.14.7"
__locals = locals()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/httpcore-0.14.5/httpcore/_async/connection_pool.py
new/httpcore-0.14.7/httpcore/_async/connection_pool.py
--- old/httpcore-0.14.5/httpcore/_async/connection_pool.py 2022-01-18
12:44:32.000000000 +0100
+++ new/httpcore-0.14.7/httpcore/_async/connection_pool.py 2022-02-04
13:16:06.000000000 +0100
@@ -223,7 +223,16 @@
while True:
timeouts = request.extensions.get("timeout", {})
timeout = timeouts.get("pool", None)
- connection = await status.wait_for_connection(timeout=timeout)
+ try:
+ connection = await status.wait_for_connection(timeout=timeout)
+ except BaseException as exc:
+ # If we timeout here, or if the task is cancelled, then make
+ # sure to remove the request from the queue before bubbling
+ # up the exception.
+ async with self._pool_lock:
+ self._requests.remove(status)
+ raise exc
+
try:
response = await connection.handle_async_request(request)
except ConnectionNotAvailable:
@@ -239,7 +248,7 @@
# status so that the request becomes queued again.
status.unset_connection()
await self._attempt_to_acquire_connection(status)
- except Exception as exc:
+ except BaseException as exc:
await self.response_closed(status)
raise exc
else:
@@ -267,7 +276,8 @@
async with self._pool_lock:
# Update the state of the connection pool.
- self._requests.remove(status)
+ if status in self._requests:
+ self._requests.remove(status)
if connection.is_closed() and connection in self._pool:
self._pool.remove(connection)
@@ -291,11 +301,19 @@
Close any connections in the pool.
"""
async with self._pool_lock:
+ requests_still_in_flight = len(self._requests)
+
for connection in self._pool:
await connection.aclose()
self._pool = []
self._requests = []
+ if requests_still_in_flight:
+ raise RuntimeError(
+ f"The connection pool was closed while
{requests_still_in_flight} "
+ f"HTTP requests/responses were still in-flight."
+ )
+
async def __aenter__(self) -> "AsyncConnectionPool":
return self
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/httpcore-0.14.5/httpcore/_async/http11.py
new/httpcore-0.14.7/httpcore/_async/http11.py
--- old/httpcore-0.14.5/httpcore/_async/http11.py 2022-01-18
12:44:32.000000000 +0100
+++ new/httpcore-0.14.7/httpcore/_async/http11.py 2022-02-04
13:16:06.000000000 +0100
@@ -279,13 +279,23 @@
def __init__(self, connection: AsyncHTTP11Connection, request: Request) ->
None:
self._connection = connection
self._request = request
+ self._closed = False
async def __aiter__(self) -> AsyncIterator[bytes]:
kwargs = {"request": self._request}
- async with Trace("http11.receive_response_body", self._request,
kwargs):
- async for chunk in
self._connection._receive_response_body(**kwargs):
- yield chunk
+ try:
+ async with Trace("http11.receive_response_body", self._request,
kwargs):
+ async for chunk in
self._connection._receive_response_body(**kwargs):
+ yield chunk
+ except BaseException as exc:
+ # If we get an exception while streaming the response,
+ # we want to close the response (and possibly the connection)
+ # before raising that exception.
+ await self.aclose()
+ raise exc
async def aclose(self) -> None:
- async with Trace("http11.response_closed", self._request):
- await self._connection._response_closed()
+ if not self._closed:
+ self._closed = True
+ async with Trace("http11.response_closed", self._request):
+ await self._connection._response_closed()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/httpcore-0.14.5/httpcore/_async/http2.py
new/httpcore-0.14.7/httpcore/_async/http2.py
--- old/httpcore-0.14.5/httpcore/_async/http2.py 2022-01-18
12:44:32.000000000 +0100
+++ new/httpcore-0.14.7/httpcore/_async/http2.py 2022-02-04
13:16:06.000000000 +0100
@@ -170,7 +170,7 @@
]
self._h2_state.initiate_connection()
- self._h2_state.increment_flow_control_window(2 ** 24)
+ self._h2_state.increment_flow_control_window(2**24)
await self._write_outgoing_data(request)
# Sending the request...
@@ -200,7 +200,7 @@
]
self._h2_state.send_headers(stream_id, headers, end_stream=end_stream)
- self._h2_state.increment_flow_control_window(2 ** 24,
stream_id=stream_id)
+ self._h2_state.increment_flow_control_window(2**24,
stream_id=stream_id)
await self._write_outgoing_data(request)
async def _send_request_body(self, request: Request, stream_id: int) ->
None:
@@ -305,7 +305,6 @@
async def aclose(self) -> None:
# Note that this method unilaterally closes the connection, and does
# not have any kind of locking in place around it.
- # For task-safe/thread-safe operations call into 'attempt_close'
instead.
self._h2_state.close_connection()
self._state = HTTPConnectionState.CLOSED
await self._network_stream.aclose()
@@ -446,16 +445,26 @@
self._connection = connection
self._request = request
self._stream_id = stream_id
+ self._closed = False
async def __aiter__(self) -> typing.AsyncIterator[bytes]:
kwargs = {"request": self._request, "stream_id": self._stream_id}
- async with Trace("http2.receive_response_body", self._request, kwargs):
- async for chunk in self._connection._receive_response_body(
- request=self._request, stream_id=self._stream_id
- ):
- yield chunk
+ try:
+ async with Trace("http2.receive_response_body", self._request,
kwargs):
+ async for chunk in self._connection._receive_response_body(
+ request=self._request, stream_id=self._stream_id
+ ):
+ yield chunk
+ except BaseException as exc:
+ # If we get an exception while streaming the response,
+ # we want to close the response (and possibly the connection)
+ # before raising that exception.
+ await self.aclose()
+ raise exc
async def aclose(self) -> None:
- kwargs = {"stream_id": self._stream_id}
- async with Trace("http2.response_closed", self._request, kwargs):
- await self._connection._response_closed(stream_id=self._stream_id)
+ if not self._closed:
+ self._closed = True
+ kwargs = {"stream_id": self._stream_id}
+ async with Trace("http2.response_closed", self._request, kwargs):
+ await
self._connection._response_closed(stream_id=self._stream_id)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/httpcore-0.14.5/httpcore/_async/socks_proxy.py
new/httpcore-0.14.7/httpcore/_async/socks_proxy.py
--- old/httpcore-0.14.5/httpcore/_async/socks_proxy.py 2022-01-18
12:44:32.000000000 +0100
+++ new/httpcore-0.14.7/httpcore/_async/socks_proxy.py 2022-02-04
13:16:06.000000000 +0100
@@ -206,7 +206,7 @@
)
self._connect_lock = AsyncLock()
self._connection: typing.Optional[AsyncConnectionInterface] = None
- self._connection_failed = False
+ self._connect_failed = False
async def handle_async_request(self, request: Request) -> Response:
timeouts = request.extensions.get("timeout", {})
@@ -239,22 +239,27 @@
trace.return_value = stream
# Upgrade the stream to SSL
- ssl_context = (
- default_ssl_context()
- if self._ssl_context is None
- else self._ssl_context
- )
- alpn_protocols = ["http/1.1", "h2"] if self._http2 else
["http/1.1"]
- ssl_context.set_alpn_protocols(alpn_protocols)
-
- kwargs = {
- "ssl_context": ssl_context,
- "server_hostname":
self._remote_origin.host.decode("ascii"),
- "timeout": timeout,
- }
- async with Trace("connection.start_tls", request, kwargs)
as trace:
- stream = await stream.start_tls(**kwargs)
- trace.return_value = stream
+ if self._remote_origin.scheme == b"https":
+ ssl_context = (
+ default_ssl_context()
+ if self._ssl_context is None
+ else self._ssl_context
+ )
+ alpn_protocols = (
+ ["http/1.1", "h2"] if self._http2 else ["http/1.1"]
+ )
+ ssl_context.set_alpn_protocols(alpn_protocols)
+
+ kwargs = {
+ "ssl_context": ssl_context,
+ "server_hostname":
self._remote_origin.host.decode("ascii"),
+ "timeout": timeout,
+ }
+ async with Trace(
+ "connection.start_tls", request, kwargs
+ ) as trace:
+ stream = await stream.start_tls(**kwargs)
+ trace.return_value = stream
# Determine if we should be using HTTP/1.1 or HTTP/2
ssl_object = stream.get_extra_info("ssl_object")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/httpcore-0.14.5/httpcore/_sync/connection_pool.py
new/httpcore-0.14.7/httpcore/_sync/connection_pool.py
--- old/httpcore-0.14.5/httpcore/_sync/connection_pool.py 2022-01-18
12:44:32.000000000 +0100
+++ new/httpcore-0.14.7/httpcore/_sync/connection_pool.py 2022-02-04
13:16:06.000000000 +0100
@@ -223,7 +223,16 @@
while True:
timeouts = request.extensions.get("timeout", {})
timeout = timeouts.get("pool", None)
- connection = status.wait_for_connection(timeout=timeout)
+ try:
+ connection = status.wait_for_connection(timeout=timeout)
+ except BaseException as exc:
+ # If we timeout here, or if the task is cancelled, then make
+ # sure to remove the request from the queue before bubbling
+ # up the exception.
+ with self._pool_lock:
+ self._requests.remove(status)
+ raise exc
+
try:
response = connection.handle_request(request)
except ConnectionNotAvailable:
@@ -239,7 +248,7 @@
# status so that the request becomes queued again.
status.unset_connection()
self._attempt_to_acquire_connection(status)
- except Exception as exc:
+ except BaseException as exc:
self.response_closed(status)
raise exc
else:
@@ -267,7 +276,8 @@
with self._pool_lock:
# Update the state of the connection pool.
- self._requests.remove(status)
+ if status in self._requests:
+ self._requests.remove(status)
if connection.is_closed() and connection in self._pool:
self._pool.remove(connection)
@@ -291,11 +301,19 @@
Close any connections in the pool.
"""
with self._pool_lock:
+ requests_still_in_flight = len(self._requests)
+
for connection in self._pool:
connection.close()
self._pool = []
self._requests = []
+ if requests_still_in_flight:
+ raise RuntimeError(
+ f"The connection pool was closed while
{requests_still_in_flight} "
+ f"HTTP requests/responses were still in-flight."
+ )
+
def __enter__(self) -> "ConnectionPool":
return self
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/httpcore-0.14.5/httpcore/_sync/http11.py
new/httpcore-0.14.7/httpcore/_sync/http11.py
--- old/httpcore-0.14.5/httpcore/_sync/http11.py 2022-01-18
12:44:32.000000000 +0100
+++ new/httpcore-0.14.7/httpcore/_sync/http11.py 2022-02-04
13:16:06.000000000 +0100
@@ -279,13 +279,23 @@
def __init__(self, connection: HTTP11Connection, request: Request) -> None:
self._connection = connection
self._request = request
+ self._closed = False
def __iter__(self) -> Iterator[bytes]:
kwargs = {"request": self._request}
- with Trace("http11.receive_response_body", self._request, kwargs):
- for chunk in self._connection._receive_response_body(**kwargs):
- yield chunk
+ try:
+ with Trace("http11.receive_response_body", self._request, kwargs):
+ for chunk in self._connection._receive_response_body(**kwargs):
+ yield chunk
+ except BaseException as exc:
+ # If we get an exception while streaming the response,
+ # we want to close the response (and possibly the connection)
+ # before raising that exception.
+ self.close()
+ raise exc
def close(self) -> None:
- with Trace("http11.response_closed", self._request):
- self._connection._response_closed()
+ if not self._closed:
+ self._closed = True
+ with Trace("http11.response_closed", self._request):
+ self._connection._response_closed()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/httpcore-0.14.5/httpcore/_sync/http2.py
new/httpcore-0.14.7/httpcore/_sync/http2.py
--- old/httpcore-0.14.5/httpcore/_sync/http2.py 2022-01-18 12:44:32.000000000
+0100
+++ new/httpcore-0.14.7/httpcore/_sync/http2.py 2022-02-04 13:16:06.000000000
+0100
@@ -170,7 +170,7 @@
]
self._h2_state.initiate_connection()
- self._h2_state.increment_flow_control_window(2 ** 24)
+ self._h2_state.increment_flow_control_window(2**24)
self._write_outgoing_data(request)
# Sending the request...
@@ -200,7 +200,7 @@
]
self._h2_state.send_headers(stream_id, headers, end_stream=end_stream)
- self._h2_state.increment_flow_control_window(2 ** 24,
stream_id=stream_id)
+ self._h2_state.increment_flow_control_window(2**24,
stream_id=stream_id)
self._write_outgoing_data(request)
def _send_request_body(self, request: Request, stream_id: int) -> None:
@@ -305,7 +305,6 @@
def close(self) -> None:
# Note that this method unilaterally closes the connection, and does
# not have any kind of locking in place around it.
- # For task-safe/thread-safe operations call into 'attempt_close'
instead.
self._h2_state.close_connection()
self._state = HTTPConnectionState.CLOSED
self._network_stream.close()
@@ -446,16 +445,26 @@
self._connection = connection
self._request = request
self._stream_id = stream_id
+ self._closed = False
def __iter__(self) -> typing.Iterator[bytes]:
kwargs = {"request": self._request, "stream_id": self._stream_id}
- with Trace("http2.receive_response_body", self._request, kwargs):
- for chunk in self._connection._receive_response_body(
- request=self._request, stream_id=self._stream_id
- ):
- yield chunk
+ try:
+ with Trace("http2.receive_response_body", self._request, kwargs):
+ for chunk in self._connection._receive_response_body(
+ request=self._request, stream_id=self._stream_id
+ ):
+ yield chunk
+ except BaseException as exc:
+ # If we get an exception while streaming the response,
+ # we want to close the response (and possibly the connection)
+ # before raising that exception.
+ self.close()
+ raise exc
def close(self) -> None:
- kwargs = {"stream_id": self._stream_id}
- with Trace("http2.response_closed", self._request, kwargs):
- self._connection._response_closed(stream_id=self._stream_id)
+ if not self._closed:
+ self._closed = True
+ kwargs = {"stream_id": self._stream_id}
+ with Trace("http2.response_closed", self._request, kwargs):
+ self._connection._response_closed(stream_id=self._stream_id)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/httpcore-0.14.5/httpcore/_sync/socks_proxy.py
new/httpcore-0.14.7/httpcore/_sync/socks_proxy.py
--- old/httpcore-0.14.5/httpcore/_sync/socks_proxy.py 2022-01-18
12:44:32.000000000 +0100
+++ new/httpcore-0.14.7/httpcore/_sync/socks_proxy.py 2022-02-04
13:16:06.000000000 +0100
@@ -206,7 +206,7 @@
)
self._connect_lock = Lock()
self._connection: typing.Optional[ConnectionInterface] = None
- self._connection_failed = False
+ self._connect_failed = False
def handle_request(self, request: Request) -> Response:
timeouts = request.extensions.get("timeout", {})
@@ -239,22 +239,27 @@
trace.return_value = stream
# Upgrade the stream to SSL
- ssl_context = (
- default_ssl_context()
- if self._ssl_context is None
- else self._ssl_context
- )
- alpn_protocols = ["http/1.1", "h2"] if self._http2 else
["http/1.1"]
- ssl_context.set_alpn_protocols(alpn_protocols)
-
- kwargs = {
- "ssl_context": ssl_context,
- "server_hostname":
self._remote_origin.host.decode("ascii"),
- "timeout": timeout,
- }
- with Trace("connection.start_tls", request, kwargs) as
trace:
- stream = stream.start_tls(**kwargs)
- trace.return_value = stream
+ if self._remote_origin.scheme == b"https":
+ ssl_context = (
+ default_ssl_context()
+ if self._ssl_context is None
+ else self._ssl_context
+ )
+ alpn_protocols = (
+ ["http/1.1", "h2"] if self._http2 else ["http/1.1"]
+ )
+ ssl_context.set_alpn_protocols(alpn_protocols)
+
+ kwargs = {
+ "ssl_context": ssl_context,
+ "server_hostname":
self._remote_origin.host.decode("ascii"),
+ "timeout": timeout,
+ }
+ with Trace(
+ "connection.start_tls", request, kwargs
+ ) as trace:
+ stream = stream.start_tls(**kwargs)
+ trace.return_value = stream
# Determine if we should be using HTTP/1.1 or HTTP/2
ssl_object = stream.get_extra_info("ssl_object")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/httpcore-0.14.5/requirements.txt
new/httpcore-0.14.7/requirements.txt
--- old/httpcore-0.14.5/requirements.txt 2022-01-18 12:44:32.000000000
+0100
+++ new/httpcore-0.14.7/requirements.txt 2022-02-04 13:16:06.000000000
+0100
@@ -6,22 +6,22 @@
# Docs
mkdocs==1.2.3
mkdocs-autorefs==0.3.1
-mkdocs-material==8.1.4
+mkdocs-material==8.1.9
mkdocs-material-extensions==1.0.3
mkdocstrings==0.17.0
# Packaging
twine==3.7.1
-wheel==0.37.0
+wheel==0.37.1
# Tests & Linting
-anyio==3.4.0
+anyio==3.5.0
autoflake==1.4
-black==21.12b0
+black==22.1.0
coverage==6.2
flake8==4.0.1
isort==5.10.1
-mypy==0.930
+mypy==0.931
pytest==6.2.5
pytest-httpbin==1.0.1
pytest-trio==0.7.0
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/httpcore-0.14.5/tests/_async/test_connection_pool.py
new/httpcore-0.14.7/tests/_async/test_connection_pool.py
--- old/httpcore-0.14.5/tests/_async/test_connection_pool.py 2022-01-18
12:44:32.000000000 +0100
+++ new/httpcore-0.14.7/tests/_async/test_connection_pool.py 2022-02-04
13:16:06.000000000 +0100
@@ -3,7 +3,7 @@
import pytest
import trio as concurrency
-from httpcore import AsyncConnectionPool, ConnectError, UnsupportedProtocol
+from httpcore import AsyncConnectionPool, ConnectError, PoolTimeout,
UnsupportedProtocol
from httpcore.backends.mock import AsyncMockBackend
@@ -435,3 +435,56 @@
with pytest.raises(UnsupportedProtocol):
await pool.request("GET", "://www.example.com/")
+
+
[email protected]
+async def test_connection_pool_closed_while_request_in_flight():
+ """
+ Closing a connection pool while a request/response is still in-flight
+ should raise an error.
+ """
+ network_backend = AsyncMockBackend(
+ [
+ b"HTTP/1.1 200 OK\r\n",
+ b"Content-Type: plain/text\r\n",
+ b"Content-Length: 13\r\n",
+ b"\r\n",
+ b"Hello, world!",
+ ]
+ )
+
+ async with AsyncConnectionPool(
+ network_backend=network_backend,
+ ) as pool:
+ # Send a request, and then close the connection pool while the
+ # response has not yet been streamed.
+ async with pool.stream("GET", "https://example.com/"):
+ with pytest.raises(RuntimeError):
+ await pool.aclose()
+
+
[email protected]
+async def test_connection_pool_timeout():
+ """
+ Ensure that exceeding max_connections can cause a request to timeout.
+ """
+ network_backend = AsyncMockBackend(
+ [
+ b"HTTP/1.1 200 OK\r\n",
+ b"Content-Type: plain/text\r\n",
+ b"Content-Length: 13\r\n",
+ b"\r\n",
+ b"Hello, world!",
+ ]
+ )
+
+ async with AsyncConnectionPool(
+ network_backend=network_backend, max_connections=1
+ ) as pool:
+ # Send a request to a pool that is configured to only support a single
+ # connection, and then ensure that a second concurrent request
+ # fails with a timeout.
+ async with pool.stream("GET", "https://example.com/"):
+ with pytest.raises(PoolTimeout):
+ extensions = {"timeout": {"pool": 0.0001}}
+ await pool.request("GET", "https://example.com/",
extensions=extensions)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/httpcore-0.14.5/tests/_async/test_http11.py
new/httpcore-0.14.7/tests/_async/test_http11.py
--- old/httpcore-0.14.5/tests/_async/test_http11.py 2022-01-18
12:44:32.000000000 +0100
+++ new/httpcore-0.14.7/tests/_async/test_http11.py 2022-02-04
13:16:06.000000000 +0100
@@ -92,6 +92,35 @@
@pytest.mark.anyio
+async def test_http11_connection_with_incomplete_response():
+ """
+ We should be gracefully handling the case where the connection ends
prematurely.
+ """
+ origin = Origin(b"https", b"example.com", 443)
+ stream = AsyncMockStream(
+ [
+ b"HTTP/1.1 200 OK\r\n",
+ b"Content-Type: plain/text\r\n",
+ b"Content-Length: 13\r\n",
+ b"\r\n",
+ b"Hello, wor",
+ ]
+ )
+ async with AsyncHTTP11Connection(origin=origin, stream=stream) as conn:
+ with pytest.raises(RemoteProtocolError):
+ await conn.request("GET", "https://example.com/")
+
+ assert not conn.is_idle()
+ assert conn.is_closed()
+ assert not conn.is_available()
+ assert not conn.has_expired()
+ assert (
+ repr(conn)
+ == "<AsyncHTTP11Connection ['https://example.com:443', CLOSED,
Request Count: 1]>"
+ )
+
+
[email protected]
async def test_http11_connection_with_local_protocol_error():
"""
If a local protocol error occurs, then no response will be returned,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/httpcore-0.14.5/tests/_sync/test_connection_pool.py
new/httpcore-0.14.7/tests/_sync/test_connection_pool.py
--- old/httpcore-0.14.5/tests/_sync/test_connection_pool.py 2022-01-18
12:44:32.000000000 +0100
+++ new/httpcore-0.14.7/tests/_sync/test_connection_pool.py 2022-02-04
13:16:06.000000000 +0100
@@ -3,7 +3,7 @@
import pytest
from tests import concurrency
-from httpcore import ConnectionPool, ConnectError, UnsupportedProtocol
+from httpcore import ConnectionPool, ConnectError, PoolTimeout,
UnsupportedProtocol
from httpcore.backends.mock import MockBackend
@@ -435,3 +435,56 @@
with pytest.raises(UnsupportedProtocol):
pool.request("GET", "://www.example.com/")
+
+
+
+def test_connection_pool_closed_while_request_in_flight():
+ """
+ Closing a connection pool while a request/response is still in-flight
+ should raise an error.
+ """
+ network_backend = MockBackend(
+ [
+ b"HTTP/1.1 200 OK\r\n",
+ b"Content-Type: plain/text\r\n",
+ b"Content-Length: 13\r\n",
+ b"\r\n",
+ b"Hello, world!",
+ ]
+ )
+
+ with ConnectionPool(
+ network_backend=network_backend,
+ ) as pool:
+ # Send a request, and then close the connection pool while the
+ # response has not yet been streamed.
+ with pool.stream("GET", "https://example.com/"):
+ with pytest.raises(RuntimeError):
+ pool.close()
+
+
+
+def test_connection_pool_timeout():
+ """
+ Ensure that exceeding max_connections can cause a request to timeout.
+ """
+ network_backend = MockBackend(
+ [
+ b"HTTP/1.1 200 OK\r\n",
+ b"Content-Type: plain/text\r\n",
+ b"Content-Length: 13\r\n",
+ b"\r\n",
+ b"Hello, world!",
+ ]
+ )
+
+ with ConnectionPool(
+ network_backend=network_backend, max_connections=1
+ ) as pool:
+ # Send a request to a pool that is configured to only support a single
+ # connection, and then ensure that a second concurrent request
+ # fails with a timeout.
+ with pool.stream("GET", "https://example.com/"):
+ with pytest.raises(PoolTimeout):
+ extensions = {"timeout": {"pool": 0.0001}}
+ pool.request("GET", "https://example.com/",
extensions=extensions)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/httpcore-0.14.5/tests/_sync/test_http11.py
new/httpcore-0.14.7/tests/_sync/test_http11.py
--- old/httpcore-0.14.5/tests/_sync/test_http11.py 2022-01-18
12:44:32.000000000 +0100
+++ new/httpcore-0.14.7/tests/_sync/test_http11.py 2022-02-04
13:16:06.000000000 +0100
@@ -92,6 +92,35 @@
+def test_http11_connection_with_incomplete_response():
+ """
+ We should be gracefully handling the case where the connection ends
prematurely.
+ """
+ origin = Origin(b"https", b"example.com", 443)
+ stream = MockStream(
+ [
+ b"HTTP/1.1 200 OK\r\n",
+ b"Content-Type: plain/text\r\n",
+ b"Content-Length: 13\r\n",
+ b"\r\n",
+ b"Hello, wor",
+ ]
+ )
+ with HTTP11Connection(origin=origin, stream=stream) as conn:
+ with pytest.raises(RemoteProtocolError):
+ conn.request("GET", "https://example.com/")
+
+ assert not conn.is_idle()
+ assert conn.is_closed()
+ assert not conn.is_available()
+ assert not conn.has_expired()
+ assert (
+ repr(conn)
+ == "<HTTP11Connection ['https://example.com:443', CLOSED, Request
Count: 1]>"
+ )
+
+
+
def test_http11_connection_with_local_protocol_error():
"""
If a local protocol error occurs, then no response will be returned,