summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/network/access/qnetworkaccessbackend_p.h1
-rw-r--r--src/network/access/qnetworkaccessmanager.cpp18
-rw-r--r--src/network/access/qnetworkreplyimpl.cpp70
-rw-r--r--src/network/access/qnetworkreplyimpl_p.h6
4 files changed, 91 insertions, 4 deletions
diff --git a/src/network/access/qnetworkaccessbackend_p.h b/src/network/access/qnetworkaccessbackend_p.h
index b8b369f..830ec7e 100644
--- a/src/network/access/qnetworkaccessbackend_p.h
+++ b/src/network/access/qnetworkaccessbackend_p.h
@@ -192,6 +192,7 @@ private:
friend class QNetworkAccessManager;
friend class QNetworkAccessManagerPrivate;
friend class QNetworkAccessBackendUploadIODevice;
+ friend class QNetworkReplyImplPrivate;
QNetworkAccessManagerPrivate *manager;
QNetworkReplyImplPrivate *reply;
};
diff --git a/src/network/access/qnetworkaccessmanager.cpp b/src/network/access/qnetworkaccessmanager.cpp
index e17beb9..617e398 100644
--- a/src/network/access/qnetworkaccessmanager.cpp
+++ b/src/network/access/qnetworkaccessmanager.cpp
@@ -1155,11 +1155,25 @@ void QNetworkAccessManagerPrivate::_q_sessionNewConfigurationActivated()
qDebug() << "Accepting new configuration.";
session->accept();
- // start waiting children
foreach (QObject *child, q->children()) {
QNetworkReplyImpl *reply = qobject_cast<QNetworkReplyImpl *>(child);
- if (reply && reply->d_func()->state == QNetworkReplyImplPrivate::WaitingForSession)
+ if (!reply)
+ continue;
+
+ switch (reply->d_func()->state) {
+ case QNetworkReplyImplPrivate::Buffering:
+ case QNetworkReplyImplPrivate::Working:
+ case QNetworkReplyImplPrivate::Reconnecting:
+ // Migrate existing downloads to new configuration.
+ reply->d_func()->migrateBackend();
+ break;
+ case QNetworkReplyImplPrivate::WaitingForSession:
+ // Start waiting requests.
QMetaObject::invokeMethod(reply, "_q_startOperation", Qt::QueuedConnection);
+ break;
+ default:
+ qDebug() << "How do we handle replies in state" << reply->d_func()->state;
+ }
}
}
diff --git a/src/network/access/qnetworkreplyimpl.cpp b/src/network/access/qnetworkreplyimpl.cpp
index 72c378a..932d81a 100644
--- a/src/network/access/qnetworkreplyimpl.cpp
+++ b/src/network/access/qnetworkreplyimpl.cpp
@@ -58,7 +58,7 @@ inline QNetworkReplyImplPrivate::QNetworkReplyImplPrivate()
copyDevice(0),
cacheEnabled(false), cacheSaveDevice(0),
notificationHandlingPaused(false),
- bytesDownloaded(0), lastBytesDownloaded(-1), bytesUploaded(-1),
+ bytesDownloaded(0), lastBytesDownloaded(-1), bytesUploaded(-1), preMigrationDownloaded(-1),
httpStatusCode(0),
state(Idle)
{
@@ -152,6 +152,8 @@ void QNetworkReplyImplPrivate::_q_copyReadyRead()
lastBytesDownloaded = bytesDownloaded;
QVariant totalSize = cookedHeaders.value(QNetworkRequest::ContentLengthHeader);
+ if (preMigrationDownloaded != Q_INT64_C(-1))
+ totalSize = totalSize.toLongLong() + preMigrationDownloaded;
pauseNotificationHandling();
emit q->downloadProgress(bytesDownloaded,
totalSize.isNull() ? Q_INT64_C(-1) : totalSize.toLongLong());
@@ -475,6 +477,8 @@ void QNetworkReplyImplPrivate::appendDownstreamData(QByteDataBuffer &data)
QPointer<QNetworkReplyImpl> qq = q;
QVariant totalSize = cookedHeaders.value(QNetworkRequest::ContentLengthHeader);
+ if (preMigrationDownloaded != Q_INT64_C(-1))
+ totalSize = totalSize.toLongLong() + preMigrationDownloaded;
pauseNotificationHandling();
emit q->downloadProgress(bytesDownloaded,
totalSize.isNull() ? Q_INT64_C(-1) : totalSize.toLongLong());
@@ -521,6 +525,8 @@ void QNetworkReplyImplPrivate::finished()
pauseNotificationHandling();
QVariant totalSize = cookedHeaders.value(QNetworkRequest::ContentLengthHeader);
+ if (preMigrationDownloaded != Q_INT64_C(-1))
+ totalSize = totalSize.toLongLong() + preMigrationDownloaded;
QNetworkSession *session = manager->d_func()->session;
if (session && session->state() == QNetworkSession::Roaming &&
state == Working && errorCode != QNetworkReply::OperationCanceledError) {
@@ -768,6 +774,68 @@ bool QNetworkReplyImpl::event(QEvent *e)
return QObject::event(e);
}
+void QNetworkReplyImplPrivate::migrateBackend()
+{
+ Q_Q(QNetworkReplyImpl);
+
+ if (state == QNetworkReplyImplPrivate::Finished ||
+ state == QNetworkReplyImplPrivate::Aborted) {
+ qDebug() << "Network reply is already finished/aborted.";
+ return;
+ }
+
+ if (!qobject_cast<QNetworkAccessHttpBackend *>(backend)) {
+ qDebug() << "Resume only support by http backend, not migrating.";
+ return;
+ }
+
+ if (outgoingData) {
+ qDebug() << "Request has outgoing data, not migrating.";
+ return;
+ }
+
+ qDebug() << "Need to check for only cacheable content.";
+
+ // stop both upload and download
+ if (outgoingData)
+ outgoingData->disconnect(q);
+ if (copyDevice)
+ copyDevice->disconnect(q);
+
+ state = QNetworkReplyImplPrivate::Reconnecting;
+
+ if (backend) {
+ backend->deleteLater();
+ backend = 0;
+ }
+
+ RawHeadersList::ConstIterator it = findRawHeader("Accept-Ranges");
+ if (it == rawHeaders.constEnd() || it->second == "none") {
+ qDebug() << "Range header not supported by server/resource.";
+ qFatal("Should fail with TemporaryNetworkFailure.");
+ }
+
+ cookedHeaders.clear();
+ rawHeaders.clear();
+
+ preMigrationDownloaded = bytesDownloaded;
+
+ request.setRawHeader("Range", "bytes=" + QByteArray::number(preMigrationDownloaded) + '-');
+
+ backend = manager->d_func()->findBackend(operation, request);
+
+ if (backend) {
+ backend->setParent(q);
+ backend->reply = this;
+ }
+
+ if (qobject_cast<QNetworkAccessHttpBackend *>(backend)) {
+ _q_startOperation();
+ } else {
+ QMetaObject::invokeMethod(q, "_q_startOperation", Qt::QueuedConnection);
+ }
+}
+
QT_END_NAMESPACE
#include "moc_qnetworkreplyimpl_p.cpp"
diff --git a/src/network/access/qnetworkreplyimpl_p.h b/src/network/access/qnetworkreplyimpl_p.h
index 861b2b2..9de16e6 100644
--- a/src/network/access/qnetworkreplyimpl_p.h
+++ b/src/network/access/qnetworkreplyimpl_p.h
@@ -115,7 +115,8 @@ public:
Working,
Finished,
Aborted,
- WaitingForSession
+ WaitingForSession,
+ Reconnecting
};
typedef QQueue<InternalNotifications> NotificationQueue;
@@ -162,6 +163,8 @@ public:
QIODevice *copyDevice;
QAbstractNetworkCache *networkCache() const;
+ void migrateBackend();
+
bool cacheEnabled;
QIODevice *cacheSaveDevice;
@@ -178,6 +181,7 @@ public:
qint64 bytesDownloaded;
qint64 lastBytesDownloaded;
qint64 bytesUploaded;
+ qint64 preMigrationDownloaded;
QString httpReasonPhrase;
int httpStatusCode;