diff options
author | Thiago Macieira <thiago.macieira@nokia.com> | 2009-04-03 14:51:21 (GMT) |
---|---|---|
committer | Thiago Macieira <thiago.macieira@nokia.com> | 2009-04-06 07:55:17 (GMT) |
commit | b11659ba9ea4532583398f6e539e78ed79a0c600 (patch) | |
tree | 20d6a95a1f626aaa3cc144140f39cbdf160d283b /src/network | |
parent | 020ced4994bace0ed7f494bec8905afa959f76ed (diff) | |
download | Qt-b11659ba9ea4532583398f6e539e78ed79a0c600.zip Qt-b11659ba9ea4532583398f6e539e78ed79a0c600.tar.gz Qt-b11659ba9ea4532583398f6e539e78ed79a0c600.tar.bz2 |
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
Diffstat (limited to 'src/network')
-rw-r--r-- | src/network/access/qnetworkreplyimpl.cpp | 44 |
1 files 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<qint64>(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<qint64>(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, |