(original) (raw)

Index: Lib/socket.py =================================================================== --- Lib/socket.py (revision 74290) +++ Lib/socket.py (working copy) @@ -84,9 +84,10 @@ from StringIO import StringIO try: - from errno import EBADF + from errno import EBADF, EINTR except ImportError: EBADF = 9 + EINTR = 4 __all__ = ["getfqdn", "create_connection"] __all__.extend(os._get_exports_list(_socket)) @@ -392,7 +393,12 @@ data = None recv = self._sock.recv while data != "\n": - data = recv(1) + try: + data = recv(1) + except error, err: + if err[0] == EINTR: + continue + raise if not data: break buffers.append(data) @@ -401,7 +407,12 @@ buf.seek(0, 2) # seek end self._rbuf = StringIO() # reset _rbuf. we consume it via buf. while True: - data = self._sock.recv(self._rbufsize) + try: + data = self._sock.recv(self._rbufsize) + except error, err: + if err[0] == EINTR: + continue + raise if not data: break nl = data.find('\n') @@ -425,7 +436,12 @@ return rv self._rbuf = StringIO() # reset _rbuf. we consume it via buf. while True: - data = self._sock.recv(self._rbufsize) + try: + data = self._sock.recv(self._rbufsize) + except error, err: + if err[0] == EINTR: + continue + raise if not data: break left = size - buf_len Index: Lib/test/test_socket.py =================================================================== --- Lib/test/test_socket.py (revision 74290) +++ Lib/test/test_socket.py (working copy) @@ -826,6 +826,40 @@ def _testClosedAttr(self): self.assert_(not self.cli_file.closed) +class FileObjectInterruptedTestCase(unittest.TestCase): + """Test that the file object correctly handles being interrupted by a signal.""" + def setUp(self): + class MockSocket(object): + def __init__(self): + # Build a generator that returns functions that we'll call for each + # call to recv() + def raise_error(): + raise socket.error(errno.EINTR) + self._step = iter([ + lambda : "This is the first line\nAnd the sec", + raise_error, + lambda : "ond line is here\n", + lambda : None, + ]) + + def recv(self, size): + return self._step.next()() + + self._mock_sock = MockSocket() + + def _test_readline(self, fo): + self.assertEquals(fo.readline(), "This is the first line\n") + self.assertEquals(fo.readline(), "And the second line is here\n") + + def test_default(self): + fo = socket._fileobject(self._mock_sock) + self._test_readline(fo) + + def test_set_buffer(self): + fo = socket._fileobject(self._mock_sock, bufsize=1024) + self._test_readline(fo) + + class UnbufferedFileObjectClassTestCase(FileObjectClassTestCase): """Repeat the tests from FileObjectClassTestCase with bufsize==0. @@ -1221,6 +1255,7 @@ tests.extend([ NonBlockingTCPTests, FileObjectClassTestCase, + FileObjectInterruptedTestCase, UnbufferedFileObjectClassTestCase, LineBufferedFileObjectClassTestCase, SmallBufferedFileObjectClassTestCase,