Skip to content
This repository was archived by the owner on Nov 23, 2017. It is now read-only.

Commit 66b4ad7

Browse files
committed
Fix transport._read_ready and _write_ready to respect _conn_lost.
Patch by Łukasz Langa.
1 parent dfae386 commit 66b4ad7

File tree

2 files changed

+24
-17
lines changed

2 files changed

+24
-17
lines changed

asyncio/selector_events.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -569,6 +569,7 @@ def close(self):
569569
self._loop.remove_reader(self._sock_fd)
570570
if not self._buffer:
571571
self._conn_lost += 1
572+
self._loop.remove_writer(self._sock_fd)
572573
self._loop.call_soon(self._call_connection_lost, None)
573574

574575
# On Python 3.3 and older, objects with a destructor part of a reference
@@ -662,6 +663,8 @@ def resume_reading(self):
662663
logger.debug("%r resumes reading", self)
663664

664665
def _read_ready(self):
666+
if self._conn_lost:
667+
return
665668
try:
666669
data = self._sock.recv(self.max_size)
667670
except (BlockingIOError, InterruptedError):
@@ -721,6 +724,8 @@ def write(self, data):
721724
def _write_ready(self):
722725
assert self._buffer, 'Data should not be empty'
723726

727+
if self._conn_lost:
728+
return
724729
try:
725730
n = self._sock.send(self._buffer)
726731
except (BlockingIOError, InterruptedError):
@@ -891,6 +896,8 @@ def resume_reading(self):
891896
logger.debug("%r resumes reading", self)
892897

893898
def _read_ready(self):
899+
if self._conn_lost:
900+
return
894901
if self._write_wants_read:
895902
self._write_wants_read = False
896903
self._write_ready()
@@ -923,6 +930,8 @@ def _read_ready(self):
923930
self.close()
924931

925932
def _write_ready(self):
933+
if self._conn_lost:
934+
return
926935
if self._read_wants_write:
927936
self._read_wants_write = False
928937
self._read_ready()
@@ -1000,6 +1009,8 @@ def get_write_buffer_size(self):
10001009
return sum(len(data) for data, _ in self._buffer)
10011010

10021011
def _read_ready(self):
1012+
if self._conn_lost:
1013+
return
10031014
try:
10041015
data, addr = self._sock.recvfrom(self.max_size)
10051016
except (BlockingIOError, InterruptedError):

tests/test_selector_events.py

Lines changed: 13 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1087,17 +1087,6 @@ def test_write_ready_exception(self):
10871087
err,
10881088
'Fatal write error on socket transport')
10891089

1090-
@mock.patch('asyncio.base_events.logger')
1091-
def test_write_ready_exception_and_close(self, m_log):
1092-
self.sock.send.side_effect = OSError()
1093-
remove_writer = self.loop.remove_writer = mock.Mock()
1094-
1095-
transport = self.socket_transport()
1096-
transport.close()
1097-
transport._buffer.extend(b'data')
1098-
transport._write_ready()
1099-
remove_writer.assert_called_with(self.sock_fd)
1100-
11011090
def test_write_eof(self):
11021091
tr = self.socket_transport()
11031092
self.assertTrue(tr.can_write_eof())
@@ -1121,6 +1110,14 @@ def test_write_eof_buffer(self):
11211110
self.sock.shutdown.assert_called_with(socket.SHUT_WR)
11221111
tr.close()
11231112

1113+
@mock.patch('asyncio.base_events.logger')
1114+
def test_transport_close_remove_writer(self, m_log):
1115+
remove_writer = self.loop.remove_writer = mock.Mock()
1116+
1117+
transport = self.socket_transport()
1118+
transport.close()
1119+
remove_writer.assert_called_with(self.sock_fd)
1120+
11241121

11251122
@unittest.skipIf(ssl is None, 'No ssl module')
11261123
class SelectorSslTransportTests(test_utils.TestCase):
@@ -1175,7 +1172,7 @@ def test_on_handshake_exc(self):
11751172
self.sslsock.do_handshake.side_effect = exc
11761173
with test_utils.disable_logger():
11771174
waiter = asyncio.Future(loop=self.loop)
1178-
transport = self.ssl_transport(waiter=waiter)
1175+
self.ssl_transport(waiter=waiter)
11791176
self.assertTrue(waiter.done())
11801177
self.assertIs(exc, waiter.exception())
11811178
self.assertTrue(self.sslsock.close.called)
@@ -1374,20 +1371,19 @@ def test_write_ready_send_closing_partial(self):
13741371
def test_write_ready_send_closing(self):
13751372
self.sslsock.send.return_value = 4
13761373
transport = self._make_one()
1377-
transport.close()
13781374
transport._buffer = list_to_buffer([b'data'])
1375+
transport.close()
13791376
transport._write_ready()
1380-
self.assertFalse(self.loop.writers)
13811377
self.protocol.connection_lost.assert_called_with(None)
13821378

13831379
def test_write_ready_send_closing_empty_buffer(self):
13841380
self.sslsock.send.return_value = 4
1381+
call_soon = self.loop.call_soon = mock.Mock()
13851382
transport = self._make_one()
1386-
transport.close()
13871383
transport._buffer = list_to_buffer()
1384+
transport.close()
13881385
transport._write_ready()
1389-
self.assertFalse(self.loop.writers)
1390-
self.protocol.connection_lost.assert_called_with(None)
1386+
call_soon.assert_called_with(transport._call_connection_lost, None)
13911387

13921388
def test_write_ready_send_retry(self):
13931389
transport = self._make_one()

0 commit comments

Comments
 (0)