From dc5350f9325eb0daef6550e7a6ff14a82d030d63 Mon Sep 17 00:00:00 2001 From: Aaron McCarthy Date: Thu, 4 Feb 2010 16:55:05 +1000 Subject: Migrate in progress http downloads. --- src/network/access/qnetworkaccessbackend_p.h | 1 + src/network/access/qnetworkaccessmanager.cpp | 18 ++++++- src/network/access/qnetworkreplyimpl.cpp | 70 +++++++++++++++++++++++++++- src/network/access/qnetworkreplyimpl_p.h | 6 ++- 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(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 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(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(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 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; -- cgit v0.12