summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAaron McCarthy <aaron.mccarthy@nokia.com>2010-01-28 11:27:49 +1000
committerAaron McCarthy <aaron.mccarthy@nokia.com>2010-02-03 16:57:42 +1000
commitdf551752b7f430ab44bb1dd2ad0aa8c2a5187ef8 (patch)
treee314f8cad85765d52669a6778610c3377dd9ef9f
parent2149a313e671b22382828b58d2520807a5a061e1 (diff)
Bearer Management Integration.
Perform application level roaming when all pending QNetworkReplys have completed. Emit temporary network failure error when connection to network is lost but is possibly recovering due to roaming. Don't save downloads in cache if they are not complete.
-rw-r--r--src/network/access/qnetworkaccessbackend.cpp24
-rw-r--r--src/network/access/qnetworkaccessbackend_p.h4
-rw-r--r--src/network/access/qnetworkaccessmanager.cpp79
-rw-r--r--src/network/access/qnetworkaccessmanager.h6
-rw-r--r--src/network/access/qnetworkaccessmanager_p.h11
-rw-r--r--src/network/access/qnetworkreply.cpp4
-rw-r--r--src/network/access/qnetworkreply.h1
-rw-r--r--src/network/access/qnetworkreplyimpl.cpp29
8 files changed, 134 insertions, 24 deletions
diff --git a/src/network/access/qnetworkaccessbackend.cpp b/src/network/access/qnetworkaccessbackend.cpp
index c712fffece..22df248a16 100644
--- a/src/network/access/qnetworkaccessbackend.cpp
+++ b/src/network/access/qnetworkaccessbackend.cpp
@@ -49,7 +49,6 @@
#include "qnetworkaccesscachebackend_p.h"
#include "qabstractnetworkcache.h"
-#include "qnetworksession.h"
#include "qhostinfo.h"
#include "private/qnoncontiguousbytedevice_p.h"
@@ -345,22 +344,20 @@ void QNetworkAccessBackend::sslErrors(const QList<QSslError> &errors)
void QNetworkAccessBackend::start()
{
- qDebug() << "Checking for localhost";
QHostInfo hostInfo = QHostInfo::fromName(reply->url.host());
foreach (const QHostAddress &address, hostInfo.addresses()) {
if (address == QHostAddress::LocalHost ||
address == QHostAddress::LocalHostIPv6) {
// Don't need session for local host access.
- qDebug() << "Access is to localhost";
open();
return;
}
}
- qDebug() << "Connecting session signals";
connect(manager->session, SIGNAL(opened()), this, SLOT(sessionOpened()));
+ connect(manager->session, SIGNAL(error(QNetworkSession::SessionError)),
+ this, SLOT(sessionError(QNetworkSession::SessionError)));
- qDebug() << "Open session if required";
if (!manager->session->isOpen())
manager->session->open();
else
@@ -369,25 +366,12 @@ void QNetworkAccessBackend::start()
void QNetworkAccessBackend::sessionOpened()
{
- manager->sendDebugMessage(QLatin1String("Session opened"));
- qDebug() << "Session opened, calling open()";
open();
}
-void QNetworkAccessBackend::preferredConfigurationChanged(const QNetworkConfiguration &config,
- bool isSeamless)
+void QNetworkAccessBackend::sessionError(QNetworkSession::SessionError error)
{
- QString message = QString::fromLatin1("preferredConfiguirationChanged %1 %2")
- .arg(config.name()) .arg(isSeamless);
-
- manager->sendDebugMessage(message);
- manager->session->ignore();
-}
-
-void QNetworkAccessBackend::newConfigurationActivated()
-{
- manager->sendDebugMessage(QLatin1String("newConfigurationActivated"));
- manager->session->reject();
+ manager->sendDebugMessage(QString::fromLatin1("Session error %1").arg(error));
}
QT_END_NAMESPACE
diff --git a/src/network/access/qnetworkaccessbackend_p.h b/src/network/access/qnetworkaccessbackend_p.h
index 62ac736738..08a8a2af65 100644
--- a/src/network/access/qnetworkaccessbackend_p.h
+++ b/src/network/access/qnetworkaccessbackend_p.h
@@ -54,6 +54,7 @@
//
#include "qnetworkreplyimpl_p.h"
+#include "QtNetwork/qnetworksession.h"
#include "QtCore/qobject.h"
QT_BEGIN_NAMESPACE
@@ -189,8 +190,7 @@ protected slots:
private slots:
void sessionOpened();
- void preferredConfigurationChanged(const QNetworkConfiguration &config, bool isSeamless);
- void newConfigurationActivated();
+ void sessionError(QNetworkSession::SessionError error);
private:
friend class QNetworkAccessManager;
diff --git a/src/network/access/qnetworkaccessmanager.cpp b/src/network/access/qnetworkaccessmanager.cpp
index b8edefad24..3f8ef01f5f 100644
--- a/src/network/access/qnetworkaccessmanager.cpp
+++ b/src/network/access/qnetworkaccessmanager.cpp
@@ -351,6 +351,17 @@ QNetworkAccessManager::QNetworkAccessManager(QObject *parent)
QNetworkConfigurationManager manager;
d_func()->session = new QNetworkSession(manager.defaultConfiguration(), this);
+
+ connect(d_func()->session, SIGNAL(opened()), this, SLOT(_q_sessionOpened()));
+ connect(d_func()->session, SIGNAL(closed()), this, SLOT(_q_sessionClosed()));
+ connect(d_func()->session, SIGNAL(stateChanged(QNetworkSession::State)),
+ this, SLOT(_q_sessionStateChanged(QNetworkSession::State)));
+ connect(d_func()->session, SIGNAL(error(QNetworkSession::SessionError)),
+ this, SLOT(_q_sessionError(QNetworkSession::SessionError)));
+ connect(d_func()->session, SIGNAL(newConfigurationActivated()),
+ this, SLOT(_q_sessionNewConfigurationActivated()));
+ connect(d_func()->session, SIGNAL(preferredConfigurationChanged(QNetworkConfiguration,bool)),
+ this, SLOT(_q_sessionPreferredConfigurationChanged(QNetworkConfiguration,bool)));
}
/*!
@@ -792,6 +803,20 @@ void QNetworkAccessManagerPrivate::_q_replyFinished()
QNetworkReply *reply = qobject_cast<QNetworkReply *>(q->sender());
if (reply)
emit q->finished(reply);
+
+ if (deferredMigration) {
+ bool repliesPending = false;
+ foreach (QObject *child, q->children()) {
+ if (child != reply && child->inherits("QNetworkReply")) {
+ repliesPending = true;
+ break;
+ }
+ }
+ if (!repliesPending) {
+ emit q->debugMessage(QLatin1String("Migrating as there are no pending replies."));
+ session->migrate();
+ }
+ }
}
void QNetworkAccessManagerPrivate::_q_replySslErrors(const QList<QSslError> &errors)
@@ -1044,6 +1069,60 @@ QNetworkAccessManagerPrivate::~QNetworkAccessManagerPrivate()
{
}
+void QNetworkAccessManagerPrivate::_q_sessionOpened()
+{
+ Q_Q(QNetworkAccessManager);
+}
+
+void QNetworkAccessManagerPrivate::_q_sessionClosed()
+{
+ Q_Q(QNetworkAccessManager);
+
+ emit q->debugMessage(QLatin1String("Session Closed"));
+}
+
+void QNetworkAccessManagerPrivate::_q_sessionError(QNetworkSession::SessionError error)
+{
+ Q_Q(QNetworkAccessManager);
+
+ emit q->debugMessage(QString::fromLatin1("Session error %1").arg(error));
+}
+
+void QNetworkAccessManagerPrivate::_q_sessionStateChanged(QNetworkSession::State state)
+{
+ Q_Q(QNetworkAccessManager);
+}
+
+void QNetworkAccessManagerPrivate::_q_sessionNewConfigurationActivated()
+{
+ Q_Q(QNetworkAccessManager);
+
+ foreach (QObject *child, q->children()) {
+ QNetworkReply *reply = qobject_cast<QNetworkReply *>(child);
+ if (reply) {
+ emit q->debugMessage(QString::fromLatin1("Unexpected reply for %1").arg(reply->url().toString()));
+ }
+ }
+
+ session->accept();
+}
+
+void QNetworkAccessManagerPrivate::_q_sessionPreferredConfigurationChanged(const QNetworkConfiguration &config, bool isSeamless)
+{
+ Q_Q(QNetworkAccessManager);
+
+ deferredMigration = false;
+ foreach (QObject *child, q->children()) {
+ if (child->inherits("QNetworkReply")) {
+ deferredMigration = true;
+ break;
+ }
+ }
+
+ if (!deferredMigration)
+ session->migrate();
+}
+
QT_END_NAMESPACE
#include "moc_qnetworkaccessmanager.cpp"
diff --git a/src/network/access/qnetworkaccessmanager.h b/src/network/access/qnetworkaccessmanager.h
index 82bbd0303d..14aaf7817b 100644
--- a/src/network/access/qnetworkaccessmanager.h
+++ b/src/network/access/qnetworkaccessmanager.h
@@ -129,6 +129,12 @@ private:
Q_DECLARE_PRIVATE(QNetworkAccessManager)
Q_PRIVATE_SLOT(d_func(), void _q_replyFinished())
Q_PRIVATE_SLOT(d_func(), void _q_replySslErrors(QList<QSslError>))
+ Q_PRIVATE_SLOT(d_func(), void _q_sessionOpened())
+ Q_PRIVATE_SLOT(d_func(), void _q_sessionClosed())
+ Q_PRIVATE_SLOT(d_func(), void _q_sessionError(QNetworkSession::SessionError))
+ Q_PRIVATE_SLOT(d_func(), void _q_sessionStateChanged(QNetworkSession::State))
+ Q_PRIVATE_SLOT(d_func(), void _q_sessionNewConfigurationActivated())
+ Q_PRIVATE_SLOT(d_func(), void _q_sessionPreferredConfigurationChanged(QNetworkConfiguration,bool))
};
QT_END_NAMESPACE
diff --git a/src/network/access/qnetworkaccessmanager_p.h b/src/network/access/qnetworkaccessmanager_p.h
index b6a266c912..b9e3964983 100644
--- a/src/network/access/qnetworkaccessmanager_p.h
+++ b/src/network/access/qnetworkaccessmanager_p.h
@@ -76,7 +76,8 @@ public:
proxyFactory(0),
#endif
cookieJarCreated(false),
- session(0)
+ session(0),
+ deferredMigration(false)
{ }
~QNetworkAccessManagerPrivate();
@@ -107,6 +108,13 @@ public:
emit q->debugMessage(message);
}
+ void _q_sessionOpened();
+ void _q_sessionClosed();
+ void _q_sessionError(QNetworkSession::SessionError error);
+ void _q_sessionStateChanged(QNetworkSession::State state);
+ void _q_sessionNewConfigurationActivated();
+ void _q_sessionPreferredConfigurationChanged(const QNetworkConfiguration &config, bool isSeamless);
+
// this is the cache for storing downloaded files
QAbstractNetworkCache *networkCache;
@@ -121,6 +129,7 @@ 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/qnetworkreply.cpp b/src/network/access/qnetworkreply.cpp
index 0a8ea5d03a..e299b5b8c1 100644
--- a/src/network/access/qnetworkreply.cpp
+++ b/src/network/access/qnetworkreply.cpp
@@ -125,6 +125,10 @@ QNetworkReplyPrivate::QNetworkReplyPrivate()
encrypted channel could not be established. The sslErrors() signal
should have been emitted.
+ \value TemporaryNetworkFailureError the connection was broken due
+ to disconnection from the network, however the system has initiated
+ roaming to another access point. The request should be resubmitted.
+
\value ProxyConnectionRefusedError the connection to the proxy
server was refused (the proxy server is not accepting requests)
diff --git a/src/network/access/qnetworkreply.h b/src/network/access/qnetworkreply.h
index 5be4cce264..b39557a082 100644
--- a/src/network/access/qnetworkreply.h
+++ b/src/network/access/qnetworkreply.h
@@ -77,6 +77,7 @@ public:
TimeoutError,
OperationCanceledError,
SslHandshakeFailedError,
+ TemporaryNetworkFailureError,
UnknownNetworkError = 99,
// proxy errors (101-199):
diff --git a/src/network/access/qnetworkreplyimpl.cpp b/src/network/access/qnetworkreplyimpl.cpp
index f097a2bf3f..7eca323761 100644
--- a/src/network/access/qnetworkreplyimpl.cpp
+++ b/src/network/access/qnetworkreplyimpl.cpp
@@ -47,6 +47,7 @@
#include "QtCore/qdatetime.h"
#include "QtNetwork/qsslconfiguration.h"
#include "qnetworkaccesshttpbackend_p.h"
+#include "qnetworkaccessmanager_p.h"
#include <QtCore/QCoreApplication>
@@ -516,7 +517,33 @@ void QNetworkReplyImplPrivate::finished()
emit q->uploadProgress(0, 0);
resumeNotificationHandling();
- completeCacheSave();
+ if (manager->d_func()->session->state() == QNetworkSession::Roaming) {
+ // only content with a known size will fail with a temporary network failure error
+ if (!totalSize.isNull()) {
+ qDebug() << "Connection broke during download.";
+ qDebug() << "Don't worry, we've already started roaming :)";
+
+ if (bytesDownloaded == totalSize) {
+ qDebug() << "Luckily download has already 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.";
+ error(QNetworkReply::TemporaryNetworkFailureError, q->tr("Temporary network failure."));
+ }
+ }
+ }
+ }
+
+ // if we don't know the total size of or we received everything save the cache
+ if (totalSize.isNull() || totalSize == -1 || bytesDownloaded == totalSize)
+ completeCacheSave();
+ else
+ qDebug() << "Not saving cache.";
// note: might not be a good idea, since users could decide to delete us
// which would delete the backend too...