8000 gh-103462: Ensure SelectorSocketTransport.writelines registers a writ… · python/cpython@19d2639 · GitHub
[go: up one dir, main page]

Skip to content

Commit 19d2639

Browse files
authored
gh-103462: Ensure SelectorSocketTransport.writelines registers a writer when data is still pending (#103463)
1 parent 9e67740 commit 19d2639

File tree

3 files changed

+49
-0
lines changed

3 files changed

+49
-0
lines changed

Lib/asyncio/selector_events.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1176,6 +1176,9 @@ def writelines(self, list_of_data):
11761176
return
11771177
self._buffer.extend([memoryview(data) for data in list_of_data])
11781178
self._write_ready()
1179+
# If the entire buffer couldn't be written, register a write handler
1180+
if self._buffer:
1181+
self._loop._add_writer(self._sock_fd, self._write_ready)
11791182

11801183
def can_write_eof(self):
11811184
return True

Lib/test/test_asyncio/test_selector_events.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -747,6 +747,48 @@ def test_write_sendmsg_no_data(self):
747747
self.assertFalse(self.sock.sendmsg.called)
748748
self.assertEqual(list_to_buffer([b'data']), transport._buffer)
749749

750+
@unittest.skipUnless(selector_events._HAS_SENDMSG, 'no sendmsg')
751+
def test_writelines_sendmsg_full(self):
752+
data = memoryview(b'data')
753+
self.sock.sendmsg = mock.Mock()
754+
self.sock.sendmsg.return_value = len(data)
755+
756+
transport = self.socket_transport(sendmsg=True)
757+
transport.writelines([data])
758+
self.assertTrue(self.sock.sendmsg.called)
759+
self.assertFalse(self.loop.writers)
760+
761+
@unittest.skipUnless(selector_events._HAS_SENDMSG, 'no sendmsg')
762+
def test_writelines_sendmsg_partial(self):
763+
data = memoryview(b'data')
764+
self.sock.sendmsg = mock.Mock()
765+
self.sock.sendmsg.return_value = 2
766+
767+
transport = self.socket_transport(sendmsg=True)
768+
transport.writelines([data])
769+
self.assertTrue(self.sock.sendmsg.called)
770+
self.assertTrue(self.loop.writers)
771+
772+
def test_writelines_send_full(self):
773+
data = memoryview(b'data')
774+
self.sock.send.return_value = len(data)
775+
self.sock.send.fileno.return_value = 7
776+
777+
transport = self.socket_transport()
778+
transport.writelines([data])
779+
self.assertTrue(self.sock.send.called)
780+
self.assertFalse(self.loop.writers)
781+
782+
def test_writelines_send_partial(self):
783+
data = memoryview(b'data')
784+
self.sock.send.return_value = 2
785+
self.sock.send.fileno.return_value = 7
786+
787+
transport = self.socket_transport()
788+
transport.writelines([data])
789+
self.assertTrue(self.sock.send.called)
790+
self.assertTrue(self.loop.writers)
791+
750792
@unittest.skipUnless(selector_events._HAS_SENDMSG, 'no sendmsg')
751793
def test_write_sendmsg_full(self):
752794
data = memoryview(b'data')
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Fixed an issue with using :meth:`~asyncio.WriteTransport.writelines` in :mod:`asyncio` to send very
2+
large payloads that exceed the amount of data that can be written in one
3+
call to :meth:`socket.socket.send` or :meth:`socket.socket.sendmsg`,
4+
resulting in the remaining buffer being left unwritten.

0 commit comments

Comments
 (0)
0