diff options
-rw-r--r-- | src/network/access/qhttpnetworkconnection.cpp | 76 | ||||
-rw-r--r-- | src/network/access/qhttpnetworkreply.cpp | 26 | ||||
-rw-r--r-- | src/network/access/qhttpnetworkreply_p.h | 1 |
3 files changed, 75 insertions, 28 deletions
diff --git a/src/network/access/qhttpnetworkconnection.cpp b/src/network/access/qhttpnetworkconnection.cpp index 8409660..56caca9 100644 --- a/src/network/access/qhttpnetworkconnection.cpp +++ b/src/network/access/qhttpnetworkconnection.cpp @@ -649,36 +649,58 @@ void QHttpNetworkConnectionPrivate::receiveReply(QAbstractSocket *socket, QHttpN } break; case QHttpNetworkReplyPrivate::ReadingDataState: { - QBuffer fragment; - fragment.open(QIODevice::WriteOnly); - bytes = reply->d_func()->readBody(socket, &fragment); - if (bytes) { - if (reply->d_func()->autoDecompress) - appendCompressedData(*reply, fragment.data()); - else - appendUncompressedData(*reply, fragment.data()); - - if (!reply->d_func()->autoDecompress) { - reply->d_func()->totalProgress += fragment.size(); - if (shouldEmitSignals(reply)) { - emit reply->readyRead(); - // make sure that the reply is valid - if (channels[i].reply != reply) - return; - // emit dataReadProgress signal (signal is currently not connected - // to the rest of QNAM) since readProgress of the - // QNonContiguousByteDevice is used - emit reply->dataReadProgress(reply->d_func()->totalProgress, reply->d_func()->bodyLength); - // make sure that the reply is valid - if (channels[i].reply != reply) - return; - } + if (!reply->d_func()->isChunked() && !reply->d_func()->autoDecompress + && reply->d_func()->bodyLength > 0) { + // bulk files like images should fulfill these properties and + // we can therefore save on memory copying + bytes = reply->d_func()->readBodyFast(socket, &reply->d_func()->responseData); + reply->d_func()->totalProgress += bytes; + if (shouldEmitSignals(reply)) { + emit reply->readyRead(); + // make sure that the reply is valid + if (channels[i].reply != reply) + return; + emit reply->dataReadProgress(reply->d_func()->totalProgress, reply->d_func()->bodyLength); + // make sure that the reply is valid + if (channels[i].reply != reply) + return; } + } + else + { + // use the traditional slower reading (for compressed encoding, chunked encoding, + // no content-length etc) + QBuffer fragment; + fragment.open(QIODevice::WriteOnly); + bytes = reply->d_func()->readBody(socket, &fragment); + if (bytes) { + if (reply->d_func()->autoDecompress) + appendCompressedData(*reply, fragment.data()); + else + appendUncompressedData(*reply, fragment.data()); + + if (!reply->d_func()->autoDecompress) { + reply->d_func()->totalProgress += fragment.size(); + if (shouldEmitSignals(reply)) { + emit reply->readyRead(); + // make sure that the reply is valid + if (channels[i].reply != reply) + return; + // emit dataReadProgress signal (signal is currently not connected + // to the rest of QNAM) since readProgress of the + // QNonContiguousByteDevice is used + emit reply->dataReadProgress(reply->d_func()->totalProgress, reply->d_func()->bodyLength); + // make sure that the reply is valid + if (channels[i].reply != reply) + return; + } + } #ifndef QT_NO_COMPRESS - else if (!expand(socket, reply, false)) { // expand a chunk if possible - return; // ### expand failed - } + else if (!expand(socket, reply, false)) { // expand a chunk if possible + return; // ### expand failed + } #endif + } } if (reply->d_func()->state == QHttpNetworkReplyPrivate::ReadingDataState) break; diff --git a/src/network/access/qhttpnetworkreply.cpp b/src/network/access/qhttpnetworkreply.cpp index 202bdea..72aec99 100644 --- a/src/network/access/qhttpnetworkreply.cpp +++ b/src/network/access/qhttpnetworkreply.cpp @@ -549,6 +549,30 @@ bool QHttpNetworkReplyPrivate::connectionCloseEnabled() headerField("proxy-connection").toLower().contains("close")); } +// note this function can only be used for non-chunked, non-compressed with +// known content length +qint64 QHttpNetworkReplyPrivate::readBodyFast(QAbstractSocket *socket, QRingBuffer *rb) +{ + quint64 toBeRead = qMin(socket->bytesAvailable(), bodyLength - contentRead); + char* dst = rb->reserve(toBeRead); + qint64 haveRead = socket->read(dst, toBeRead); + if (haveRead == -1) { + rb->chop(toBeRead); + return 0; // ### error checking here; + } + + rb->chop(toBeRead - haveRead); + + if (contentRead + haveRead == bodyLength) { + state = AllDoneState; + socket->readAll(); // Read the rest to clean (CRLF) ### will break pipelining + } + + contentRead += haveRead; + return haveRead; +} + + qint64 QHttpNetworkReplyPrivate::readBody(QAbstractSocket *socket, QIODevice *out) { qint64 bytes = 0; @@ -562,7 +586,7 @@ qint64 QHttpNetworkReplyPrivate::readBody(QAbstractSocket *socket, QIODevice *ou bytes += readReplyBodyRaw(socket, out, socket->bytesAvailable()); } if (state == AllDoneState) - socket->readAll(); // Read the rest to clean (CRLF) + socket->readAll(); // Read the rest to clean (CRLF) ### will break pipelining contentRead += bytes; return bytes; } diff --git a/src/network/access/qhttpnetworkreply_p.h b/src/network/access/qhttpnetworkreply_p.h index 69c9158..26e1047 100644 --- a/src/network/access/qhttpnetworkreply_p.h +++ b/src/network/access/qhttpnetworkreply_p.h @@ -160,6 +160,7 @@ public: qint64 readHeader(QAbstractSocket *socket); void parseHeader(const QByteArray &header); qint64 readBody(QAbstractSocket *socket, QIODevice *out); + qint64 readBodyFast(QAbstractSocket *socket, QRingBuffer *rb); bool findChallenge(bool forProxy, QByteArray &challenge) const; QAuthenticatorPrivate::Method authenticationMethod(bool isProxy) const; void clear(); |