Index: Modules/_io/bufferedio.c =================================================================== --- Modules/_io/bufferedio.c (revision 73404) +++ Modules/_io/bufferedio.c (working copy) @@ -1425,27 +1425,39 @@ _bufferedreader_peek_unlocked(buffered *self, Py_ssize_t n) { Py_ssize_t have, r; + PyObject *ret, *chunk; - have = Py_SAFE_DOWNCAST(READAHEAD(self), Py_off_t, Py_ssize_t); - /* Constraints: - 1. we don't want to advance the file position. - 2. we don't want to lose block alignment, so we can't shift the buffer - to make some place. - Therefore, we either return `have` bytes (if > 0), or a full buffer. - */ - if (have > 0) { - return PyBytes_FromStringAndSize(self->buffer + self->pos, have); + ret = PyBytes_FromString(""); + + /* Loop over several chunks of data + until we cannot get anymore bytes + and then send back to the user + what we got (unless we got an error) */ + while (n > 0) { + have = Py_SAFE_DOWNCAST(READAHEAD(self), Py_off_t, Py_ssize_t); + if (have >= n) { + chunk = PyBytes_FromStringAndSize(self->buffer + self->pos, n); + PyBytes_ConcatAndDel(&ret, chunk); + return ret; + } + else if (have > 0) { + chunk = PyBytes_FromStringAndSize(self->buffer + self->pos, have); + PyBytes_ConcatAndDel(&ret, chunk); + n -= have; + } + + _bufferedreader_reset_buf(self); + r = _bufferedreader_fill_buffer(self); + if (r == -1) { + PyObject_Del(ret); + return NULL; + } + if (r == -2) { + /* Return 'ret' as it is now */ + return ret; + } + self->pos = 0; } - - /* Fill the buffer from the raw stream, and copy it to the result. */ - _bufferedreader_reset_buf(self); - r = _bufferedreader_fill_buffer(self); - if (r == -1) - return NULL; - if (r == -2) - r = 0; - self->pos = 0; - return PyBytes_FromStringAndSize(self->buffer, r); } static PyMethodDef bufferedreader_methods[] = {