summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorAlex Trotsenko <alex1973tr@gmail.com>2015-06-02 22:01:44 +0300
committerAlex Trotsenko <alex1973tr@gmail.com>2016-01-12 18:00:58 +0000
commit7d257aab8175f3d4fd3b838d4f47457a8d868885 (patch)
tree7ebbbc4809561ad8a95961e1914890d37f19a934 /src
parent98cea2b6c49940e806c102cd33381807d86df44e (diff)
QIODevice: handle incomplete reads
Introduce a transaction mechanism that gives the ability to read the data atomically. Current implementation supports transactions for both types of devices. For sequential devices, it records the whole input stream during transaction. For random-access devices, device position is saved when transaction starts. If an error occurs, the application may be able to recover the input stream by rolling back to the start point. Also, QIODevice::peek() was rewritten to make use of transactions internally. The replacement of QIODevicePrivateLinearBuffer by QRingBuffer is closely entangled with that, which makes it unfeasible to do separately. Bump the TypeInformationVersion field in qtHookData, to notify the Qt Creator developers that the offset of QFilePrivate::fileName was changed and dumpers should be adapted. [ChangeLog][QtCore] Added QIODevice's startTransaction(), commitTransaction(), rollbackTransaction(), isTransactionStarted() functions to support the read transactions. Task-number: QTBUG-44418 Change-Id: I3564b343ebeeaaf7c48a1dcdb7ef0a7ffec550f2 Reviewed-by: Joerg Bornemann <joerg.bornemann@theqtcompany.com> Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@theqtcompany.com>
Diffstat (limited to 'src')
-rw-r--r--src/corelib/global/qhooks.cpp2
-rw-r--r--src/corelib/io/qfiledevice.cpp2
-rw-r--r--src/corelib/io/qiodevice.cpp244
-rw-r--r--src/corelib/io/qiodevice.h5
-rw-r--r--src/corelib/io/qiodevice_p.h143
-rw-r--r--src/corelib/io/qprocess.cpp18
-rw-r--r--src/network/ssl/qsslsocket.cpp4
7 files changed, 233 insertions, 185 deletions
diff --git a/src/corelib/global/qhooks.cpp b/src/corelib/global/qhooks.cpp
index 40a7c88f13..88df9c2be9 100644
--- a/src/corelib/global/qhooks.cpp
+++ b/src/corelib/global/qhooks.cpp
@@ -61,7 +61,7 @@ quintptr Q_CORE_EXPORT qtHookData[] = {
// The required sizes and offsets are tested in tests/auto/other/toolsupport.
// When this fails and the change was intentional, adjust the test and
// adjust this value here.
- 0
+ 1
};
Q_STATIC_ASSERT(QHooks::LastHookIndex == sizeof(qtHookData) / sizeof(qtHookData[0]));
diff --git a/src/corelib/io/qfiledevice.cpp b/src/corelib/io/qfiledevice.cpp
index 4c5ed0aef6..e94da6de64 100644
--- a/src/corelib/io/qfiledevice.cpp
+++ b/src/corelib/io/qfiledevice.cpp
@@ -355,7 +355,7 @@ bool QFileDevice::atEnd() const
Q_D(const QFileDevice);
// If there's buffered data left, we're not at the end.
- if (!d->buffer.isEmpty())
+ if (!d->isBufferEmpty())
return false;
if (!isOpen())
diff --git a/src/corelib/io/qiodevice.cpp b/src/corelib/io/qiodevice.cpp
index 64078b5c54..00b50af5ca 100644
--- a/src/corelib/io/qiodevice.cpp
+++ b/src/corelib/io/qiodevice.cpp
@@ -143,7 +143,9 @@ static void checkWarnMessage(const QIODevice *device, const char *function, cons
*/
QIODevicePrivate::QIODevicePrivate()
: openMode(QIODevice::NotOpen), buffer(QIODEVICE_BUFFERSIZE),
- pos(0), devicePos(0)
+ pos(0), devicePos(0),
+ transactionPos(0),
+ transactionStarted(false)
, baseReadLineDataCalled(false)
, accessMode(Unset)
#ifdef QT_NO_QOBJECT
@@ -264,6 +266,12 @@ QIODevicePrivate::~QIODevicePrivate()
subclassing QIODevice, remember to bypass any buffer you may use
when the device is open in Unbuffered mode.
+ Usually, the incoming data stream from an asynchronous device is
+ fragmented, and chunks of data can arrive at arbitrary points in time.
+ To handle incomplete reads of data structures, use the transaction
+ mechanism implemented by QIODevice. See startTransaction() and related
+ functions for more details.
+
\sa QBuffer, QFile, QTcpSocket
*/
@@ -588,6 +596,8 @@ void QIODevice::close()
d->openMode = NotOpen;
d->errorString.clear();
d->pos = 0;
+ d->transactionStarted = false;
+ d->transactionPos = 0;
d->buffer.clear();
}
@@ -660,18 +670,8 @@ bool QIODevice::seek(qint64 pos)
this, pos, d->pos, d->buffer.size());
#endif
- qint64 offset = pos - d->pos;
- d->pos = pos;
d->devicePos = pos;
-
- if (offset < 0 || offset >= d->buffer.size())
- // When seeking backwards, an operation that is only allowed for
- // random-access devices, the buffer is cleared. The next read
- // operation will then refill the buffer. We can optimize this, if we
- // find that seeking backwards becomes a significant performance hit.
- d->buffer.clear();
- else
- d->buffer.skip(offset);
+ d->seekBuffer(pos);
#if defined QIODEVICE_DEBUG
printf("%p \tafter: d->pos == %lld, d->buffer.size() == %lld\n", this, d->pos,
@@ -681,6 +681,24 @@ bool QIODevice::seek(qint64 pos)
}
/*!
+ \internal
+*/
+void QIODevicePrivate::seekBuffer(qint64 newPos)
+{
+ const qint64 offset = newPos - pos;
+ pos = newPos;
+
+ if (offset < 0 || offset >= buffer.size()) {
+ // When seeking backwards, an operation that is only allowed for
+ // random-access devices, the buffer is cleared. The next read
+ // operation will then refill the buffer.
+ buffer.clear();
+ } else {
+ buffer.free(offset);
+ }
+}
+
+/*!
Returns \c true if the current read and write position is at the end
of the device (i.e. there is no more data available for reading on
the device); otherwise returns \c false.
@@ -695,7 +713,7 @@ bool QIODevice::seek(qint64 pos)
bool QIODevice::atEnd() const
{
Q_D(const QIODevice);
- const bool result = (d->openMode == NotOpen || (d->buffer.isEmpty()
+ const bool result = (d->openMode == NotOpen || (d->isBufferEmpty()
&& bytesAvailable() == 0));
#if defined QIODEVICE_DEBUG
printf("%p QIODevice::atEnd() returns %s, d->openMode == %d, d->pos == %lld\n", this,
@@ -740,7 +758,7 @@ qint64 QIODevice::bytesAvailable() const
Q_D(const QIODevice);
if (!d->isSequential())
return qMax(size() - d->pos, qint64(0));
- return d->buffer.size();
+ return d->buffer.size() - d->transactionPos;
}
/*! For buffered devices, this function returns the number of bytes
@@ -777,9 +795,10 @@ qint64 QIODevice::read(char *data, qint64 maxSize)
#endif
const bool sequential = d->isSequential();
+ const bool keepDataInBuffer = sequential && d->transactionStarted;
// Short circuit for getChar()
- if (maxSize == 1) {
+ if (maxSize == 1 && !keepDataInBuffer) {
int chint;
while ((chint = d->buffer.getChar()) != -1) {
if (!sequential)
@@ -806,9 +825,13 @@ qint64 QIODevice::read(char *data, qint64 maxSize)
char *readPtr = data;
forever {
// Try reading from the buffer.
- qint64 bufferReadChunkSize = d->buffer.read(data, maxSize);
+ qint64 bufferReadChunkSize = keepDataInBuffer
+ ? d->buffer.peek(data, maxSize, d->transactionPos)
+ : d->buffer.read(data, maxSize);
if (bufferReadChunkSize > 0) {
- if (!sequential)
+ if (keepDataInBuffer)
+ d->transactionPos += bufferReadChunkSize;
+ else if (!sequential)
d->pos += bufferReadChunkSize;
readSoFar += bufferReadChunkSize;
data += bufferReadChunkSize;
@@ -826,7 +849,8 @@ qint64 QIODevice::read(char *data, qint64 maxSize)
// Make sure the device is positioned correctly.
if (sequential || d->pos == d->devicePos || seek(d->pos)) {
madeBufferReadsOnly = false; // fix readData attempt
- if (maxSize >= QIODEVICE_BUFFERSIZE || (d->openMode & Unbuffered)) {
+ if ((maxSize >= QIODEVICE_BUFFERSIZE || (d->openMode & Unbuffered))
+ && !keepDataInBuffer) {
// Read big chunk directly to output buffer
readFromDevice = readData(data, maxSize);
deviceAtEof = (readFromDevice != maxSize);
@@ -844,7 +868,9 @@ qint64 QIODevice::read(char *data, qint64 maxSize)
}
}
} else {
- const qint64 bytesToBuffer = QIODEVICE_BUFFERSIZE;
+ // Do not read more than maxSize on unbuffered devices
+ const qint64 bytesToBuffer = (d->openMode & Unbuffered)
+ ? qMin(maxSize, QIODEVICE_BUFFERSIZE) : QIODEVICE_BUFFERSIZE;
// Try to fill QIODevice buffer by single read
readFromDevice = readData(d->buffer.reserve(bytesToBuffer), bytesToBuffer);
deviceAtEof = (readFromDevice != bytesToBuffer);
@@ -907,10 +933,8 @@ qint64 QIODevice::read(char *data, qint64 maxSize)
debugBinaryString(data - readSoFar, readSoFar);
#endif
- if (madeBufferReadsOnly && d->buffer.isEmpty()) {
- d->buffer.clear();
+ if (madeBufferReadsOnly && d->isBufferEmpty())
readData(data, 0);
- }
return readSoFar;
}
@@ -992,7 +1016,9 @@ QByteArray QIODevice::readAll()
qint64 readBytes = (d->isSequential() ? Q_INT64_C(0) : size());
if (readBytes == 0) {
// Size is unknown, read incrementally.
- qint64 readChunkSize = qMax(d->buffer.size(), QIODEVICE_BUFFERSIZE);
+ qint64 readChunkSize = qMax(QIODEVICE_BUFFERSIZE,
+ d->isSequential() ? (d->buffer.size() - d->transactionPos)
+ : d->buffer.size());
qint64 readResult;
do {
if (readBytes + readChunkSize >= MaxByteArraySize) {
@@ -1077,21 +1103,35 @@ qint64 QIODevice::readLine(char *data, qint64 maxSize)
--maxSize;
const bool sequential = d->isSequential();
+ const bool keepDataInBuffer = sequential && d->transactionStarted;
qint64 readSoFar = 0;
- if (!d->buffer.isEmpty()) {
- readSoFar = d->buffer.readLine(data, maxSize);
+ if (keepDataInBuffer) {
+ if (d->transactionPos < d->buffer.size()) {
+ // Peek line from the specified position
+ const qint64 i = d->buffer.indexOf('\n', maxSize, d->transactionPos);
+ readSoFar = d->buffer.peek(data, i >= 0 ? (i - d->transactionPos + 1) : maxSize,
+ d->transactionPos);
+ d->transactionPos += readSoFar;
+ if (d->transactionPos == d->buffer.size())
+ readData(data, 0);
+ }
+ } else if (!d->buffer.isEmpty()) {
+ // QRingBuffer::readLine() terminates the line with '\0'
+ readSoFar = d->buffer.readLine(data, maxSize + 1);
if (d->buffer.isEmpty())
readData(data,0);
if (!sequential)
d->pos += readSoFar;
+ }
+
+ if (readSoFar) {
#if defined QIODEVICE_DEBUG
printf("%p \tread from buffer: %lld bytes, last character read: %hhx\n", this,
readSoFar, data[readSoFar - 1]);
- if (readSoFar)
- debugBinaryString(data, int(readSoFar));
+ debugBinaryString(data, int(readSoFar));
#endif
- if (readSoFar && data[readSoFar - 1] == '\n') {
+ if (data[readSoFar - 1] == '\n') {
if (d->openMode & Text) {
// QRingBuffer::readLine() isn't Text aware.
if (readSoFar > 1 && data[readSoFar - 2] == '\r') {
@@ -1107,7 +1147,11 @@ qint64 QIODevice::readLine(char *data, qint64 maxSize)
if (d->pos != d->devicePos && !sequential && !seek(d->pos))
return qint64(-1);
d->baseReadLineDataCalled = false;
- qint64 readBytes = readLineData(data + readSoFar, maxSize - readSoFar);
+ // Force base implementation for transaction on sequential device
+ // as it stores the data in internal buffer automatically.
+ qint64 readBytes = keepDataInBuffer
+ ? QIODevice::readLineData(data + readSoFar, maxSize - readSoFar)
+ : readLineData(data + readSoFar, maxSize - readSoFar);
#if defined QIODEVICE_DEBUG
printf("%p \tread from readLineData: %lld bytes, readSoFar = %lld bytes\n", this,
readBytes, readSoFar);
@@ -1262,7 +1306,95 @@ qint64 QIODevice::readLineData(char *data, qint64 maxSize)
*/
bool QIODevice::canReadLine() const
{
- return d_func()->buffer.canReadLine();
+ Q_D(const QIODevice);
+ return d->buffer.indexOf('\n', d->buffer.size(),
+ d->isSequential() ? d->transactionPos : Q_INT64_C(0)) >= 0;
+}
+
+/*!
+ \since 5.7
+
+ Starts a new read transaction on the device.
+
+ Defines a restorable point within the sequence of read operations. For
+ sequential devices, read data will be duplicated internally to allow
+ recovery in case of incomplete reads. For random-access devices,
+ this function saves the current position. Call commitTransaction() or
+ rollbackTransaction() to finish the transaction.
+
+ \note Nesting transactions is not supported.
+
+ \sa commitTransaction(), rollbackTransaction()
+*/
+void QIODevice::startTransaction()
+{
+ Q_D(QIODevice);
+ if (d->transactionStarted) {
+ checkWarnMessage(this, "startTransaction", "Called while transaction already in progress");
+ return;
+ }
+ d->transactionPos = d->pos;
+ d->transactionStarted = true;
+}
+
+/*!
+ \since 5.7
+
+ Completes a read transaction.
+
+ For sequential devices, all data recorded in the internal buffer during
+ the transaction will be discarded.
+
+ \sa startTransaction(), rollbackTransaction()
+*/
+void QIODevice::commitTransaction()
+{
+ Q_D(QIODevice);
+ if (!d->transactionStarted) {
+ checkWarnMessage(this, "commitTransaction", "Called while no transaction in progress");
+ return;
+ }
+ if (d->isSequential())
+ d->buffer.free(d->transactionPos);
+ d->transactionStarted = false;
+ d->transactionPos = 0;
+}
+
+/*!
+ \since 5.7
+
+ Rolls back a read transaction.
+
+ Restores the input stream to the point of the startTransaction() call.
+ This function is commonly used to rollback the transaction when an
+ incomplete read was detected prior to committing the transaction.
+
+ \sa startTransaction(), commitTransaction()
+*/
+void QIODevice::rollbackTransaction()
+{
+ Q_D(QIODevice);
+ if (!d->transactionStarted) {
+ checkWarnMessage(this, "rollbackTransaction", "Called while no transaction in progress");
+ return;
+ }
+ if (!d->isSequential())
+ d->seekBuffer(d->transactionPos);
+ d->transactionStarted = false;
+ d->transactionPos = 0;
+}
+
+/*!
+ \since 5.7
+
+ Returns \c true if a transaction is in progress on the device, otherwise
+ \c false.
+
+ \sa startTransaction()
+*/
+bool QIODevice::isTransactionStarted() const
+{
+ return d_func()->transactionStarted;
}
/*!
@@ -1386,12 +1518,19 @@ qint64 QIODevice::write(const char *data)
If \a c was not previously read from the device, the behavior is
undefined.
+
+ \note This function is not available while a transaction is in progress.
*/
void QIODevice::ungetChar(char c)
{
Q_D(QIODevice);
CHECK_READABLE(read, Q_VOID);
+ if (d->transactionStarted) {
+ checkWarnMessage(this, "ungetChar", "Called while transaction is in progress");
+ return;
+ }
+
#if defined QIODEVICE_DEBUG
printf("%p QIODevice::ungetChar(0x%hhx '%c')\n", this, c, isprint(c) ? c : '?');
#endif
@@ -1426,13 +1565,26 @@ bool QIODevicePrivate::putCharHelper(char c)
*/
qint64 QIODevicePrivate::peek(char *data, qint64 maxSize)
{
- qint64 readBytes = q_func()->read(data, maxSize);
- if (readBytes <= 0)
+ Q_Q(QIODevice);
+
+ if (transactionStarted) {
+ const qint64 savedTransactionPos = transactionPos;
+ const qint64 savedPos = pos;
+
+ qint64 readBytes = q->read(data, maxSize);
+
+ // Restore initial position
+ if (isSequential())
+ transactionPos = savedTransactionPos;
+ else
+ seekBuffer(savedPos);
return readBytes;
+ }
+
+ q->startTransaction();
+ qint64 readBytes = q->read(data, maxSize);
+ q->rollbackTransaction();
- buffer.ungetBlock(data, readBytes);
- if (!isSequential())
- pos -= readBytes;
return readBytes;
}
@@ -1441,14 +1593,26 @@ qint64 QIODevicePrivate::peek(char *data, qint64 maxSize)
*/
QByteArray QIODevicePrivate::peek(qint64 maxSize)
{
- QByteArray result = q_func()->read(maxSize);
+ Q_Q(QIODevice);
+
+ if (transactionStarted) {
+ const qint64 savedTransactionPos = transactionPos;
+ const qint64 savedPos = pos;
+
+ QByteArray result = q->read(maxSize);
- if (result.isEmpty())
+ // Restore initial position
+ if (isSequential())
+ transactionPos = savedTransactionPos;
+ else
+ seekBuffer(savedPos);
return result;
+ }
+
+ q->startTransaction();
+ QByteArray result = q->read(maxSize);
+ q->rollbackTransaction();
- buffer.ungetBlock(result.constData(), result.size());
- if (!isSequential())
- pos -= result.size();
return result;
}
diff --git a/src/corelib/io/qiodevice.h b/src/corelib/io/qiodevice.h
index b62c8d266c..49f6848540 100644
--- a/src/corelib/io/qiodevice.h
+++ b/src/corelib/io/qiodevice.h
@@ -111,6 +111,11 @@ public:
QByteArray readLine(qint64 maxlen = 0);
virtual bool canReadLine() const;
+ void startTransaction();
+ void commitTransaction();
+ void rollbackTransaction();
+ bool isTransactionStarted() const;
+
qint64 write(const char *data, qint64 len);
qint64 write(const char *data);
inline qint64 write(const QByteArray &data)
diff --git a/src/corelib/io/qiodevice_p.h b/src/corelib/io/qiodevice_p.h
index 56a89ab680..45f5219240 100644
--- a/src/corelib/io/qiodevice_p.h
+++ b/src/corelib/io/qiodevice_p.h
@@ -62,138 +62,6 @@ QT_BEGIN_NAMESPACE
Q_CORE_EXPORT int qt_subtract_from_timeout(int timeout, int elapsed);
-// This is QIODevice's read buffer, optimized for read(), isEmpty() and getChar()
-class QIODevicePrivateLinearBuffer
-{
-public:
- QIODevicePrivateLinearBuffer(int) : len(0), first(0), buf(0), capacity(0) {
- }
- ~QIODevicePrivateLinearBuffer() {
- delete [] buf;
- }
- void clear() {
- len = 0;
- delete [] buf;
- buf = 0;
- first = buf;
- capacity = 0;
- }
- qint64 size() const {
- return len;
- }
- bool isEmpty() const {
- return len == 0;
- }
- void skip(qint64 n) {
- if (n >= len) {
- clear();
- } else {
- len -= n;
- first += n;
- }
- }
- int getChar() {
- if (len == 0)
- return -1;
- int ch = uchar(*first);
- len--;
- first++;
- return ch;
- }
- qint64 read(char* target, qint64 size) {
- qint64 r = qMin(size, len);
- memcpy(target, first, r);
- len -= r;
- first += r;
- return r;
- }
- qint64 peek(char* target, qint64 size) {
- qint64 r = qMin(size, len);
- memcpy(target, first, r);
- return r;
- }
- char* reserve(qint64 size) {
- makeSpace(size + len, freeSpaceAtEnd);
- char* writePtr = first + len;
- len += size;
- return writePtr;
- }
- void chop(qint64 size) {
- if (size >= len) {
- clear();
- } else {
- len -= size;
- }
- }
- QByteArray readAll() {
- QByteArray retVal(first, len);
- clear();
- return retVal;
- }
- qint64 readLine(char* target, qint64 size) {
- qint64 r = qMin(size, len);
- char* eol = static_cast<char*>(memchr(first, '\n', r));
- if (eol)
- r = 1+(eol-first);
- memcpy(target, first, r);
- len -= r;
- first += r;
- return r;
- }
- bool canReadLine() const {
- return memchr(first, '\n', len);
- }
- void ungetChar(char c) {
- if (first == buf) {
- // underflow, the existing valid data needs to move to the end of the (potentially bigger) buffer
- makeSpace(len+1, freeSpaceAtStart);
- }
- first--;
- len++;
- *first = c;
- }
- void ungetBlock(const char* block, qint64 size) {
- if ((first - buf) < size) {
- // underflow, the existing valid data needs to move to the end of the (potentially bigger) buffer
- makeSpace(len + size, freeSpaceAtStart);
- }
- first -= size;
- len += size;
- memcpy(first, block, size);
- }
-
-private:
- enum FreeSpacePos {freeSpaceAtStart, freeSpaceAtEnd};
- void makeSpace(size_t required, FreeSpacePos where) {
- size_t newCapacity = qMax(capacity, size_t(QIODEVICE_BUFFERSIZE));
- while (newCapacity < required)
- newCapacity *= 2;
- const size_t moveOffset = (where == freeSpaceAtEnd) ? 0 : newCapacity - size_t(len);
- if (newCapacity > capacity) {
- // allocate more space
- char* newBuf = new char[newCapacity];
- memmove(newBuf + moveOffset, first, len);
- delete [] buf;
- buf = newBuf;
- capacity = newCapacity;
- } else {
- // shift any existing data to make space
- memmove(buf + moveOffset, first, len);
- }
- first = buf + moveOffset;
- }
-
-private:
- // length of the unread data
- qint64 len;
- // start of the unread data
- char* first;
- // the allocated buffer
- char* buf;
- // allocated buffer size
- size_t capacity;
-};
-
class Q_CORE_EXPORT QIODevicePrivate
#ifndef QT_NO_QOBJECT
: public QObjectPrivate
@@ -208,9 +76,11 @@ public:
QIODevice::OpenMode openMode;
QString errorString;
- QIODevicePrivateLinearBuffer buffer;
+ QRingBuffer buffer;
qint64 pos;
qint64 devicePos;
+ qint64 transactionPos;
+ bool transactionStarted;
bool baseReadLineDataCalled;
virtual bool putCharHelper(char c);
@@ -228,6 +98,13 @@ public:
return accessMode == Sequential;
}
+ inline bool isBufferEmpty() const
+ {
+ return buffer.isEmpty() || (transactionStarted && isSequential()
+ && transactionPos == buffer.size());
+ }
+ void seekBuffer(qint64 newPos);
+
virtual qint64 peek(char *data, qint64 maxSize);
virtual QByteArray peek(qint64 maxSize);
diff --git a/src/corelib/io/qprocess.cpp b/src/corelib/io/qprocess.cpp
index 823dc4c144..2392f7cbfd 100644
--- a/src/corelib/io/qprocess.cpp
+++ b/src/corelib/io/qprocess.cpp
@@ -1395,15 +1395,17 @@ QProcess::ProcessChannel QProcess::readChannel() const
void QProcess::setReadChannel(ProcessChannel channel)
{
Q_D(QProcess);
+
+ if (d->transactionStarted) {
+ qWarning("QProcess::setReadChannel: Failed due to the active read transaction");
+ return;
+ }
+
if (d->processChannel != channel) {
- QByteArray buf = d->buffer.readAll();
- if (d->processChannel == QProcess::StandardOutput) {
- for (int i = buf.size() - 1; i >= 0; --i)
- d->stdoutChannel.buffer.ungetChar(buf.at(i));
- } else {
- for (int i = buf.size() - 1; i >= 0; --i)
- d->stderrChannel.buffer.ungetChar(buf.at(i));
- }
+ QRingBuffer *buffer = (d->processChannel == QProcess::StandardOutput)
+ ? &d->stdoutChannel.buffer
+ : &d->stderrChannel.buffer;
+ d->buffer.read(buffer->reserveFront(d->buffer.size()), d->buffer.size());
}
d->processChannel = channel;
}
diff --git a/src/network/ssl/qsslsocket.cpp b/src/network/ssl/qsslsocket.cpp
index 1dfd87a0f8..6f3ed58e18 100644
--- a/src/network/ssl/qsslsocket.cpp
+++ b/src/network/ssl/qsslsocket.cpp
@@ -2531,7 +2531,7 @@ qint64 QSslSocketPrivate::peek(char *data, qint64 maxSize)
if (mode == QSslSocket::UnencryptedMode && !autoStartHandshake) {
//unencrypted mode - do not use QIODevice::peek, as it reads ahead data from the plain socket
//peek at data already in the QIODevice buffer (from a previous read)
- qint64 r = buffer.peek(data, maxSize);
+ qint64 r = buffer.peek(data, maxSize, transactionPos);
if (r == maxSize)
return r;
data += r;
@@ -2560,7 +2560,7 @@ QByteArray QSslSocketPrivate::peek(qint64 maxSize)
//peek at data already in the QIODevice buffer (from a previous read)
QByteArray ret;
ret.reserve(maxSize);
- ret.resize(buffer.peek(ret.data(), maxSize));
+ ret.resize(buffer.peek(ret.data(), maxSize, transactionPos));
if (ret.length() == maxSize)
return ret;
//peek at data in the plain socket