Kaydet (Commit) fe9ebe4f authored tarafından Victor Stinner's avatar Victor Stinner

Issue #16133: The asynchat.async_chat.handle_read() method now ignores

socket.error() exceptions with blocking I/O errors: EAGAIN, EALREADY,
EINPROGRESS, or EWOULDBLOCK. Initial patch written by Xavier de Gaye.
üst 186f6654
...@@ -193,6 +193,11 @@ any that have been added to the map during asynchronous service) is closed. ...@@ -193,6 +193,11 @@ any that have been added to the map during asynchronous service) is closed.
Read at most *buffer_size* bytes from the socket's remote end-point. An Read at most *buffer_size* bytes from the socket's remote end-point. An
empty string implies that the channel has been closed from the other end. empty string implies that the channel has been closed from the other end.
Note that :meth:`recv` may raise :exc:`socket.error` with
:data:`~errno.EAGAIN` or :data:`~errno.EWOULDBLOCK`, even though
:func:`select.select` or :func:`select.poll` has reported the socket
ready for reading.
.. method:: listen(backlog) .. method:: listen(backlog)
......
...@@ -46,12 +46,17 @@ method) up to the terminator, and then control will be returned to ...@@ -46,12 +46,17 @@ method) up to the terminator, and then control will be returned to
you - by calling your self.found_terminator() method. you - by calling your self.found_terminator() method.
""" """
import socket
import asyncore import asyncore
import errno
import socket
from collections import deque from collections import deque
from sys import py3kwarning from sys import py3kwarning
from warnings import filterwarnings, catch_warnings from warnings import filterwarnings, catch_warnings
_BLOCKING_IO_ERRORS = (errno.EAGAIN, errno.EALREADY, errno.EINPROGRESS,
errno.EWOULDBLOCK)
class async_chat (asyncore.dispatcher): class async_chat (asyncore.dispatcher):
"""This is an abstract class. You must derive from this class, and add """This is an abstract class. You must derive from this class, and add
the two methods collect_incoming_data() and found_terminator()""" the two methods collect_incoming_data() and found_terminator()"""
...@@ -109,6 +114,8 @@ class async_chat (asyncore.dispatcher): ...@@ -109,6 +114,8 @@ class async_chat (asyncore.dispatcher):
try: try:
data = self.recv (self.ac_in_buffer_size) data = self.recv (self.ac_in_buffer_size)
except socket.error, why: except socket.error, why:
if why.args[0] in _BLOCKING_IO_ERRORS:
return
self.handle_error() self.handle_error()
return return
......
# test asynchat # test asynchat
import asyncore, asynchat, socket, time import errno
import asyncore
import asynchat
import socket
import time
import unittest import unittest
import sys import sys
from test import test_support from test import test_support
...@@ -235,6 +239,31 @@ class TestAsynchat(unittest.TestCase): ...@@ -235,6 +239,31 @@ class TestAsynchat(unittest.TestCase):
class TestAsynchat_WithPoll(TestAsynchat): class TestAsynchat_WithPoll(TestAsynchat):
usepoll = True usepoll = True
class TestAsynchatMocked(unittest.TestCase):
def test_blockingioerror(self):
# Issue #16133: handle_read() must ignore blocking I/O errors like
# EAGAIN
class fake_socket:
def fileno(self):
return 0
def recv(self, size):
raise socket.error(errno.EAGAIN, "EAGAIN")
class MyChat(asynchat.async_chat):
def handle_error(self):
raise Exception("error")
sock = fake_socket()
dispatcher = MyChat()
dispatcher.set_socket(sock)
self.addCleanup(dispatcher.del_channel)
# must not call handle_error()
dispatcher.handle_read()
class TestHelperFunctions(unittest.TestCase): class TestHelperFunctions(unittest.TestCase):
def test_find_prefix_at_end(self): def test_find_prefix_at_end(self):
self.assertEqual(asynchat.find_prefix_at_end("qwerty\r", "\r\n"), 1) self.assertEqual(asynchat.find_prefix_at_end("qwerty\r", "\r\n"), 1)
...@@ -267,6 +296,7 @@ class TestFifo(unittest.TestCase): ...@@ -267,6 +296,7 @@ class TestFifo(unittest.TestCase):
def test_main(verbose=None): def test_main(verbose=None):
test_support.run_unittest(TestAsynchat, TestAsynchat_WithPoll, test_support.run_unittest(TestAsynchat, TestAsynchat_WithPoll,
TestAsynchatMocked,
TestHelperFunctions, TestFifo) TestHelperFunctions, TestFifo)
if __name__ == "__main__": if __name__ == "__main__":
......
...@@ -13,6 +13,10 @@ Core and Builtins ...@@ -13,6 +13,10 @@ Core and Builtins
Library Library
------- -------
- Issue #16133: The asynchat.async_chat.handle_read() method now ignores
socket.error() exceptions with blocking I/O errors: EAGAIN, EALREADY,
EINPROGRESS, or EWOULDBLOCK.
- Issue #1730136: Fix the comparison between a tkFont.Font and an object of - Issue #1730136: Fix the comparison between a tkFont.Font and an object of
another kind. another kind.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment