From 402cb62d5db7516e4d8d77d972e55e90cb855679 Mon Sep 17 00:00:00 2001 From: Timur Pocheptsov Date: Fri, 15 Mar 2019 12:05:38 +0100 Subject: Introduce QNetworkConnection/Status/Monitor MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Private classes to replace broken or even not working at all 'session management' and 'bearer manager' (on at least two major platforms we support). This implementation is macOS/iOS-specific and uses SystemConfiguration framework, or more precisely SCNetworkReachability's part of it. Task-number: QTBUG-40332 Change-Id: Iac5f44c4063c4092b93b8cf2bde3fb2c524855b3 Reviewed-by: MÃ¥rten Nordheim --- src/network/access/qnetworkaccessmanager.cpp | 153 +++++++++++++++++++-------- 1 file changed, 111 insertions(+), 42 deletions(-) (limited to 'src/network/access/qnetworkaccessmanager.cpp') diff --git a/src/network/access/qnetworkaccessmanager.cpp b/src/network/access/qnetworkaccessmanager.cpp index 50b9488594..8bd630ad9d 100644 --- a/src/network/access/qnetworkaccessmanager.cpp +++ b/src/network/access/qnetworkaccessmanager.cpp @@ -90,6 +90,8 @@ #include "qnetworkreplywasmimpl_p.h" #endif +#include "qnetconmonitor_p.h" + QT_BEGIN_NAMESPACE Q_GLOBAL_STATIC(QNetworkAccessFileBackendFactory, fileBackend) @@ -486,18 +488,25 @@ QNetworkAccessManager::QNetworkAccessManager(QObject *parent) qRegisterMetaType(); qRegisterMetaType >(); -#ifndef QT_NO_BEARERMANAGEMENT Q_D(QNetworkAccessManager); - // if a session is required, we track online state through - // the QNetworkSession's signals if a request is already made. - // we need to track current accessibility state by default - // - connect(&d->networkConfigurationManager, SIGNAL(onlineStateChanged(bool)), - SLOT(_q_onlineStateChanged(bool))); - connect(&d->networkConfigurationManager, SIGNAL(configurationChanged(QNetworkConfiguration)), - SLOT(_q_configurationChanged(QNetworkConfiguration))); - -#endif + if (QNetworkStatusMonitor::isEnabled()) { + connect(&d->statusMonitor, SIGNAL(onlineStateChanged(bool)), + SLOT(_q_onlineStateChanged(bool))); +#ifdef QT_NO_BEARERMANAGEMENT + d->networkAccessible = d->statusMonitor.isNetworkAccesible(); +#else + d->networkAccessible = d->statusMonitor.isNetworkAccesible() ? Accessible : NotAccessible; + } else { + // if a session is required, we track online state through + // the QNetworkSession's signals if a request is already made. + // we need to track current accessibility state by default + // + connect(&d->networkConfigurationManager, SIGNAL(onlineStateChanged(bool)), + SLOT(_q_onlineStateChanged(bool))); + connect(&d->networkConfigurationManager, SIGNAL(configurationChanged(QNetworkConfiguration)), + SLOT(_q_configurationChanged(QNetworkConfiguration))); +#endif // QT_NO_BEARERMANAGEMENT + } } /*! @@ -1030,9 +1039,13 @@ QNetworkReply *QNetworkAccessManager::deleteResource(const QNetworkRequest &requ void QNetworkAccessManager::setConfiguration(const QNetworkConfiguration &config) { Q_D(QNetworkAccessManager); - d->networkConfiguration = config; - d->customNetworkConfiguration = true; - d->createSession(config); + if (!d->statusMonitor.isEnabled()) { + d->networkConfiguration = config; + d->customNetworkConfiguration = true; + d->createSession(config); + } else { + qWarning(lcNetMon, "No network configuration can be set with network status monitor enabled"); + } } /*! @@ -1048,7 +1061,7 @@ QNetworkConfiguration QNetworkAccessManager::configuration() const Q_D(const QNetworkAccessManager); QSharedPointer session(d->getNetworkSession()); - if (session) { + if (session && !d->statusMonitor.isEnabled()) { return session->configuration(); } else { return d->networkConfigurationManager.defaultConfiguration(); @@ -1075,7 +1088,7 @@ QNetworkConfiguration QNetworkAccessManager::activeConfiguration() const Q_D(const QNetworkAccessManager); QSharedPointer networkSession(d->getNetworkSession()); - if (networkSession) { + if (networkSession && !d->statusMonitor.isEnabled()) { return d->networkConfigurationManager.configurationFromIdentifier( networkSession->sessionProperty(QLatin1String("ActiveConfiguration")).toString()); } else { @@ -1094,6 +1107,11 @@ void QNetworkAccessManager::setNetworkAccessible(QNetworkAccessManager::NetworkA { Q_D(QNetworkAccessManager); + if (d->statusMonitor.isEnabled()) { + qWarning(lcNetMon, "Can not manually set network accessibility with the network status monitor enabled"); + return; + } + d->defaultAccessControl = accessible == NotAccessible ? false : true; if (d->networkAccessible != accessible) { @@ -1114,6 +1132,12 @@ QNetworkAccessManager::NetworkAccessibility QNetworkAccessManager::networkAccess { Q_D(const QNetworkAccessManager); + if (d->statusMonitor.isEnabled()) { + if (!d->statusMonitor.isMonitoring()) + d->statusMonitor.start(); + return d->networkAccessible; + } + if (d->customNetworkConfiguration && d->networkConfiguration.state().testFlag(QNetworkConfiguration::Undefined)) return UnknownAccessibility; @@ -1434,35 +1458,57 @@ QNetworkReply *QNetworkAccessManager::createRequest(QNetworkAccessManager::Opera } } -#ifndef QT_NO_BEARERMANAGEMENT + if (d->statusMonitor.isEnabled()) { + // See the code in ctor - QNetworkStatusMonitor allows us to + // immediately set 'networkAccessible' even before we start + // the monitor. +#ifdef QT_NO_BEARERMANAGEMENT + if (d->networkAccessible +#else + if (d->networkAccessible == NotAccessible +#endif // QT_NO_BEARERMANAGEMENT + && !isLocalFile) { + QHostAddress dest; + QString host = req.url().host().toLower(); + if (!(dest.setAddress(host) && dest.isLoopback()) + && host != QLatin1String("localhost") + && host != QHostInfo::localHostName().toLower()) { + return new QDisabledNetworkReply(this, req, op); + } + } - // Return a disabled network reply if network access is disabled. - // Except if the scheme is empty or file:// or if the host resolves to a loopback address. - if (d->networkAccessible == NotAccessible && !isLocalFile) { - QHostAddress dest; - QString host = req.url().host().toLower(); - if (!(dest.setAddress(host) && dest.isLoopback()) && host != QLatin1String("localhost") + if (!d->statusMonitor.isMonitoring() && !d->statusMonitor.start()) + qWarning(lcNetMon, "failed to start network status monitoring"); + } else { +#ifndef QT_NO_BEARERMANAGEMENT + // Return a disabled network reply if network access is disabled. + // Except if the scheme is empty or file:// or if the host resolves to a loopback address. + if (d->networkAccessible == NotAccessible && !isLocalFile) { + QHostAddress dest; + QString host = req.url().host().toLower(); + if (!(dest.setAddress(host) && dest.isLoopback()) && host != QLatin1String("localhost") && host != QHostInfo::localHostName().toLower()) { - return new QDisabledNetworkReply(this, req, op); + return new QDisabledNetworkReply(this, req, op); + } } - } - if (!d->networkSessionStrongRef && (d->initializeSession || !d->networkConfiguration.identifier().isEmpty())) { - if (!d->networkConfiguration.identifier().isEmpty()) { - if ((d->networkConfiguration.state() & QNetworkConfiguration::Defined) - && d->networkConfiguration != d->networkConfigurationManager.defaultConfiguration()) - d->createSession(d->networkConfigurationManager.defaultConfiguration()); - else - d->createSession(d->networkConfiguration); + if (!d->networkSessionStrongRef && (d->initializeSession || !d->networkConfiguration.identifier().isEmpty())) { + if (!d->networkConfiguration.identifier().isEmpty()) { + if ((d->networkConfiguration.state() & QNetworkConfiguration::Defined) + && d->networkConfiguration != d->networkConfigurationManager.defaultConfiguration()) + d->createSession(d->networkConfigurationManager.defaultConfiguration()); + else + d->createSession(d->networkConfiguration); - } else { - if (d->networkSessionRequired) - d->createSession(d->networkConfigurationManager.defaultConfiguration()); - else - d->initializeSession = false; + } else { + if (d->networkSessionRequired) + d->createSession(d->networkConfigurationManager.defaultConfiguration()); + else + d->initializeSession = false; + } } - } #endif + } QNetworkRequest request = req; if (!request.header(QNetworkRequest::ContentLengthHeader).isValid() && @@ -1509,8 +1555,10 @@ QNetworkReply *QNetworkAccessManager::createRequest(QNetworkAccessManager::Opera #endif QNetworkReplyHttpImpl *reply = new QNetworkReplyHttpImpl(this, request, op, outgoingData); #ifndef QT_NO_BEARERMANAGEMENT - connect(this, SIGNAL(networkSessionConnected()), - reply, SLOT(_q_networkSessionConnected())); + if (!d->statusMonitor.isEnabled()) { + connect(this, SIGNAL(networkSessionConnected()), + reply, SLOT(_q_networkSessionConnected())); + } #endif return reply; } @@ -1519,7 +1567,9 @@ QNetworkReply *QNetworkAccessManager::createRequest(QNetworkAccessManager::Opera // first step: create the reply QNetworkReplyImpl *reply = new QNetworkReplyImpl(this); #ifndef QT_NO_BEARERMANAGEMENT - if (!isLocalFile) { + // NETMONTODO: network reply impl must be augmented to use the same monitoring + // capabilities as http network reply impl does. + if (!isLocalFile && !d->statusMonitor.isEnabled()) { connect(this, SIGNAL(networkSessionConnected()), reply, SLOT(_q_networkSessionConnected())); } @@ -1988,7 +2038,13 @@ void QNetworkAccessManagerPrivate::_q_networkSessionStateChanged(QNetworkSession void QNetworkAccessManagerPrivate::_q_onlineStateChanged(bool isOnline) { - Q_Q(QNetworkAccessManager); + Q_Q(QNetworkAccessManager); + + if (statusMonitor.isEnabled()) { + networkAccessible = isOnline ? QNetworkAccessManager::Accessible : QNetworkAccessManager::NotAccessible; + return; + } + // if the user set a config, we only care whether this one is active. // Otherwise, this QNAM is online if there is an online config. @@ -2018,6 +2074,9 @@ void QNetworkAccessManagerPrivate::_q_onlineStateChanged(bool isOnline) void QNetworkAccessManagerPrivate::_q_configurationChanged(const QNetworkConfiguration &configuration) { + if (statusMonitor.isEnabled()) + return; + const QString id = configuration.identifier(); if (configuration.state().testFlag(QNetworkConfiguration::Active)) { if (!onlineConfigurations.contains(id)) { @@ -2050,6 +2109,9 @@ void QNetworkAccessManagerPrivate::_q_configurationChanged(const QNetworkConfigu void QNetworkAccessManagerPrivate::_q_networkSessionFailed(QNetworkSession::SessionError) { + if (statusMonitor.isEnabled()) + return; + const auto cfgs = networkConfigurationManager.allConfigurations(); for (const QNetworkConfiguration &cfg : cfgs) { if (cfg.state().testFlag(QNetworkConfiguration::Active)) { @@ -2061,6 +2123,13 @@ void QNetworkAccessManagerPrivate::_q_networkSessionFailed(QNetworkSession::Sess } } +#else + +void QNetworkAccessManagerPrivate::_q_onlineStateChanged(bool isOnline) +{ + networkAccessible = isOnline; +} + #endif // QT_NO_BEARERMANAGEMENT #if QT_CONFIG(http) -- cgit v1.2.3