summaryrefslogtreecommitdiffstats
path: root/src/network
diff options
context:
space:
mode:
Diffstat (limited to 'src/network')
-rw-r--r--src/network/access/qnetworkaccessbackend_p.h4
-rw-r--r--src/network/access/qnetworkaccesshttpbackend.cpp48
-rw-r--r--src/network/access/qnetworkaccesshttpbackend_p.h5
-rw-r--r--src/network/access/qnetworkreplyimpl.cpp21
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)) {