Skip to content

Commit dbe52dc

Browse files
committed
Fix socket reading function for TCP (non-HTTPS) connections on Windows
Signed-off-by: Joffrey F <[email protected]>
1 parent 49bb738 commit dbe52dc

File tree

2 files changed

+59
-2
lines changed

2 files changed

+59
-2
lines changed

docker/utils/socket.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import errno
22
import os
33
import select
4+
import socket as pysocket
45
import struct
56

67
import six
@@ -28,6 +29,8 @@ def read(socket, n=4096):
2829
try:
2930
if hasattr(socket, 'recv'):
3031
return socket.recv(n)
32+
if six.PY3 and isinstance(socket, getattr(pysocket, 'SocketIO')):
33+
return socket.read(n)
3134
return os.read(socket.fileno(), n)
3235
except EnvironmentError as e:
3336
if e.errno not in recoverable_errors:

tests/unit/api_test.py

Lines changed: 56 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -365,7 +365,7 @@ def test_stream_helper_decoding(self):
365365
assert result == content
366366

367367

368-
class StreamTest(unittest.TestCase):
368+
class UnixSocketStreamTest(unittest.TestCase):
369369
def setUp(self):
370370
socket_dir = tempfile.mkdtemp()
371371
self.build_context = tempfile.mkdtemp()
@@ -462,7 +462,61 @@ def test_early_stream_response(self):
462462
raise e
463463

464464
assert list(stream) == [
465-
str(i).encode() for i in range(50)]
465+
str(i).encode() for i in range(50)
466+
]
467+
468+
469+
class TCPSocketStreamTest(unittest.TestCase):
470+
text_data = b'''
471+
Now, those children out there, they're jumping through the
472+
flames in the hope that the god of the fire will make them fruitful.
473+
Really, you can't blame them. After all, what girl would not prefer the
474+
child of a god to that of some acne-scarred artisan?
475+
'''
476+
477+
def setUp(self):
478+
479+
self.server = six.moves.socketserver.ThreadingTCPServer(
480+
('', 0), self.get_handler_class()
481+
)
482+
self.thread = threading.Thread(target=self.server.serve_forever)
483+
self.thread.setDaemon(True)
484+
self.thread.start()
485+
self.address = 'http://{}:{}'.format(
486+
socket.gethostname(), self.server.server_address[1]
487+
)
488+
489+
def tearDown(self):
490+
self.server.shutdown()
491+
self.server.server_close()
492+
self.thread.join()
493+
494+
def get_handler_class(self):
495+
text_data = self.text_data
496+
497+
class Handler(six.moves.BaseHTTPServer.BaseHTTPRequestHandler, object):
498+
def do_POST(self):
499+
self.send_response(101)
500+
self.send_header(
501+
'Content-Type', 'application/vnd.docker.raw-stream'
502+
)
503+
self.send_header('Connection', 'Upgrade')
504+
self.send_header('Upgrade', 'tcp')
505+
self.end_headers()
506+
self.wfile.flush()
507+
time.sleep(0.2)
508+
self.wfile.write(text_data)
509+
self.wfile.flush()
510+
511+
return Handler
512+
513+
def test_read_from_socket(self):
514+
with APIClient(base_url=self.address) as client:
515+
resp = client._post(client._url('/dummy'), stream=True)
516+
data = client._read_from_socket(resp, stream=True, tty=True)
517+
results = b''.join(data)
518+
519+
assert results == self.text_data
466520

467521

468522
class UserAgentTest(unittest.TestCase):

0 commit comments

Comments
 (0)