Skip to content

Commit 2826dd5

Browse files
committed
Don't set socket timeout if it's already disabled when streaming
Signed-off-by: Kevin Frommelt <[email protected]>
1 parent b98e240 commit 2826dd5

File tree

2 files changed

+65
-6
lines changed

2 files changed

+65
-6
lines changed

docker/client.py

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -291,14 +291,29 @@ def _disable_socket_timeout(self, socket):
291291
""" Depending on the combination of python version and whether we're
292292
connecting over http or https, we might need to access _sock, which
293293
may or may not exist; or we may need to just settimeout on socket
294-
itself, which also may or may not have settimeout on it.
294+
itself, which also may or may not have settimeout on it. To avoid
295+
missing the correct one, we try both.
295296
296-
To avoid missing the correct one, we try both.
297+
We also do not want to set the timeout if it is already disabled, as
298+
you run the risk of changing a socket that was non-blocking to
299+
blocking, for example when using gevent.
297300
"""
298-
if hasattr(socket, "settimeout"):
299-
socket.settimeout(None)
300-
if hasattr(socket, "_sock") and hasattr(socket._sock, "settimeout"):
301-
socket._sock.settimeout(None)
301+
sockets = [socket, getattr(socket, '_sock', None)]
302+
303+
for s in sockets:
304+
if not hasattr(s, 'settimeout'):
305+
continue
306+
307+
timeout = -1
308+
309+
if hasattr(s, 'gettimeout'):
310+
timeout = s.gettimeout()
311+
312+
# Don't change the timeout if it is already disabled.
313+
if timeout is None or timeout == 0.0:
314+
continue
315+
316+
s.settimeout(None)
302317

303318
def _get_result(self, container, stream, res):
304319
cont = self.inspect_container(container)

tests/unit/client_test.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,47 @@ def test_from_env(self):
2424
DOCKER_TLS_VERIFY='1')
2525
client = Client.from_env()
2626
self.assertEqual(client.base_url, "https://192.168.59.103:2376")
27+
28+
29+
class DisableSocketTest(base.BaseTestCase):
30+
class DummySocket(object):
31+
def __init__(self, timeout=60):
32+
self.timeout = timeout
33+
34+
def settimeout(self, timeout):
35+
self.timeout = timeout
36+
37+
def gettimeout(self):
38+
return self.timeout
39+
40+
def setUp(self):
41+
self.client = Client()
42+
43+
def test_disable_socket_timeout(self):
44+
"""Test that the timeout is disabled on a generic socket object."""
45+
socket = self.DummySocket()
46+
47+
self.client._disable_socket_timeout(socket)
48+
49+
self.assertEqual(socket.timeout, None)
50+
51+
def test_disable_socket_timeout2(self):
52+
"""Test that the timeouts are disabled on a generic socket object
53+
and it's _sock object if present."""
54+
socket = self.DummySocket()
55+
socket._sock = self.DummySocket()
56+
57+
self.client._disable_socket_timeout(socket)
58+
59+
self.assertEqual(socket.timeout, None)
60+
self.assertEqual(socket._sock.timeout, None)
61+
62+
def test_disable_socket_timout_non_blocking(self):
63+
"""Test that a non-blocking socket does not get set to blocking."""
64+
socket = self.DummySocket()
65+
socket._sock = self.DummySocket(0.0)
66+
67+
self.client._disable_socket_timeout(socket)
68+
69+
self.assertEqual(socket.timeout, None)
70+
self.assertEqual(socket._sock.timeout, 0.0)

0 commit comments

Comments
 (0)