Skip to content

Commit

Permalink
🐛 fix conn dropped issue occurring in 2.11.900
Browse files Browse the repository at this point in the history
  • Loading branch information
Ousret committed Oct 21, 2024
1 parent 1446db4 commit d227a96
Show file tree
Hide file tree
Showing 6 changed files with 26 additions and 39 deletions.
7 changes: 7 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
2.11.91 (2024-10-21)
=====================

- Fixed error in ``is_connected`` for a Connection. The logic is no longer applicable due to how urllib3-future grows.
We no longer use the function ``wait_for_read``. Also we stopped using MSG_PEEK for our discrete incoming data watcher
due to suspicious behavior noticed. Finally we shielded any exception from attempting to close a broken socket.

2.11.900 (2024-10-21)
=====================

Expand Down
1 change: 0 additions & 1 deletion src/urllib3/_async/connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,6 @@ def is_closed(self) -> bool:
def is_connected(self) -> bool:
if self.sock is None:
return False
# wait_for_read: not functional with multiplexed connection!
if self._promises or self._pending_responses:
return True
return self._protocol is not None and self._protocol.has_expired() is False
Expand Down
2 changes: 1 addition & 1 deletion src/urllib3/_version.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# This file is protected via CODEOWNERS
from __future__ import annotations

__version__ = "2.11.900"
__version__ = "2.11.901"
6 changes: 4 additions & 2 deletions src/urllib3/backend/_async/hface.py
Original file line number Diff line number Diff line change
Expand Up @@ -720,7 +720,6 @@ async def peek_and_react(self) -> bool:
bck_timeout = self.sock.gettimeout()
# either there is data ready for us, or there's nothing and we stop waiting
# almost instantaneously.
# we can't use socket.MSG_PEEK in asyncio socket wrapper, it is non-functional.
self.sock.settimeout(0.001)

try:
Expand Down Expand Up @@ -1597,7 +1596,10 @@ async def close(self) -> None: # type: ignore[override]
): # don't want our goodbye, never mind then!
break

self.sock.close()
try:
self.sock.close()
except OSError:
pass

self._protocol = None
self._stream_id = None
Expand Down
40 changes: 13 additions & 27 deletions src/urllib3/backend/hface.py
Original file line number Diff line number Diff line change
Expand Up @@ -768,39 +768,22 @@ def peek_and_react(self) -> bool:
if self.sock is None or self._protocol is None:
return False

try:
self.sock.setblocking(False)
except OSError: # disconnected!
return False
bck_timeout = self.sock.gettimeout()

# SSLSocket can't support non-zero flag for read.
# so, we'll improvise!
if isinstance(self.sock, ssl.SSLSocket):
try:
sock = socket.socket(fileno=self.sock.fileno())
except (OSError, AttributeError):
# Defensive: that means we can't go further, sock is not standard or don't implement fileno
return False
self.sock.settimeout(0.001)

try:
peek_data = sock.recv(self.blocksize, socket.MSG_PEEK)
except OSError:
return False
finally:
self.sock.setblocking(True)
else:
try:
peek_data = self.sock.recv(self.blocksize, socket.MSG_PEEK)
except OSError:
return False
finally:
self.sock.setblocking(True)
try:
peek_data = self.sock.recv(self.blocksize)
except (OSError, TimeoutError, socket.timeout):
return False
finally:
self.sock.settimeout(bck_timeout)

if not peek_data:
return False

try:
self._protocol.bytes_received(self.sock.recv(self.blocksize))
self._protocol.bytes_received(peek_data)
except self._protocol.exceptions():
return False

Expand Down Expand Up @@ -1669,7 +1652,10 @@ def close(self) -> None:
): # don't want our goodbye, never mind then!
break

self.sock.close()
try:
self.sock.close()
except OSError:
pass

self._protocol = None
self._stream_id = None
Expand Down
9 changes: 1 addition & 8 deletions src/urllib3/connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
from .response import HTTPResponse
from .util.timeout import _DEFAULT_TIMEOUT, Timeout
from .util.util import to_str
from .util.wait import wait_for_read

try: # Compiled with SSL?
import ssl
Expand Down Expand Up @@ -291,15 +290,9 @@ def is_closed(self) -> bool:
def is_connected(self) -> bool:
if self.sock is None:
return False
# wait_for_read: not functional with multiplexed connection!
if self._promises or self._pending_responses:
return True
# wait_for_read: not functional w/ UDP!
if self._svn == HttpVersion.h3:
return self._protocol is not None and self._protocol.has_expired() is False
if self._protocol is not None and self._protocol.has_expired() is True:
return False
return not wait_for_read(self.sock, timeout=0.0)
return self._protocol is not None and self._protocol.has_expired() is False

@property
def has_connected_to_proxy(self) -> bool:
Expand Down

0 comments on commit d227a96

Please sign in to comment.