diff --git a/httpcore/_async/http11.py b/httpcore/_async/http11.py index 0493a923d..d484a6250 100644 --- a/httpcore/_async/http11.py +++ b/httpcore/_async/http11.py @@ -59,7 +59,7 @@ def __init__( ) -> None: self._origin = origin self._network_stream = stream - self._keepalive_expiry: Optional[float] = keepalive_expiry + self._keepalive_expiry = keepalive_expiry self._expire_at: Optional[float] = None self._state = HTTPConnectionState.NEW self._state_lock = AsyncLock() @@ -77,6 +77,16 @@ async def handle_async_request(self, request: Request) -> Response: ) async with self._state_lock: + # If the HTTP connection is idle but the socket is readable, then the + # only valid state is that the socket is about to return b"", indicating + # a server-initiated disconnect. + server_disconnected = ( + self._state == HTTPConnectionState.IDLE + and self._network_stream.get_extra_info("is_readable") + ) + if server_disconnected: + raise ConnectionNotAvailable() + if self._state in (HTTPConnectionState.NEW, HTTPConnectionState.IDLE): self._request_count += 1 self._state = HTTPConnectionState.ACTIVE @@ -280,17 +290,7 @@ def is_available(self) -> bool: def has_expired(self) -> bool: now = time.monotonic() - keepalive_expired = self._expire_at is not None and now > self._expire_at - - # If the HTTP connection is idle but the socket is readable, then the - # only valid state is that the socket is about to return b"", indicating - # a server-initiated disconnect. - server_disconnected = ( - self._state == HTTPConnectionState.IDLE - and self._network_stream.get_extra_info("is_readable") - ) - - return keepalive_expired or server_disconnected + return self._expire_at is not None and now > self._expire_at def is_idle(self) -> bool: return self._state == HTTPConnectionState.IDLE diff --git a/httpcore/_sync/http11.py b/httpcore/_sync/http11.py index a74ff8e80..f276bdade 100644 --- a/httpcore/_sync/http11.py +++ b/httpcore/_sync/http11.py @@ -59,7 +59,7 @@ def __init__( ) -> None: self._origin = origin self._network_stream = stream - self._keepalive_expiry: Optional[float] = keepalive_expiry + self._keepalive_expiry = keepalive_expiry self._expire_at: Optional[float] = None self._state = HTTPConnectionState.NEW self._state_lock = Lock() @@ -77,6 +77,16 @@ def handle_request(self, request: Request) -> Response: ) with self._state_lock: + # If the HTTP connection is idle but the socket is readable, then the + # only valid state is that the socket is about to return b"", indicating + # a server-initiated disconnect. + server_disconnected = ( + self._state == HTTPConnectionState.IDLE + and self._network_stream.get_extra_info("is_readable") + ) + if server_disconnected: + raise ConnectionNotAvailable() + if self._state in (HTTPConnectionState.NEW, HTTPConnectionState.IDLE): self._request_count += 1 self._state = HTTPConnectionState.ACTIVE @@ -280,17 +290,7 @@ def is_available(self) -> bool: def has_expired(self) -> bool: now = time.monotonic() - keepalive_expired = self._expire_at is not None and now > self._expire_at - - # If the HTTP connection is idle but the socket is readable, then the - # only valid state is that the socket is about to return b"", indicating - # a server-initiated disconnect. - server_disconnected = ( - self._state == HTTPConnectionState.IDLE - and self._network_stream.get_extra_info("is_readable") - ) - - return keepalive_expired or server_disconnected + return self._expire_at is not None and now > self._expire_at def is_idle(self) -> bool: return self._state == HTTPConnectionState.IDLE