From b11659ba9ea4532583398f6e539e78ed79a0c600 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Fri, 3 Apr 2009 16:51:21 +0200 Subject: Fix QNetworkReply's automatic pushing of a cache when the cache is more than 64k. This issue was found by Warwick: the copyReadyRead() slot is called only once as a result of readyRead(), but since there's no more data to be received (the source QIODevice is a QBuffer), we'll never get a readyRead() again. So, if we don't have a limited buffer size, we should read everything. This applies to QFile as well. The side-effect is that we cause the entire QFile to be loaded to memory, so if you had a 2 GB cache entry, you'll probably run out of memory. Future optimisations: - don't memcpy the data from a QBuffer into another buffer - find a way to avoid loading the entire contents of the file (probably not possible with the default QNetworkDiskCache since that may compress the data, so we won't know the size and thus can't fake finished()) Reviewed-by: Warwick Allison --- src/network/access/qnetworkreplyimpl.cpp | 44 ++++++++++++++++++++------------ 1 file changed, 27 insertions(+), 17 deletions(-) diff --git a/src/network/access/qnetworkreplyimpl.cpp b/src/network/access/qnetworkreplyimpl.cpp index eaa572f..79c3d1a 100644 --- a/src/network/access/qnetworkreplyimpl.cpp +++ b/src/network/access/qnetworkreplyimpl.cpp @@ -131,27 +131,37 @@ void QNetworkReplyImplPrivate::_q_copyReadyRead() if (!copyDevice && !q->isOpen()) return; - qint64 bytesToRead = nextDownstreamBlockSize(); - if (bytesToRead == 0) - // we'll be called again, eventually - return; + forever { + qint64 bytesToRead = nextDownstreamBlockSize(); + if (bytesToRead == 0) + // we'll be called again, eventually + break; - bytesToRead = qBound(1, bytesToRead, copyDevice->bytesAvailable()); - char *ptr = readBuffer.reserve(bytesToRead); - qint64 bytesActuallyRead = copyDevice->read(ptr, bytesToRead); - if (bytesActuallyRead == -1) { - readBuffer.chop(bytesToRead); - backendNotify(NotifyCopyFinished); - return; - } + bytesToRead = qBound(1, bytesToRead, copyDevice->bytesAvailable()); + char *ptr = readBuffer.reserve(bytesToRead); + qint64 bytesActuallyRead = copyDevice->read(ptr, bytesToRead); + if (bytesActuallyRead == -1) { + readBuffer.chop(bytesToRead); + backendNotify(NotifyCopyFinished); + return; + } - if (bytesActuallyRead != bytesToRead) - readBuffer.chop(bytesToRead - bytesActuallyRead); + if (bytesActuallyRead != bytesToRead) + readBuffer.chop(bytesToRead - bytesActuallyRead); - if (!copyDevice->isSequential() && copyDevice->atEnd()) - backendNotify(NotifyCopyFinished); + if (!copyDevice->isSequential() && copyDevice->atEnd()) { + backendNotify(NotifyCopyFinished); + break; + } + + bytesDownloaded += bytesActuallyRead; + } + + if (bytesDownloaded == lastBytesDownloaded) { + // we didn't read anything + return; + } - bytesDownloaded += bytesActuallyRead; lastBytesDownloaded = bytesDownloaded; QVariant totalSize = cookedHeaders.value(QNetworkRequest::ContentLengthHeader); emit q->downloadProgress(bytesDownloaded, -- cgit v0.12