diff -r 9770d5114890 -r 666c3f440c4b Lib/test/test_socket.py --- a/Lib/test/test_socket.py Thu Jan 13 03:52:26 2011 +0100 +++ b/Lib/test/test_socket.py Thu Jan 13 11:23:45 2011 +0200 @@ -441,6 +441,45 @@ # Check that setting it to an invalid type raises TypeError self.assertRaises(TypeError, socket.setdefaulttimeout, "spam") + def test_7322(self): + # Test issue 7322: Don't lose data after calling readline() + # on a socket with a timeout + self._test_7322("rb", 0, b"XXXYYYZZZ", b"XXXYYYZZZ", b"a", b"a") + self._test_7322("rb", 5, b"XXXYYYZZZ", b"XXXYYYZZZ", b"a", b"a") + self._test_7322("rb", 10, b"XXXYYYZZZ", b"XXXYYYZZZ", b"a", b"a") + self._test_7322("r", 5, b"XXXYYYZZZ", "XXXYYYZZZ", b"a", "a") + self._test_7322("r", 10, b"XXXYYYZZZ", "XXXYYYZZZ", b"a", "a") + self._test_7322("rb", 0, b"", b"", b"a", b"a") + self._test_7322("rb", 5, b"", b"", b"a", b"a") + self._test_7322("r", 5, b"", "", b"a", "a") + + def _test_7322_setup(self): + with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: + c = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + s.bind(('', 0)) + s.listen(5) + c.connect(('localhost', s.getsockname()[1])) + c.settimeout(1) + return (c, s.accept()[0]) + + def _test_7322(self, mode, bufsize, s1, s2, s3, s4): + c, s = self._test_7322_setup() + try: + f = c.makefile(mode, buffering=bufsize) + s.send(s1) + + try: + print(f.readline()) + except socket.timeout as e: + assert(e.data == s2) + + s.send(s3) + assert(f.read(1) == s4) + finally: + f.close() + c.close() + s.close() + def testIPv4_inet_aton_fourbytes(self): if not hasattr(socket, 'inet_aton'): return # No inet_aton, nothing to check diff -r 9770d5114890 -r 666c3f440c4b Modules/_io/bufferedio.c --- a/Modules/_io/bufferedio.c Thu Jan 13 03:52:26 2011 +0100 +++ b/Modules/_io/bufferedio.c Thu Jan 13 11:23:45 2011 +0200 @@ -902,6 +902,7 @@ static PyObject * _buffered_readline(buffered *self, Py_ssize_t limit) { + PyObject *ptype, *pvalue, *ptraceback; PyObject *res = NULL; PyObject *chunks = NULL; Py_ssize_t n, written = 0; @@ -1005,6 +1006,15 @@ end: LEAVE_BUFFERED(self) end_unlocked: + if (res == NULL && chunks != NULL) { + res = _PyBytes_Join(_PyIO_empty_bytes, chunks); + PyErr_Fetch(&ptype, &pvalue, &ptraceback); + PyObject_SetAttrString(pvalue, "data", res); + PyErr_Restore(ptype, pvalue, ptraceback); + Py_DECREF(res); + Py_DECREF(chunks); + return NULL; + } Py_XDECREF(chunks); return res; } diff -r 9770d5114890 -r 666c3f440c4b Modules/_io/iobase.c --- a/Modules/_io/iobase.c Thu Jan 13 03:52:26 2011 +0100 +++ b/Modules/_io/iobase.c Thu Jan 13 11:23:45 2011 +0200 @@ -446,6 +446,7 @@ iobase_readline(PyObject *self, PyObject *args) { /* For backwards compatibility, a (slowish) readline(). */ + PyObject *ptype, *pvalue, *ptraceback; Py_ssize_t limit = -1; int has_peek = 0; @@ -533,6 +534,12 @@ Py_DECREF(buffer); return result; fail: + result = PyBytes_FromStringAndSize(PyByteArray_AS_STRING(buffer), + PyByteArray_GET_SIZE(buffer)); + PyErr_Fetch(&ptype, &pvalue, &ptraceback); + PyObject_SetAttrString(pvalue, "data", result); + PyErr_Restore(ptype, pvalue, ptraceback); + Py_DECREF(result); Py_DECREF(buffer); return NULL; } diff -r 9770d5114890 -r 666c3f440c4b Modules/_io/textio.c --- a/Modules/_io/textio.c Thu Jan 13 03:52:26 2011 +0100 +++ b/Modules/_io/textio.c Thu Jan 13 11:23:45 2011 +0200 @@ -1672,6 +1672,7 @@ static PyObject * _textiowrapper_readline(textio *self, Py_ssize_t limit) { + PyObject *ptype, *pvalue, *ptraceback; PyObject *line = NULL, *chunks = NULL, *remaining = NULL; Py_ssize_t start, endpos, chunked, offset_to_buffer; int res; @@ -1817,6 +1818,18 @@ return line; error: + Py_XDECREF(line); + line = PyUnicode_Join(_PyIO_empty_str, chunks); + if (line == NULL) + line = PyUnicode_FromStringAndSize(NULL, 0); + if (remaining != NULL) { + PyObject *result = PyUnicode_Concat(line, remaining); + Py_XDECREF(line); + line = result; + } + PyErr_Fetch(&ptype, &pvalue, &ptraceback); + PyObject_SetAttrString(pvalue, "data", line); + PyErr_Restore(ptype, pvalue, ptraceback); Py_XDECREF(chunks); Py_XDECREF(remaining); Py_XDECREF(line);