diff options
Diffstat (limited to 'src/network')
-rw-r--r-- | src/network/access/qnetworkaccessbackend_p.h | 4 | ||||
-rw-r--r-- | src/network/access/qnetworkaccesshttpbackend.cpp | 48 | ||||
-rw-r--r-- | src/network/access/qnetworkaccesshttpbackend_p.h | 5 | ||||
-rw-r--r-- | src/network/access/qnetworkreplyimpl.cpp | 21 |
4 files changed, 60 insertions, 18 deletions
diff --git a/src/network/access/qnetworkaccessbackend_p.h b/src/network/access/qnetworkaccessbackend_p.h index 830ec7e..eab011c 100644 --- a/src/network/access/qnetworkaccessbackend_p.h +++ b/src/network/access/qnetworkaccessbackend_p.h @@ -162,6 +162,10 @@ public: // This will possibly enable buffering of the upload data. virtual bool needsResetableUploadData() { return false; } + // Returns true if backend is able to resume downloads. + virtual bool canResume() const { return false; } + virtual void setResumeOffset(quint64 offset) { Q_UNUSED(offset); } + protected: // Create the device used for reading the upload data QNonContiguousByteDevice* createUploadByteDevice(); diff --git a/src/network/access/qnetworkaccesshttpbackend.cpp b/src/network/access/qnetworkaccesshttpbackend.cpp index 8e02723..aa6a820 100644 --- a/src/network/access/qnetworkaccesshttpbackend.cpp +++ b/src/network/access/qnetworkaccesshttpbackend.cpp @@ -296,6 +296,7 @@ QNetworkAccessHttpBackend::QNetworkAccessHttpBackend() #ifndef QT_NO_OPENSSL , pendingSslConfiguration(0), pendingIgnoreAllSslErrors(false) #endif + , resumeOffset(0) { } @@ -533,6 +534,28 @@ void QNetworkAccessHttpBackend::postRequest() httpRequest.setUrl(url()); QList<QByteArray> headers = request().rawHeaderList(); + if (resumeOffset != 0) { + if (headers.contains("Range")) { + // Need to adjust resume offset for user specified range + + headers.removeOne("Range"); + + // We've already verified that requestRange starts with "bytes=", see canResume. + QByteArray requestRange = request().rawHeader("Range").mid(6); + + int index = requestRange.indexOf('-'); + + quint64 requestStartOffset = requestRange.left(index).toULongLong(); + quint64 requestEndOffset = requestRange.mid(index + 1).toULongLong(); + + requestRange = "bytes=" + QByteArray::number(resumeOffset + requestStartOffset) + + '-' + QByteArray::number(requestEndOffset); + + httpRequest.setHeaderField("Range", requestRange); + } else { + httpRequest.setHeaderField("Range", "bytes=" + QByteArray::number(resumeOffset) + '-'); + } + } foreach (const QByteArray &header, headers) httpRequest.setHeaderField(header, request().rawHeader(header)); @@ -1108,6 +1131,31 @@ QNetworkCacheMetaData QNetworkAccessHttpBackend::fetchCacheMetaData(const QNetwo return metaData; } +bool QNetworkAccessHttpBackend::canResume() const +{ + // Only GET operation supports resuming. + if (operation() != QNetworkAccessManager::GetOperation) + return false; + + // Can only resume if server/resource supports Range header. + if (httpReply->headerField("Accept-Ranges", "none") == "none") + return false; + + // We only support resuming for byte ranges. + if (request().hasRawHeader("Range")) { + QByteArray range = request().rawHeader("Range"); + if (!range.startsWith("bytes=")) + return false; + } + + return true; +} + +void QNetworkAccessHttpBackend::setResumeOffset(quint64 offset) +{ + resumeOffset = offset; +} + QT_END_NAMESPACE #endif // QT_NO_HTTP diff --git a/src/network/access/qnetworkaccesshttpbackend_p.h b/src/network/access/qnetworkaccesshttpbackend_p.h index 0eaf003..e5cc0ab 100644 --- a/src/network/access/qnetworkaccesshttpbackend_p.h +++ b/src/network/access/qnetworkaccesshttpbackend_p.h @@ -99,6 +99,9 @@ public: // we return true since HTTP needs to send PUT/POST data again after having authenticated bool needsResetableUploadData() { return true; } + bool canResume() const; + void setResumeOffset(quint64 offset); + private slots: void replyReadyRead(); void replyFinished(); @@ -120,6 +123,8 @@ private: QList<QSslError> pendingIgnoreSslErrorsList; #endif + quint64 resumeOffset; + void disconnectFromHttp(); void setupConnection(); void validateCache(QHttpNetworkRequest &httpRequest, bool &loadedFromCache); diff --git a/src/network/access/qnetworkreplyimpl.cpp b/src/network/access/qnetworkreplyimpl.cpp index 7f66b25..2906caa 100644 --- a/src/network/access/qnetworkreplyimpl.cpp +++ b/src/network/access/qnetworkreplyimpl.cpp @@ -497,15 +497,6 @@ void QNetworkReplyImplPrivate::appendDownstreamData(QByteDataBuffer &data) QPointer<QNetworkReplyImpl> qq = q; QVariant totalSize = cookedHeaders.value(QNetworkRequest::ContentLengthHeader); - if (totalSize.isNull()) { - RawHeadersList::ConstIterator it = findRawHeader("Content-Range"); - if (it != rawHeaders.constEnd()) { - int index = it->second.lastIndexOf('/'); - if (index != -1) - totalSize = it->second.mid(index + 1).toLongLong() - preMigrationDownloaded; - } - } - if (preMigrationDownloaded != Q_INT64_C(-1)) totalSize = totalSize.toLongLong() + preMigrationDownloaded; pauseNotificationHandling(); @@ -812,8 +803,8 @@ bool QNetworkReplyImplPrivate::migrateBackend() if (state == Finished || state == Aborted) return true; - // Resume only supported by http backend, not migrating. - if (!qobject_cast<QNetworkAccessHttpBackend *>(backend)) + // Backend does not support resuming download. + if (!backend->canResume()) return false; // Request has outgoing data, not migrating. @@ -824,11 +815,6 @@ bool QNetworkReplyImplPrivate::migrateBackend() if (copyDevice) return true; - // Range header is not supported by server/resource, can't migrate. - RawHeadersList::ConstIterator it = findRawHeader("Accept-Ranges"); - if (it == rawHeaders.constEnd() || it->second == "none") - return false; - state = QNetworkReplyImplPrivate::Reconnecting; if (backend) { @@ -841,13 +827,12 @@ bool QNetworkReplyImplPrivate::migrateBackend() preMigrationDownloaded = bytesDownloaded; - request.setRawHeader("Range", "bytes=" + QByteArray::number(preMigrationDownloaded) + '-'); - backend = manager->d_func()->findBackend(operation, request); if (backend) { backend->setParent(q); backend->reply = this; + backend->setResumeOffset(bytesDownloaded); } if (qobject_cast<QNetworkAccessHttpBackend *>(backend)) { |