From 5f55645b796d2a5384c32635654c231a588d5f25 Mon Sep 17 00:00:00 2001 From: karosis88 Date: Thu, 14 Sep 2023 17:29:36 +0300 Subject: [PATCH 1/8] Add is_new property for HTTPConnections --- httpcore/_async/connection.py | 16 ++++++++++++++-- httpcore/_sync/connection.py | 16 ++++++++++++++-- 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/httpcore/_async/connection.py b/httpcore/_async/connection.py index 45ee22a6..f6b8b1c8 100644 --- a/httpcore/_async/connection.py +++ b/httpcore/_async/connection.py @@ -63,6 +63,7 @@ def __init__( self._connect_failed: bool = False self._request_lock = AsyncLock() self._socket_options = socket_options + self._is_new = True async def handle_async_request(self, request: Request) -> Response: if not self.can_handle_request(request.url.origin): @@ -73,6 +74,7 @@ async def handle_async_request(self, request: Request) -> Response: async with self._request_lock: if self._connection is None: try: + self._is_new = False stream = await self._connect(request) ssl_object = stream.get_extra_info("ssl_object") @@ -94,7 +96,7 @@ async def handle_async_request(self, request: Request) -> Response: stream=stream, keepalive_expiry=self._keepalive_expiry, ) - except Exception as exc: + except BaseException as exc: self._connect_failed = True raise exc elif not self._connection.is_available(): @@ -174,6 +176,8 @@ async def aclose(self) -> None: def is_available(self) -> bool: if self._connection is None: + if self._is_new: + return True # If HTTP/2 support is enabled, and the resulting connection could # end up as HTTP/2 then we should indicate the connection as being # available to service multiple requests. @@ -185,6 +189,8 @@ def is_available(self) -> bool: return self._connection.is_available() def has_expired(self) -> bool: + if self._connect_failed: + return True if self._connection is None: return self._connect_failed return self._connection.has_expired() @@ -201,7 +207,13 @@ def is_closed(self) -> bool: def info(self) -> str: if self._connection is None: - return "CONNECTION FAILED" if self._connect_failed else "CONNECTING" + if self._is_new: + return "NEW CONNECTION" + return ( + "CONNECTING" + if not (self._is_new or self._connect_failed) + else "CONNECTINION FAILED" + ) return self._connection.info() def __repr__(self) -> str: diff --git a/httpcore/_sync/connection.py b/httpcore/_sync/connection.py index 81e4172a..7540af6a 100644 --- a/httpcore/_sync/connection.py +++ b/httpcore/_sync/connection.py @@ -63,6 +63,7 @@ def __init__( self._connect_failed: bool = False self._request_lock = Lock() self._socket_options = socket_options + self._is_new = True def handle_request(self, request: Request) -> Response: if not self.can_handle_request(request.url.origin): @@ -73,6 +74,7 @@ def handle_request(self, request: Request) -> Response: with self._request_lock: if self._connection is None: try: + self._is_new = False stream = self._connect(request) ssl_object = stream.get_extra_info("ssl_object") @@ -94,7 +96,7 @@ def handle_request(self, request: Request) -> Response: stream=stream, keepalive_expiry=self._keepalive_expiry, ) - except Exception as exc: + except BaseException as exc: self._connect_failed = True raise exc elif not self._connection.is_available(): @@ -174,6 +176,8 @@ def close(self) -> None: def is_available(self) -> bool: if self._connection is None: + if self._is_new: + return True # If HTTP/2 support is enabled, and the resulting connection could # end up as HTTP/2 then we should indicate the connection as being # available to service multiple requests. @@ -185,6 +189,8 @@ def is_available(self) -> bool: return self._connection.is_available() def has_expired(self) -> bool: + if self._connect_failed: + return True if self._connection is None: return self._connect_failed return self._connection.has_expired() @@ -201,7 +207,13 @@ def is_closed(self) -> bool: def info(self) -> str: if self._connection is None: - return "CONNECTION FAILED" if self._connect_failed else "CONNECTING" + if self._is_new: + return "NEW CONNECTION" + return ( + "CONNECTING" + if not (self._is_new or self._connect_failed) + else "CONNECTINION FAILED" + ) return self._connection.info() def __repr__(self) -> str: From 093f4b86f8d43acf19d94e8b4459e9268478f678 Mon Sep 17 00:00:00 2001 From: karosis88 Date: Thu, 14 Sep 2023 17:47:12 +0300 Subject: [PATCH 2/8] Optimize --- httpcore/_async/connection.py | 6 +----- httpcore/_sync/connection.py | 6 +----- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/httpcore/_async/connection.py b/httpcore/_async/connection.py index f6b8b1c8..f9f30fe9 100644 --- a/httpcore/_async/connection.py +++ b/httpcore/_async/connection.py @@ -189,8 +189,6 @@ def is_available(self) -> bool: return self._connection.is_available() def has_expired(self) -> bool: - if self._connect_failed: - return True if self._connection is None: return self._connect_failed return self._connection.has_expired() @@ -210,9 +208,7 @@ def info(self) -> str: if self._is_new: return "NEW CONNECTION" return ( - "CONNECTING" - if not (self._is_new or self._connect_failed) - else "CONNECTINION FAILED" + "CONNECTINION FAILED" if self._connect_failed else "CONNECTINION FAILED" ) return self._connection.info() diff --git a/httpcore/_sync/connection.py b/httpcore/_sync/connection.py index 7540af6a..d8df4e16 100644 --- a/httpcore/_sync/connection.py +++ b/httpcore/_sync/connection.py @@ -189,8 +189,6 @@ def is_available(self) -> bool: return self._connection.is_available() def has_expired(self) -> bool: - if self._connect_failed: - return True if self._connection is None: return self._connect_failed return self._connection.has_expired() @@ -210,9 +208,7 @@ def info(self) -> str: if self._is_new: return "NEW CONNECTION" return ( - "CONNECTING" - if not (self._is_new or self._connect_failed) - else "CONNECTINION FAILED" + "CONNECTINION FAILED" if self._connect_failed else "CONNECTINION FAILED" ) return self._connection.info() From 49ad393ed2b13f7c81fedb8ecbbfbc6d7deb78b0 Mon Sep 17 00:00:00 2001 From: karosis88 Date: Thu, 14 Sep 2023 17:48:09 +0300 Subject: [PATCH 3/8] Typo --- httpcore/_async/connection.py | 4 +--- httpcore/_sync/connection.py | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/httpcore/_async/connection.py b/httpcore/_async/connection.py index f9f30fe9..a69ff5de 100644 --- a/httpcore/_async/connection.py +++ b/httpcore/_async/connection.py @@ -207,9 +207,7 @@ def info(self) -> str: if self._connection is None: if self._is_new: return "NEW CONNECTION" - return ( - "CONNECTINION FAILED" if self._connect_failed else "CONNECTINION FAILED" - ) + return "CONNECTINION FAILED" if self._connect_failed else "CONNECTING" return self._connection.info() def __repr__(self) -> str: diff --git a/httpcore/_sync/connection.py b/httpcore/_sync/connection.py index d8df4e16..79bdca69 100644 --- a/httpcore/_sync/connection.py +++ b/httpcore/_sync/connection.py @@ -207,9 +207,7 @@ def info(self) -> str: if self._connection is None: if self._is_new: return "NEW CONNECTION" - return ( - "CONNECTINION FAILED" if self._connect_failed else "CONNECTINION FAILED" - ) + return "CONNECTINION FAILED" if self._connect_failed else "CONNECTING" return self._connection.info() def __repr__(self) -> str: From fbb6904d70df7a5400828178e85aa640c193e3cd Mon Sep 17 00:00:00 2001 From: Kar Petrosyan <92274156+karosis88@users.noreply.github.com> Date: Fri, 15 Sep 2023 08:16:12 +0300 Subject: [PATCH 4/8] Update httpcore/_sync/connection.py Co-authored-by: Zanie Blue --- httpcore/_sync/connection.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/httpcore/_sync/connection.py b/httpcore/_sync/connection.py index 79bdca69..f4078116 100644 --- a/httpcore/_sync/connection.py +++ b/httpcore/_sync/connection.py @@ -207,7 +207,7 @@ def info(self) -> str: if self._connection is None: if self._is_new: return "NEW CONNECTION" - return "CONNECTINION FAILED" if self._connect_failed else "CONNECTING" + return "CONNECTION FAILED" if self._connect_failed else "CONNECTING" return self._connection.info() def __repr__(self) -> str: From c46ec09404a0460ce0f84e60d111471ea04b16b2 Mon Sep 17 00:00:00 2001 From: Kar Petrosyan <92274156+karosis88@users.noreply.github.com> Date: Fri, 15 Sep 2023 08:16:18 +0300 Subject: [PATCH 5/8] Update httpcore/_async/connection.py Co-authored-by: Zanie Blue --- httpcore/_async/connection.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/httpcore/_async/connection.py b/httpcore/_async/connection.py index a69ff5de..5bb94bfc 100644 --- a/httpcore/_async/connection.py +++ b/httpcore/_async/connection.py @@ -207,7 +207,7 @@ def info(self) -> str: if self._connection is None: if self._is_new: return "NEW CONNECTION" - return "CONNECTINION FAILED" if self._connect_failed else "CONNECTING" + return "CONNECTION FAILED" if self._connect_failed else "CONNECTING" return self._connection.info() def __repr__(self) -> str: From 958e402f0be2a273978b501fa56951849f63d0bd Mon Sep 17 00:00:00 2001 From: karosis88 Date: Fri, 15 Sep 2023 08:37:17 +0300 Subject: [PATCH 6/8] Fix tests --- tests/_async/test_connection.py | 4 ++-- tests/_sync/test_connection.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/_async/test_connection.py b/tests/_async/test_connection.py index b6ee0c7e..9d36dbed 100644 --- a/tests/_async/test_connection.py +++ b/tests/_async/test_connection.py @@ -37,9 +37,9 @@ async def test_http_connection(): ) as conn: assert not conn.is_idle() assert not conn.is_closed() - assert not conn.is_available() + assert conn.is_available() assert not conn.has_expired() - assert repr(conn) == "" + assert repr(conn) == "" async with conn.stream("GET", "https://example.com/") as response: assert ( diff --git a/tests/_sync/test_connection.py b/tests/_sync/test_connection.py index 37c82e02..c0286fa6 100644 --- a/tests/_sync/test_connection.py +++ b/tests/_sync/test_connection.py @@ -37,9 +37,9 @@ def test_http_connection(): ) as conn: assert not conn.is_idle() assert not conn.is_closed() - assert not conn.is_available() + assert conn.is_available() assert not conn.has_expired() - assert repr(conn) == "" + assert repr(conn) == "" with conn.stream("GET", "https://example.com/") as response: assert ( From ef814ee44a4a2db9782265a1faeaa00b2d9cc96e Mon Sep 17 00:00:00 2001 From: karosis88 Date: Fri, 15 Sep 2023 08:41:46 +0300 Subject: [PATCH 7/8] coverage --- httpcore/_async/connection.py | 6 ++++-- httpcore/_sync/connection.py | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/httpcore/_async/connection.py b/httpcore/_async/connection.py index 5bb94bfc..fb3785db 100644 --- a/httpcore/_async/connection.py +++ b/httpcore/_async/connection.py @@ -181,7 +181,7 @@ def is_available(self) -> bool: # If HTTP/2 support is enabled, and the resulting connection could # end up as HTTP/2 then we should indicate the connection as being # available to service multiple requests. - return ( + return ( # pragma: no cover self._http2 and (self._origin.scheme == b"https" or not self._http1) and not self._connect_failed @@ -207,7 +207,9 @@ def info(self) -> str: if self._connection is None: if self._is_new: return "NEW CONNECTION" - return "CONNECTION FAILED" if self._connect_failed else "CONNECTING" + return ( + "CONNECTION FAILED" if self._connect_failed else "CONNECTING" + ) # pragma: no cover return self._connection.info() def __repr__(self) -> str: diff --git a/httpcore/_sync/connection.py b/httpcore/_sync/connection.py index f4078116..aa4ebab4 100644 --- a/httpcore/_sync/connection.py +++ b/httpcore/_sync/connection.py @@ -181,7 +181,7 @@ def is_available(self) -> bool: # If HTTP/2 support is enabled, and the resulting connection could # end up as HTTP/2 then we should indicate the connection as being # available to service multiple requests. - return ( + return ( # pragma: no cover self._http2 and (self._origin.scheme == b"https" or not self._http1) and not self._connect_failed @@ -207,7 +207,9 @@ def info(self) -> str: if self._connection is None: if self._is_new: return "NEW CONNECTION" - return "CONNECTION FAILED" if self._connect_failed else "CONNECTING" + return ( + "CONNECTION FAILED" if self._connect_failed else "CONNECTING" + ) # pragma: no cover return self._connection.info() def __repr__(self) -> str: From 87e526d33fab804cc0696d2ee94a3b39b5360720 Mon Sep 17 00:00:00 2001 From: karosis88 Date: Thu, 19 Oct 2023 10:35:14 +0300 Subject: [PATCH 8/8] changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index dc8ca42b..b69da45c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ## Unreleased +- Handle asynchronous cancellations for the HTTPConnection instances. (#802) - Fix pool timeout to account for the total time spent retrying. (#823) ## 1.0.0 (October 6th, 2023)