diff options
author | Mårten Nordheim <marten.nordheim@qt.io> | 2020-05-13 11:04:28 +0200 |
---|---|---|
committer | Mårten Nordheim <marten.nordheim@qt.io> | 2021-06-12 00:04:04 +0200 |
commit | 6f25051536c1636688a0a0939196007aac34676d (patch) | |
tree | 390fc3fc4e0147a51d56aee6d563614b77981b6a /src/network/access | |
parent | f9b867216ba2728ff993020599f5062e2f023de1 (diff) |
QNetworkReply: Decompress when reading
Rather than when the data is received. Source compatibility is
achieved through double-decompressing the data. This lets us know
how many bytes are available just as before but without having the
uncompressed data left in memory.
Fixes: QTBUG-83269
Change-Id: I352bd09581614c582e4628243e2a0e895ba4946b
Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
Diffstat (limited to 'src/network/access')
-rw-r--r-- | src/network/access/qhttp2protocolhandler.cpp | 24 | ||||
-rw-r--r-- | src/network/access/qhttpnetworkconnection.cpp | 1 | ||||
-rw-r--r-- | src/network/access/qhttpnetworkreply.cpp | 38 | ||||
-rw-r--r-- | src/network/access/qhttpnetworkreply_p.h | 2 | ||||
-rw-r--r-- | src/network/access/qhttpnetworkrequest.cpp | 13 | ||||
-rw-r--r-- | src/network/access/qhttpnetworkrequest_p.h | 4 | ||||
-rw-r--r-- | src/network/access/qhttpprotocolhandler.cpp | 3 | ||||
-rw-r--r-- | src/network/access/qhttpthreaddelegate.cpp | 5 | ||||
-rw-r--r-- | src/network/access/qhttpthreaddelegate_p.h | 4 | ||||
-rw-r--r-- | src/network/access/qnetworkreplyhttpimpl.cpp | 174 | ||||
-rw-r--r-- | src/network/access/qnetworkreplyhttpimpl_p.h | 9 |
11 files changed, 155 insertions, 122 deletions
diff --git a/src/network/access/qhttp2protocolhandler.cpp b/src/network/access/qhttp2protocolhandler.cpp index aaa7b58ac4..3b28775466 100644 --- a/src/network/access/qhttp2protocolhandler.cpp +++ b/src/network/access/qhttp2protocolhandler.cpp @@ -1233,13 +1233,8 @@ void QHttp2ProtocolHandler::updateStream(Stream &stream, const HPack::HttpHeader if (QHttpNetworkReply::isHttpRedirect(statusCode) && redirectUrl.isValid()) httpReply->setRedirectUrl(redirectUrl); - if (httpReplyPrivate->isCompressed() && httpRequest.d->autoDecompress) { + if (httpReplyPrivate->isCompressed() && httpRequest.d->autoDecompress) httpReplyPrivate->removeAutoDecompressHeader(); - httpReplyPrivate->decompressHelper.setEncoding( - httpReplyPrivate->headerField("content-encoding")); - httpReplyPrivate->decompressHelper.setMinimumArchiveBombSize( - httpReplyPrivate->request.minimumArchiveBombSize()); - } if (QHttpNetworkReply::isHttpRedirect(statusCode)) { // Note: This status code can trigger uploadByteDevice->reset() in @@ -1276,27 +1271,12 @@ void QHttp2ProtocolHandler::updateStream(Stream &stream, const Frame &frame, if (const auto length = frame.dataSize()) { const char *data = reinterpret_cast<const char *>(frame.dataBegin()); - auto &httpRequest = stream.request(); auto replyPrivate = httpReply->d_func(); replyPrivate->totalProgress += length; const QByteArray wrapped(data, length); - if (httpRequest.d->autoDecompress && replyPrivate->isCompressed()) { - Q_ASSERT(replyPrivate->decompressHelper.isValid()); - - replyPrivate->decompressHelper.feed(wrapped); - while (replyPrivate->decompressHelper.hasData()) { - QByteArray output(4 * 1024, Qt::Uninitialized); - qint64 read = replyPrivate->decompressHelper.read(output.data(), output.size()); - if (read > 0) { - output.resize(read); - replyPrivate->responseData.append(std::move(output)); - } - } - } else { - replyPrivate->responseData.append(wrapped); - } + replyPrivate->responseData.append(wrapped); if (replyPrivate->shouldEmitSignals()) { if (connectionType == Qt::DirectConnection) { diff --git a/src/network/access/qhttpnetworkconnection.cpp b/src/network/access/qhttpnetworkconnection.cpp index 18134dda13..dec354b47f 100644 --- a/src/network/access/qhttpnetworkconnection.cpp +++ b/src/network/access/qhttpnetworkconnection.cpp @@ -48,6 +48,7 @@ #include <qnetworkproxy.h> #include <qauthenticator.h> #include <qcoreapplication.h> +#include <private/qdecompresshelper_p.h> #include <qbuffer.h> #include <qpair.h> diff --git a/src/network/access/qhttpnetworkreply.cpp b/src/network/access/qhttpnetworkreply.cpp index a9579d71bc..0ad5ee372e 100644 --- a/src/network/access/qhttpnetworkreply.cpp +++ b/src/network/access/qhttpnetworkreply.cpp @@ -46,6 +46,8 @@ # include <QtNetwork/qsslconfiguration.h> #endif +#include <private/qdecompresshelper_p.h> + QT_BEGIN_NAMESPACE QHttpNetworkReply::QHttpNetworkReply(const QUrl &url, QObject *parent) @@ -348,7 +350,6 @@ void QHttpNetworkReplyPrivate::clearHttpLayerInformation() currentChunkRead = 0; lastChunkRead = false; connectionCloseEnabled = true; - decompressHelper.clear(); fields.clear(); } @@ -554,11 +555,6 @@ qint64 QHttpNetworkReplyPrivate::readHeader(QAbstractSocket *socket) headerField("proxy-connection").toLower().contains("close")) || (majorVersion == 1 && minorVersion == 0 && (connectionHeaderField.isEmpty() && !headerField("proxy-connection").toLower().contains("keep-alive"))); - if (autoDecompress && isCompressed()) { - if (!decompressHelper.setEncoding(headerField("content-encoding"))) - return -1; // Either the encoding was unsupported or the decoder could not be set up - decompressHelper.setMinimumArchiveBombSize(request.minimumArchiveBombSize()); - } } return bytes; } @@ -660,42 +656,18 @@ qint64 QHttpNetworkReplyPrivate::readBody(QAbstractSocket *socket, QByteDataBuff { qint64 bytes = 0; - // for compressed data we'll allocate a temporary one that we then decompress - QByteDataBuffer *tempOutDataBuffer = (autoDecompress ? new QByteDataBuffer : out); - - if (isChunked()) { // chunked transfer encoding (rfc 2616, sec 3.6) - bytes += readReplyBodyChunked(socket, tempOutDataBuffer); + bytes += readReplyBodyChunked(socket, out); } else if (bodyLength > 0) { // we have a Content-Length - bytes += readReplyBodyRaw(socket, tempOutDataBuffer, bodyLength - contentRead); + bytes += readReplyBodyRaw(socket, out, bodyLength - contentRead); if (contentRead + bytes == bodyLength) state = AllDoneState; } else { // no content length. just read what's possible - bytes += readReplyBodyRaw(socket, tempOutDataBuffer, socket->bytesAvailable()); - } - - // This is true if there is compressed encoding and we're supposed to use it. - if (autoDecompress) { - QScopedPointer holder(tempOutDataBuffer); - if (!decompressHelper.isValid()) - return -1; - - decompressHelper.feed(std::move(*tempOutDataBuffer)); - while (decompressHelper.hasData()) { - QByteArray output(4 * 1024, Qt::Uninitialized); - qint64 read = decompressHelper.read(output.data(), output.size()); - if (read < 0) { - return -1; - } else if (read > 0) { - output.resize(read); - out->append(std::move(output)); - } - } + bytes += readReplyBodyRaw(socket, out, socket->bytesAvailable()); } - contentRead += bytes; return bytes; } diff --git a/src/network/access/qhttpnetworkreply_p.h b/src/network/access/qhttpnetworkreply_p.h index 1fb965f989..618de43b14 100644 --- a/src/network/access/qhttpnetworkreply_p.h +++ b/src/network/access/qhttpnetworkreply_p.h @@ -274,8 +274,6 @@ public: char* userProvidedDownloadBuffer; QUrl redirectUrl; - - QDecompressHelper decompressHelper; }; diff --git a/src/network/access/qhttpnetworkrequest.cpp b/src/network/access/qhttpnetworkrequest.cpp index c1b859958a..e3c699efed 100644 --- a/src/network/access/qhttpnetworkrequest.cpp +++ b/src/network/access/qhttpnetworkrequest.cpp @@ -57,7 +57,6 @@ QHttpNetworkRequestPrivate::QHttpNetworkRequestPrivate(const QHttpNetworkRequest customVerb(other.customVerb), priority(other.priority), uploadByteDevice(other.uploadByteDevice), - minimumArchiveBombSize(other.minimumArchiveBombSize), autoDecompress(other.autoDecompress), pipeliningAllowed(other.pipeliningAllowed), http2Allowed(other.http2Allowed), @@ -94,7 +93,7 @@ bool QHttpNetworkRequestPrivate::operator==(const QHttpNetworkRequestPrivate &ot && (redirectPolicy == other.redirectPolicy) && (peerVerifyName == other.peerVerifyName) && (needResendWithCredentials == other.needResendWithCredentials) - && (minimumArchiveBombSize == other.minimumArchiveBombSize); + ; } QByteArray QHttpNetworkRequest::methodName() const @@ -406,15 +405,5 @@ void QHttpNetworkRequest::setPeerVerifyName(const QString &peerName) d->peerVerifyName = peerName; } -qint64 QHttpNetworkRequest::minimumArchiveBombSize() const -{ - return d->minimumArchiveBombSize; -} - -void QHttpNetworkRequest::setMinimumArchiveBombSize(qint64 threshold) -{ - d->minimumArchiveBombSize = threshold; -} - QT_END_NAMESPACE diff --git a/src/network/access/qhttpnetworkrequest_p.h b/src/network/access/qhttpnetworkrequest_p.h index bcb9576474..50fdd64290 100644 --- a/src/network/access/qhttpnetworkrequest_p.h +++ b/src/network/access/qhttpnetworkrequest_p.h @@ -150,9 +150,6 @@ public: QString peerVerifyName() const; void setPeerVerifyName(const QString &peerName); - qint64 minimumArchiveBombSize() const; - void setMinimumArchiveBombSize(qint64 threshold); - private: QSharedDataPointer<QHttpNetworkRequestPrivate> d; friend class QHttpNetworkRequestPrivate; @@ -178,7 +175,6 @@ public: QByteArray customVerb; QHttpNetworkRequest::Priority priority; mutable QNonContiguousByteDevice* uploadByteDevice; - qint64 minimumArchiveBombSize = 0; bool autoDecompress; bool pipeliningAllowed; bool http2Allowed; diff --git a/src/network/access/qhttpprotocolhandler.cpp b/src/network/access/qhttpprotocolhandler.cpp index c4ea73ce9d..f7f68ca65b 100644 --- a/src/network/access/qhttpprotocolhandler.cpp +++ b/src/network/access/qhttpprotocolhandler.cpp @@ -177,8 +177,7 @@ void QHttpProtocolHandler::_q_receiveReply() m_connection->d_func()->emitReplyError(m_socket, m_reply, QNetworkReply::RemoteHostClosedError); break; } - } else if (!replyPrivate->isChunked() && !replyPrivate->autoDecompress - && replyPrivate->bodyLength > 0) { + } else if (!replyPrivate->isChunked() && replyPrivate->bodyLength > 0) { // bulk files like images should fulfill these properties and // we can therefore save on memory copying qint64 haveRead = replyPrivate->readBodyFast(m_socket, &replyPrivate->responseData); diff --git a/src/network/access/qhttpthreaddelegate.cpp b/src/network/access/qhttpthreaddelegate.cpp index 05b720c4df..48e7953616 100644 --- a/src/network/access/qhttpthreaddelegate.cpp +++ b/src/network/access/qhttpthreaddelegate.cpp @@ -545,6 +545,7 @@ void QHttpThreadDelegate::synchronousFinishedSlot() incomingErrorCode = statusCodeFromHttp(httpReply->statusCode(), httpRequest.url()); } + isCompressed = httpReply->isCompressed(); synchronousDownloadData = httpReply->readAll(); QMetaObject::invokeMethod(httpReply, "deleteLater", Qt::QueuedConnection); @@ -634,6 +635,7 @@ void QHttpThreadDelegate::headerChangedSlot() incomingContentLength = httpReply->contentLength(); removedContentLength = httpReply->removedContentLength(); isHttp2Used = httpReply->isHttp2Used(); + isCompressed = httpReply->isCompressed(); emit downloadMetaData(incomingHeaders, incomingStatusCode, @@ -642,7 +644,8 @@ void QHttpThreadDelegate::headerChangedSlot() downloadBuffer, incomingContentLength, removedContentLength, - isHttp2Used); + isHttp2Used, + isCompressed); } void QHttpThreadDelegate::synchronousHeaderChangedSlot() diff --git a/src/network/access/qhttpthreaddelegate_p.h b/src/network/access/qhttpthreaddelegate_p.h index 5849d3427f..5c3857b515 100644 --- a/src/network/access/qhttpthreaddelegate_p.h +++ b/src/network/access/qhttpthreaddelegate_p.h @@ -119,6 +119,8 @@ public: QString incomingErrorDetail; QHttp2Configuration http2Parameters; + bool isCompressed; + protected: // The zerocopy download buffer, if used: QSharedPointer<char> downloadBuffer; @@ -142,7 +144,7 @@ signals: void preSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator *); #endif void downloadMetaData(const QList<QPair<QByteArray,QByteArray> > &, int, const QString &, bool, - QSharedPointer<char>, qint64, qint64, bool); + QSharedPointer<char>, qint64, qint64, bool, bool); void downloadProgress(qint64, qint64); void downloadData(const QByteArray &); void error(QNetworkReply::NetworkError, const QString &); diff --git a/src/network/access/qnetworkreplyhttpimpl.cpp b/src/network/access/qnetworkreplyhttpimpl.cpp index 88f8e62df1..cc6590f713 100644 --- a/src/network/access/qnetworkreplyhttpimpl.cpp +++ b/src/network/access/qnetworkreplyhttpimpl.cpp @@ -305,6 +305,13 @@ qint64 QNetworkReplyHttpImpl::bytesAvailable() const return QNetworkReply::bytesAvailable() + d->downloadBufferCurrentSize - d->downloadBufferReadPosition; } + if (d->decompressHelper.isValid()) { + if (d->decompressHelper.isCountingBytes()) + return QNetworkReply::bytesAvailable() + d->decompressHelper.uncompressedSize(); + if (d->decompressHelper.hasData()) + return QNetworkReply::bytesAvailable() + 1; + } + // normal buffer return QNetworkReply::bytesAvailable(); } @@ -345,6 +352,30 @@ qint64 QNetworkReplyHttpImpl::readData(char* data, qint64 maxlen) } + if (d->decompressHelper.isValid() && (d->decompressHelper.hasData() || !isFinished())) { + if (maxlen == 0 || !d->decompressHelper.hasData()) + return 0; + const qint64 bytesRead = d->decompressHelper.read(data, maxlen); + if (!d->decompressHelper.isValid()) { + // error occurred, error copied from QHttpNetworkConnectionPrivate::errorDetail + d->error(QNetworkReplyImpl::NetworkError::ProtocolFailure, + QCoreApplication::translate("QHttp", "Data corrupted")); + } + if (d->cacheSaveDevice) { + // Need to write to the cache now that we have the data + d->cacheSaveDevice->write(data, bytesRead); + // ... and if we've read everything then the cache can be closed. + if (isFinished() && !d->decompressHelper.hasData()) + d->completeCacheSave(); + } + // In case of buffer size restriction we need to emit that it has been emptied + qint64 wasBuffered = d->bytesBuffered; + d->bytesBuffered = 0; + if (readBufferSize()) + emit readBufferFreed(wasBuffered); + return bytesRead; + } + // normal buffer if (d->state == d->Finished || d->state == d->Aborted) return -1; @@ -774,7 +805,6 @@ void QNetworkReplyHttpImplPrivate::postRequest(const QNetworkRequest &newHttpReq if (request.attribute(QNetworkRequest::EmitAllUploadProgressSignalsAttribute).toBool()) emitAllUploadProgressSignals = true; - httpRequest.setMinimumArchiveBombSize(newHttpRequest.minimumArchiveBombSize()); httpRequest.setPeerVerifyName(newHttpRequest.peerVerifyName()); // Create the HTTP thread delegate @@ -839,14 +869,8 @@ void QNetworkReplyHttpImplPrivate::postRequest(const QNetworkRequest &newHttpReq QObject::connect(delegate, SIGNAL(downloadFinished()), q, SLOT(replyFinished()), Qt::QueuedConnection); - QObject::connect(delegate, SIGNAL(downloadMetaData(QList<QPair<QByteArray,QByteArray> >, - int, QString, bool, - QSharedPointer<char>, qint64, qint64, - bool)), - q, SLOT(replyDownloadMetaData(QList<QPair<QByteArray,QByteArray> >, - int, QString, bool, - QSharedPointer<char>, qint64, qint64, bool)), - Qt::QueuedConnection); + connect(delegate, &QHttpThreadDelegate::downloadMetaData, this, + &QNetworkReplyHttpImplPrivate::replyDownloadMetaData, Qt::QueuedConnection); QObject::connect(delegate, SIGNAL(downloadProgress(qint64,qint64)), q, SLOT(replyDownloadProgressSlot(qint64,qint64)), Qt::QueuedConnection); @@ -946,30 +970,20 @@ void QNetworkReplyHttpImplPrivate::postRequest(const QNetworkRequest &newHttpReq if (synchronous) { emit q->startHttpRequestSynchronously(); // This one is BlockingQueuedConnection, so it will return when all work is done - if (delegate->incomingErrorCode != QNetworkReply::NoError) { - replyDownloadMetaData - (delegate->incomingHeaders, - delegate->incomingStatusCode, - delegate->incomingReasonPhrase, - delegate->isPipeliningUsed, - QSharedPointer<char>(), - delegate->incomingContentLength, - delegate->removedContentLength, - delegate->isHttp2Used); - replyDownloadData(delegate->synchronousDownloadData); + replyDownloadMetaData + (delegate->incomingHeaders, + delegate->incomingStatusCode, + delegate->incomingReasonPhrase, + delegate->isPipeliningUsed, + QSharedPointer<char>(), + delegate->incomingContentLength, + delegate->removedContentLength, + delegate->isHttp2Used, + delegate->isCompressed); + replyDownloadData(delegate->synchronousDownloadData); + + if (delegate->incomingErrorCode != QNetworkReply::NoError) httpError(delegate->incomingErrorCode, delegate->incomingErrorDetail); - } else { - replyDownloadMetaData - (delegate->incomingHeaders, - delegate->incomingStatusCode, - delegate->incomingReasonPhrase, - delegate->isPipeliningUsed, - QSharedPointer<char>(), - delegate->incomingContentLength, - delegate->removedContentLength, - delegate->isHttp2Used); - replyDownloadData(delegate->synchronousDownloadData); - } thread->quit(); thread->wait(QDeadlineTimer(5000)); @@ -1040,23 +1054,72 @@ void QNetworkReplyHttpImplPrivate::replyDownloadData(QByteArray d) if (!q->isOpen()) return; + // cache this, we need it later and it's invalidated when dealing with compressed data + auto dataSize = d.size(); + // Grab this to compare later (only relevant for compressed data) in case none of the data + // will be propagated to the user + const qint64 previousBytesDownloaded = bytesDownloaded; + if (cacheEnabled && isCachingAllowed() && !cacheSaveDevice) initCacheSaveDevice(); + if (decompressHelper.isValid()) { + qint64 uncompressedBefore = -1; + if (decompressHelper.isCountingBytes()) + uncompressedBefore = decompressHelper.uncompressedSize(); + + decompressHelper.feed(std::move(d)); + + if (!decompressHelper.isValid()) { + // error occurred, error copied from QHttpNetworkConnectionPrivate::errorDetail + error(QNetworkReplyImpl::NetworkError::ProtocolFailure, + QCoreApplication::translate("QHttp", "Data corrupted")); + return; + } + + if (!isHttpRedirectResponse()) { + if (decompressHelper.isCountingBytes()) + bytesDownloaded += (decompressHelper.uncompressedSize() - uncompressedBefore); + setupTransferTimeout(); + } + + if (synchronous) { + d = QByteArray(); + const qsizetype increments = 16 * 1024; + qint64 bytesRead = 0; + while (decompressHelper.hasData()) { + quint64 nextSize = quint64(d.size()) + quint64(increments); + if (nextSize > quint64(std::numeric_limits<QByteArray::size_type>::max())) { + error(QNetworkReplyImpl::NetworkError::ProtocolFailure, + QCoreApplication::translate("QHttp", "Data corrupted")); + return; + } + d.resize(nextSize); + bytesRead += decompressHelper.read(d.data() + bytesRead, increments); + } + d.resize(bytesRead); + // we're synchronous so we're not calling this function again; reset the decompressHelper + decompressHelper.clear(); + } + } + // This is going to look a little strange. When downloading data while a // HTTP redirect is happening (and enabled), we write the redirect // response to the cache. However, we do not append it to our internal // buffer as that will contain the response data only for the final // response - if (cacheSaveDevice) + // Note: For compressed data this is done in readData() + if (cacheSaveDevice && !decompressHelper.isValid()) { cacheSaveDevice->write(d); + } - if (!isHttpRedirectResponse()) { + // if decompressHelper is valid then we have compressed data, and this is handled above + if (!decompressHelper.isValid() && !isHttpRedirectResponse()) { buffer.append(d); - bytesDownloaded += d.size(); + bytesDownloaded += dataSize; setupTransferTimeout(); } - bytesBuffered += d.size(); + bytesBuffered += dataSize; int pendingSignals = pendingDownloadDataEmissions->fetchAndSubAcquire(1) - 1; if (pendingSignals > 0) { @@ -1070,17 +1133,25 @@ void QNetworkReplyHttpImplPrivate::replyDownloadData(QByteArray d) if (isHttpRedirectResponse()) return; + // This can occur when downloading compressed data as some of the data may be the content + // encoding's header. Don't emit anything for this. + if (previousBytesDownloaded == bytesDownloaded) { + if (readBufferMaxSize) + emit q->readBufferFreed(dataSize); + return; + } + QVariant totalSize = cookedHeaders.value(QNetworkRequest::ContentLengthHeader); emit q->readyRead(); // emit readyRead before downloadProgress incase this will cause events to be // processed and we get into a recursive call (as in QProgressDialog). - if (downloadProgressSignalChoke.elapsed() >= progressSignalInterval) { + if (downloadProgressSignalChoke.elapsed() >= progressSignalInterval + && (!decompressHelper.isValid() || decompressHelper.isCountingBytes())) { downloadProgressSignalChoke.restart(); emit q->downloadProgress(bytesDownloaded, totalSize.isNull() ? Q_INT64_C(-1) : totalSize.toLongLong()); } - } void QNetworkReplyHttpImplPrivate::replyFinished() @@ -1207,6 +1278,7 @@ void QNetworkReplyHttpImplPrivate::followRedirect() Q_Q(QNetworkReplyHttpImpl); Q_ASSERT(managerPrivate); + decompressHelper.clear(); rawHeaders.clear(); cookedHeaders.clear(); @@ -1242,7 +1314,7 @@ void QNetworkReplyHttpImplPrivate::replyDownloadMetaData(const QList<QPair<QByte QSharedPointer<char> db, qint64 contentLength, qint64 removedContentLength, - bool h2Used) + bool h2Used, bool isCompressed) { Q_Q(QNetworkReplyHttpImpl); Q_UNUSED(contentLength); @@ -1283,6 +1355,20 @@ void QNetworkReplyHttpImplPrivate::replyDownloadMetaData(const QList<QPair<QByte if (it->first.toLower() == "location") value.clear(); + if (isCompressed && !decompressHelper.isValid() + && it->first.compare("content-encoding", Qt::CaseInsensitive) == 0) { + + if (!synchronous) // with synchronous all the data is expected to be handled at once + decompressHelper.setCountingBytesEnabled(true); + + if (!decompressHelper.setEncoding(it->second)) { + // error occurred, error copied from QHttpNetworkConnectionPrivate::errorDetail + error(QNetworkReplyImpl::NetworkError::ProtocolFailure, + QCoreApplication::translate("QHttp", "Data corrupted")); + } + decompressHelper.setMinimumArchiveBombSize(request.minimumArchiveBombSize()); + } + if (!value.isEmpty()) { // Why are we appending values for headers which are already // present? @@ -2001,9 +2087,12 @@ void QNetworkReplyHttpImplPrivate::finished() QVariant totalSize = cookedHeaders.value(QNetworkRequest::ContentLengthHeader); - // if we don't know the total size of or we received everything save the cache - if (totalSize.isNull() || totalSize == -1 || bytesDownloaded == totalSize) + // if we don't know the total size of or we received everything save the cache. + // If the data is compressed then this is done in readData() + if ((totalSize.isNull() || totalSize == -1 || bytesDownloaded == totalSize) + && !decompressHelper.isValid()) { completeCacheSave(); + } // We check for errorCode too as in case of SSL handshake failure, we still // get the HTTP redirect status code (301, 303 etc) @@ -2041,6 +2130,9 @@ void QNetworkReplyHttpImplPrivate::error(QNetworkReplyImpl::NetworkError code, c return; } + if (decompressHelper.isValid()) + decompressHelper.clear(); // Just get rid of any data that might be stored + errorCode = code; q->setErrorString(errorMessage); diff --git a/src/network/access/qnetworkreplyhttpimpl_p.h b/src/network/access/qnetworkreplyhttpimpl_p.h index 2bd6072c21..12fc484fe5 100644 --- a/src/network/access/qnetworkreplyhttpimpl_p.h +++ b/src/network/access/qnetworkreplyhttpimpl_p.h @@ -73,6 +73,8 @@ Q_MOC_INCLUDE(<QtNetwork/QAuthenticator>) +#include <private/qdecompresshelper_p.h> + QT_REQUIRE_CONFIG(http); QT_BEGIN_NAMESPACE @@ -108,9 +110,6 @@ public: // From reply Q_PRIVATE_SLOT(d_func(), void replyDownloadData(QByteArray)) Q_PRIVATE_SLOT(d_func(), void replyFinished()) - Q_PRIVATE_SLOT(d_func(), void replyDownloadMetaData(QList<QPair<QByteArray,QByteArray> >, - int, QString, bool, QSharedPointer<char>, - qint64, qint64, bool)) Q_PRIVATE_SLOT(d_func(), void replyDownloadProgressSlot(qint64,qint64)) Q_PRIVATE_SLOT(d_func(), void httpAuthenticationRequired(const QHttpNetworkRequest &, QAuthenticator *)) Q_PRIVATE_SLOT(d_func(), void httpError(QNetworkReply::NetworkError, const QString &)) @@ -258,6 +257,8 @@ public: QNetworkRequest redirectRequest; + QDecompressHelper decompressHelper; + bool loadFromCacheIfAllowed(QHttpNetworkRequest &httpRequest); void invalidateCache(); bool sendCacheContents(const QNetworkCacheMetaData &metaData); @@ -274,7 +275,7 @@ public: void replyDownloadData(QByteArray); void replyFinished(); void replyDownloadMetaData(const QList<QPair<QByteArray,QByteArray> > &, int, const QString &, - bool, QSharedPointer<char>, qint64, qint64, bool); + bool, QSharedPointer<char>, qint64, qint64, bool, bool); void replyDownloadProgressSlot(qint64,qint64); void httpAuthenticationRequired(const QHttpNetworkRequest &request, QAuthenticator *auth); void httpError(QNetworkReply::NetworkError error, const QString &errorString); |