From c6157559204b61b11537ab0c0aba16eb182b09fe Mon Sep 17 00:00:00 2001 From: Aaron McCarthy Date: Mon, 8 Feb 2010 17:37:48 +1000 Subject: Automatically migrate in-progress transfers after roaming. Automatically migrate in-progress transfers after roaming to a new access point for backends that support it. Currently only works for http transfers that do not upload data (i.e. HTTP GET). --- src/network/access/qnetworkaccessmanager.cpp | 35 +++----------------------- src/network/access/qnetworkaccessmanager_p.h | 4 +-- src/network/access/qnetworkreplyimpl.cpp | 37 +++++++++++++++++++--------- src/network/access/qnetworkreplyimpl_p.h | 2 +- 4 files changed, 31 insertions(+), 47 deletions(-) diff --git a/src/network/access/qnetworkaccessmanager.cpp b/src/network/access/qnetworkaccessmanager.cpp index 617e398..8df580d 100644 --- a/src/network/access/qnetworkaccessmanager.cpp +++ b/src/network/access/qnetworkaccessmanager.cpp @@ -802,27 +802,6 @@ void QNetworkAccessManagerPrivate::_q_replyFinished() QNetworkReply *reply = qobject_cast(q->sender()); if (reply) emit q->finished(reply); - - if (session && deferredMigration) { - foreach (QObject *child, q->children()) { - if (child == reply) - continue; - - QNetworkReplyImpl *replyImpl = qobject_cast(child); - if (!replyImpl) - continue; - - QNetworkReplyImplPrivate::State state = replyImpl->d_func()->state; - if (state == QNetworkReplyImplPrivate::Buffering || - state == QNetworkReplyImplPrivate::Working) { - return; - } - } - - deferredMigration = false; - qDebug() << "Migrating as there are no pending replies."; - session->migrate(); - } } void QNetworkAccessManagerPrivate::_q_replySslErrors(const QList &errors) @@ -1136,6 +1115,7 @@ void QNetworkAccessManagerPrivate::_q_sessionNewConfigurationActivated() { Q_Q(QNetworkAccessManager); +#if 0 foreach (QObject *child, q->children()) { QNetworkReplyImpl *reply = qobject_cast(child); if (reply) { @@ -1151,6 +1131,7 @@ void QNetworkAccessManagerPrivate::_q_sessionNewConfigurationActivated() } } } +#endif qDebug() << "Accepting new configuration."; session->accept(); @@ -1183,18 +1164,10 @@ void QNetworkAccessManagerPrivate::_q_sessionPreferredConfigurationChanged(const foreach (QObject *child, q->children()) { QNetworkReplyImpl *replyImpl = qobject_cast(child); - if (replyImpl) { - QNetworkReplyImplPrivate::State state = replyImpl->d_func()->state; - if (state == QNetworkReplyImplPrivate::Buffering || - state == QNetworkReplyImplPrivate::Working) { - deferredMigration = true; - return; - } - } + if (replyImpl) + replyImpl->migrateBackend(); } - deferredMigration = false; - qDebug() << "Migrating as there are no pending replies."; session->migrate(); } diff --git a/src/network/access/qnetworkaccessmanager_p.h b/src/network/access/qnetworkaccessmanager_p.h index 92b2782..e916158 100644 --- a/src/network/access/qnetworkaccessmanager_p.h +++ b/src/network/access/qnetworkaccessmanager_p.h @@ -76,8 +76,7 @@ public: proxyFactory(0), #endif cookieJarCreated(false), - session(0), - deferredMigration(false) + session(0) { } ~QNetworkAccessManagerPrivate(); @@ -131,7 +130,6 @@ public: bool cookieJarCreated; QNetworkSession *session; - bool deferredMigration; // this cache can be used by individual backends to cache e.g. their TCP connections to a server // and use the connections for multiple requests. diff --git a/src/network/access/qnetworkreplyimpl.cpp b/src/network/access/qnetworkreplyimpl.cpp index 0c7aca8..9721e32 100644 --- a/src/network/access/qnetworkreplyimpl.cpp +++ b/src/network/access/qnetworkreplyimpl.cpp @@ -477,6 +477,17 @@ void QNetworkReplyImplPrivate::appendDownstreamData(QByteDataBuffer &data) QPointer 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; + } else { + qDebug() << "Could not find Content-Length or Content-Range header"; + } + } + if (preMigrationDownloaded != Q_INT64_C(-1)) totalSize = totalSize.toLongLong() + preMigrationDownloaded; pauseNotificationHandling(); @@ -520,7 +531,8 @@ void QNetworkReplyImplPrivate::appendDownstreamData(QIODevice *data) void QNetworkReplyImplPrivate::finished() { Q_Q(QNetworkReplyImpl); - if (state == Finished || state == Aborted) + + if (state == Finished || state == Aborted || state == WaitingForSession) return; pauseNotificationHandling(); @@ -540,11 +552,10 @@ void QNetworkReplyImplPrivate::finished() } else { qDebug() << "Download hasn't finished"; - if (q->bytesAvailable() == bytesDownloaded) { - qDebug() << "User hasn't read data from reply, we could continue after reconnect."; - error(QNetworkReply::TemporaryNetworkFailureError, q->tr("Temporary network failure.")); - } else if (q->bytesAvailable() < bytesDownloaded) { - qDebug() << "User has already read data from reply."; + if (migrateBackend()) { + return; + } else { + qDebug() << "Could not migrate backend, application needs to send another requeset."; error(QNetworkReply::TemporaryNetworkFailureError, q->tr("Temporary network failure.")); } } @@ -781,24 +792,24 @@ void QNetworkReplyImpl::migrateBackend() d->migrateBackend(); } -void QNetworkReplyImplPrivate::migrateBackend() +bool QNetworkReplyImplPrivate::migrateBackend() { Q_Q(QNetworkReplyImpl); if (state == QNetworkReplyImplPrivate::Finished || state == QNetworkReplyImplPrivate::Aborted) { qDebug() << "Network reply is already finished/aborted."; - return; + return false; } if (!qobject_cast(backend)) { qDebug() << "Resume only support by http backend, not migrating."; - return; + return false; } if (outgoingData) { qDebug() << "Request has outgoing data, not migrating."; - return; + return false; } qDebug() << "Need to check for only cacheable content."; @@ -812,14 +823,14 @@ void QNetworkReplyImplPrivate::migrateBackend() state = QNetworkReplyImplPrivate::Reconnecting; if (backend) { - backend->deleteLater(); + delete backend; 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."); + return false; } cookedHeaders.clear(); @@ -841,6 +852,8 @@ void QNetworkReplyImplPrivate::migrateBackend() } else { QMetaObject::invokeMethod(q, "_q_startOperation", Qt::QueuedConnection); } + + return true; } QT_END_NAMESPACE diff --git a/src/network/access/qnetworkreplyimpl_p.h b/src/network/access/qnetworkreplyimpl_p.h index ac82ca0..89b976f 100644 --- a/src/network/access/qnetworkreplyimpl_p.h +++ b/src/network/access/qnetworkreplyimpl_p.h @@ -165,7 +165,7 @@ public: QIODevice *copyDevice; QAbstractNetworkCache *networkCache() const; - void migrateBackend(); + bool migrateBackend(); bool cacheEnabled; QIODevice *cacheSaveDevice; -- cgit v0.12