diff options
Diffstat (limited to 'src/network/access')
19 files changed, 319 insertions, 29 deletions
diff --git a/src/network/access/qhttpnetworkconnection.cpp b/src/network/access/qhttpnetworkconnection.cpp index a279990f4c..c3e3716b26 100644 --- a/src/network/access/qhttpnetworkconnection.cpp +++ b/src/network/access/qhttpnetworkconnection.cpp @@ -85,6 +85,7 @@ QHttpNetworkConnectionPrivate::QHttpNetworkConnectionPrivate(const QString &host #ifndef QT_NO_NETWORKPROXY , networkProxy(QNetworkProxy::NoProxy) #endif + , preConnectRequests(0) { channels = new QHttpNetworkConnectionChannel[channelCount]; } @@ -96,6 +97,7 @@ QHttpNetworkConnectionPrivate::QHttpNetworkConnectionPrivate(quint16 channelCoun #ifndef QT_NO_NETWORKPROXY , networkProxy(QNetworkProxy::NoProxy) #endif + , preConnectRequests(0) { channels = new QHttpNetworkConnectionChannel[channelCount]; } @@ -541,6 +543,9 @@ QHttpNetworkReply* QHttpNetworkConnectionPrivate::queueRequest(const QHttpNetwor reply->d_func()->connectionChannel = &channels[0]; // will have the correct one set later HttpMessagePair pair = qMakePair(request, reply); + if (request.isPreConnect()) + preConnectRequests++; + switch (request.priority()) { case QHttpNetworkRequest::HighPriority: highPriorityQueue.prepend(pair); @@ -925,13 +930,24 @@ void QHttpNetworkConnectionPrivate::_q_startNextRequest() // If there is not already any connected channels we need to connect a new one. // We do not pair the channel with the request until we know if it is // connected or not. This is to reuse connected channels before we connect new once. - int queuedRequest = highPriorityQueue.count() + lowPriorityQueue.count(); - for (int i = 0; i < channelCount; ++i) { + int queuedRequests = highPriorityQueue.count() + lowPriorityQueue.count(); + + // in case we have in-flight preconnect requests and normal requests, + // we only need one socket for each (preconnect, normal request) pair + int neededOpenChannels = queuedRequests; + if (preConnectRequests > 0) { + int normalRequests = queuedRequests - preConnectRequests; + neededOpenChannels = qMax(normalRequests, preConnectRequests); + } + for (int i = 0; i < channelCount && neededOpenChannels > 0; ++i) { bool connectChannel = false; if (channels[i].socket) { - if ((channels[i].socket->state() == QAbstractSocket::ConnectingState) || (channels[i].socket->state() == QAbstractSocket::HostLookupState)) - queuedRequest--; - if ( queuedRequest <=0 ) + if ((channels[i].socket->state() == QAbstractSocket::ConnectingState) + || (channels[i].socket->state() == QAbstractSocket::HostLookupState) + || channels[i].pendingEncrypt) // pendingEncrypt == "EncryptingState" + neededOpenChannels--; + + if (neededOpenChannels <= 0) break; if (!channels[i].reply && !channels[i].isSocketBusy() && (channels[i].socket->state() == QAbstractSocket::UnconnectedState)) connectChannel = true; @@ -945,11 +961,8 @@ void QHttpNetworkConnectionPrivate::_q_startNextRequest() else if (networkLayerState == IPv6) channels[i].networkLayerPreference = QAbstractSocket::IPv6Protocol; channels[i].ensureConnection(); - queuedRequest--; + neededOpenChannels--; } - - if ( queuedRequest <=0 ) - break; } } @@ -1270,6 +1283,11 @@ void QHttpNetworkConnection::ignoreSslErrors(const QList<QSslError> &errors, int #endif //QT_NO_SSL +void QHttpNetworkConnection::preConnectFinished() +{ + d_func()->preConnectRequests--; +} + #ifndef QT_NO_NETWORKPROXY // only called from QHttpNetworkConnectionChannel::_q_proxyAuthenticationRequired, not // from QHttpNetworkConnectionChannel::handleAuthenticationChallenge diff --git a/src/network/access/qhttpnetworkconnection_p.h b/src/network/access/qhttpnetworkconnection_p.h index 956499ddab..c54250f6ed 100644 --- a/src/network/access/qhttpnetworkconnection_p.h +++ b/src/network/access/qhttpnetworkconnection_p.h @@ -131,6 +131,8 @@ public: void setSslContext(QSharedPointer<QSslContext> context); #endif + void preConnectFinished(); + private: Q_DECLARE_PRIVATE(QHttpNetworkConnection) Q_DISABLE_COPY(QHttpNetworkConnection) @@ -239,6 +241,8 @@ public: QList<HttpMessagePair> highPriorityQueue; QList<HttpMessagePair> lowPriorityQueue; + int preConnectRequests; + #ifndef QT_NO_SSL QSharedPointer<QSslContext> sslContext; #endif diff --git a/src/network/access/qhttpnetworkconnectionchannel.cpp b/src/network/access/qhttpnetworkconnectionchannel.cpp index 5c537691e2..7aee9aa38a 100644 --- a/src/network/access/qhttpnetworkconnectionchannel.cpp +++ b/src/network/access/qhttpnetworkconnectionchannel.cpp @@ -183,6 +183,9 @@ void QHttpNetworkConnectionChannel::close() else state = QHttpNetworkConnectionChannel::ClosingState; + // pendingEncrypt must only be true in between connected and encrypted states + pendingEncrypt = false; + if (socket) socket->close(); } @@ -205,6 +208,17 @@ bool QHttpNetworkConnectionChannel::sendRequest() // _q_connected or _q_encrypted return false; } + QString scheme = request.url().scheme(); + if (scheme == QLatin1String("preconnect-http") + || scheme == QLatin1String("preconnect-https")) { + state = QHttpNetworkConnectionChannel::IdleState; + reply->d_func()->state = QHttpNetworkReplyPrivate::AllDoneState; + allDone(); + connection->preConnectFinished(); // will only decrease the counter + reply = 0; // so we can reuse this channel + return true; // we have a working connection and are done + } + written = 0; // excluding the header bytesTotal = 0; diff --git a/src/network/access/qhttpnetworkreply.cpp b/src/network/access/qhttpnetworkreply.cpp index eb8a8869cc..1b9e1f5a53 100644 --- a/src/network/access/qhttpnetworkreply.cpp +++ b/src/network/access/qhttpnetworkreply.cpp @@ -290,6 +290,11 @@ QHttpNetworkReplyPrivate::QHttpNetworkReplyPrivate(const QUrl &newUrl) #endif { + QString scheme = newUrl.scheme(); + if (scheme == QLatin1String("preconnect-http") + || scheme == QLatin1String("preconnect-https")) + // make sure we do not close the socket after preconnecting + connectionCloseEnabled = false; } QHttpNetworkReplyPrivate::~QHttpNetworkReplyPrivate() diff --git a/src/network/access/qhttpnetworkrequest.cpp b/src/network/access/qhttpnetworkrequest.cpp index e5b2eced99..d9f9b555d7 100644 --- a/src/network/access/qhttpnetworkrequest.cpp +++ b/src/network/access/qhttpnetworkrequest.cpp @@ -49,7 +49,8 @@ QT_BEGIN_NAMESPACE QHttpNetworkRequestPrivate::QHttpNetworkRequestPrivate(QHttpNetworkRequest::Operation op, QHttpNetworkRequest::Priority pri, const QUrl &newUrl) : QHttpNetworkHeaderPrivate(newUrl), operation(op), priority(pri), uploadByteDevice(0), - autoDecompress(false), pipeliningAllowed(false), withCredentials(true) + autoDecompress(false), pipeliningAllowed(false), withCredentials(true), + preConnect(false) { } @@ -64,6 +65,7 @@ QHttpNetworkRequestPrivate::QHttpNetworkRequestPrivate(const QHttpNetworkRequest customVerb = other.customVerb; withCredentials = other.withCredentials; ssl = other.ssl; + preConnect = other.preConnect; } QHttpNetworkRequestPrivate::~QHttpNetworkRequestPrivate() @@ -74,8 +76,15 @@ bool QHttpNetworkRequestPrivate::operator==(const QHttpNetworkRequestPrivate &ot { return QHttpNetworkHeaderPrivate::operator==(other) && (operation == other.operation) + && (priority == other.priority) + && (uploadByteDevice == other.uploadByteDevice) + && (autoDecompress == other.autoDecompress) + && (pipeliningAllowed == other.pipeliningAllowed) + // we do not clear the customVerb in setOperation + && (operation != QHttpNetworkRequest::Custom || (customVerb == other.customVerb)) + && (withCredentials == other.withCredentials) && (ssl == other.ssl) - && (uploadByteDevice == other.uploadByteDevice); + && (preConnect == other.preConnect); } QByteArray QHttpNetworkRequestPrivate::methodName() const @@ -205,6 +214,15 @@ void QHttpNetworkRequest::setSsl(bool s) d->ssl = s; } +bool QHttpNetworkRequest::isPreConnect() const +{ + return d->preConnect; +} +void QHttpNetworkRequest::setPreConnect(bool preConnect) +{ + d->preConnect = preConnect; +} + qint64 QHttpNetworkRequest::contentLength() const { return d->contentLength(); diff --git a/src/network/access/qhttpnetworkrequest_p.h b/src/network/access/qhttpnetworkrequest_p.h index fc4a6928c6..ce9fbb1509 100644 --- a/src/network/access/qhttpnetworkrequest_p.h +++ b/src/network/access/qhttpnetworkrequest_p.h @@ -120,6 +120,9 @@ public: bool isSsl() const; void setSsl(bool); + bool isPreConnect() const; + void setPreConnect(bool preConnect); + void setUploadByteDevice(QNonContiguousByteDevice *bd); QNonContiguousByteDevice* uploadByteDevice() const; @@ -151,6 +154,7 @@ public: bool pipeliningAllowed; bool withCredentials; bool ssl; + bool preConnect; }; diff --git a/src/network/access/qhttpthreaddelegate.cpp b/src/network/access/qhttpthreaddelegate.cpp index a2cee48b22..ee3911c72c 100644 --- a/src/network/access/qhttpthreaddelegate.cpp +++ b/src/network/access/qhttpthreaddelegate.cpp @@ -107,8 +107,14 @@ static QByteArray makeCacheKey(QUrl &url, QNetworkProxy *proxy) { QString result; QUrl copy = url; - bool isEncrypted = copy.scheme().toLower() == QLatin1String("https"); + QString scheme = copy.scheme().toLower(); + bool isEncrypted = scheme == QLatin1String("https"); copy.setPort(copy.port(isEncrypted ? 443 : 80)); + if (scheme == QLatin1String("preconnect-http")) { + copy.setScheme(QLatin1String("http")); + } else if (scheme == QLatin1String("preconnect-https")) { + copy.setScheme(QLatin1String("https")); + } result = copy.toString(QUrl::RemoveUserInfo | QUrl::RemovePath | QUrl::RemoveQuery | QUrl::RemoveFragment | QUrl::FullyEncoded); diff --git a/src/network/access/qnetworkaccessbackend.cpp b/src/network/access/qnetworkaccessbackend.cpp index a895864d76..47cd928541 100644 --- a/src/network/access/qnetworkaccessbackend.cpp +++ b/src/network/access/qnetworkaccessbackend.cpp @@ -47,6 +47,7 @@ #include "qnetworkreply_p.h" #include "QtCore/qhash.h" #include "QtCore/qmutex.h" +#include "QtCore/qstringlist.h" #include "QtNetwork/private/qnetworksession_p.h" #include "qnetworkaccesscachebackend_p.h" @@ -110,6 +111,22 @@ QNetworkAccessBackend *QNetworkAccessManagerPrivate::findBackend(QNetworkAccessM return 0; } +QStringList QNetworkAccessManagerPrivate::backendSupportedSchemes() const +{ + if (QNetworkAccessBackendFactoryData::valid.load()) { + QMutexLocker locker(&factoryData()->mutex); + QNetworkAccessBackendFactoryData::ConstIterator it = factoryData()->constBegin(); + QNetworkAccessBackendFactoryData::ConstIterator end = factoryData()->constEnd(); + QStringList schemes; + while (it != end) { + schemes += (*it)->supportedSchemes(); + ++it; + } + return schemes; + } + return QStringList(); +} + QNonContiguousByteDevice* QNetworkAccessBackend::createUploadByteDevice() { if (reply->outgoingDataBuffer) diff --git a/src/network/access/qnetworkaccessbackend_p.h b/src/network/access/qnetworkaccessbackend_p.h index bf284414e0..d9657cf750 100644 --- a/src/network/access/qnetworkaccessbackend_p.h +++ b/src/network/access/qnetworkaccessbackend_p.h @@ -62,6 +62,7 @@ class QAuthenticator; class QNetworkProxy; class QNetworkProxyQuery; class QNetworkRequest; +class QStringList; class QUrl; class QUrlInfo; class QSslConfiguration; @@ -219,6 +220,7 @@ class QNetworkAccessBackendFactory public: QNetworkAccessBackendFactory(); virtual ~QNetworkAccessBackendFactory(); + virtual QStringList supportedSchemes() const = 0; virtual QNetworkAccessBackend *create(QNetworkAccessManager::Operation op, const QNetworkRequest &request) const = 0; }; diff --git a/src/network/access/qnetworkaccessdebugpipebackend.cpp b/src/network/access/qnetworkaccessdebugpipebackend.cpp index b6c04dddea..a91751523a 100644 --- a/src/network/access/qnetworkaccessdebugpipebackend.cpp +++ b/src/network/access/qnetworkaccessdebugpipebackend.cpp @@ -42,6 +42,7 @@ #include "qnetworkaccessdebugpipebackend_p.h" #include "QtCore/qdatastream.h" #include <QCoreApplication> +#include <QStringList> #include <QUrlQuery> #include "private/qnoncontiguousbytedevice_p.h" @@ -54,6 +55,11 @@ enum { WriteBufferSize = ReadBufferSize }; +QStringList QNetworkAccessDebugPipeBackendFactory::supportedSchemes() const +{ + return QStringList(QStringLiteral("debugpipe")); +} + QNetworkAccessBackend * QNetworkAccessDebugPipeBackendFactory::create(QNetworkAccessManager::Operation op, const QNetworkRequest &request) const diff --git a/src/network/access/qnetworkaccessdebugpipebackend_p.h b/src/network/access/qnetworkaccessdebugpipebackend_p.h index 0ae49de132..7593dfa9b7 100644 --- a/src/network/access/qnetworkaccessdebugpipebackend_p.h +++ b/src/network/access/qnetworkaccessdebugpipebackend_p.h @@ -102,6 +102,7 @@ private: class QNetworkAccessDebugPipeBackendFactory: public QNetworkAccessBackendFactory { public: + virtual QStringList supportedSchemes() const Q_DECL_OVERRIDE; virtual QNetworkAccessBackend *create(QNetworkAccessManager::Operation op, const QNetworkRequest &request) const; }; diff --git a/src/network/access/qnetworkaccessfilebackend.cpp b/src/network/access/qnetworkaccessfilebackend.cpp index 13428cc802..13e7394003 100644 --- a/src/network/access/qnetworkaccessfilebackend.cpp +++ b/src/network/access/qnetworkaccessfilebackend.cpp @@ -49,6 +49,17 @@ QT_BEGIN_NAMESPACE +QStringList QNetworkAccessFileBackendFactory::supportedSchemes() const +{ + QStringList schemes; + schemes << QStringLiteral("file") + << QStringLiteral("qrc"); +#if defined(Q_OS_ANDROID) + schemes << QStringLiteral("assets"); +#endif + return schemes; +} + QNetworkAccessBackend * QNetworkAccessFileBackendFactory::create(QNetworkAccessManager::Operation op, const QNetworkRequest &request) const diff --git a/src/network/access/qnetworkaccessfilebackend_p.h b/src/network/access/qnetworkaccessfilebackend_p.h index a52ecef165..157461fee7 100644 --- a/src/network/access/qnetworkaccessfilebackend_p.h +++ b/src/network/access/qnetworkaccessfilebackend_p.h @@ -88,6 +88,7 @@ private: class QNetworkAccessFileBackendFactory: public QNetworkAccessBackendFactory { public: + virtual QStringList supportedSchemes() const Q_DECL_OVERRIDE; virtual QNetworkAccessBackend *create(QNetworkAccessManager::Operation op, const QNetworkRequest &request) const; }; diff --git a/src/network/access/qnetworkaccessftpbackend.cpp b/src/network/access/qnetworkaccessftpbackend.cpp index 737d7d0151..246eb41657 100644 --- a/src/network/access/qnetworkaccessftpbackend.cpp +++ b/src/network/access/qnetworkaccessftpbackend.cpp @@ -43,6 +43,7 @@ #include "qnetworkaccessmanager_p.h" #include "QtNetwork/qauthenticator.h" #include "private/qnoncontiguousbytedevice_p.h" +#include <QStringList> #ifndef QT_NO_FTP @@ -61,6 +62,11 @@ static QByteArray makeCacheKey(const QUrl &url) QUrl::RemoveFragment); } +QStringList QNetworkAccessFtpBackendFactory::supportedSchemes() const +{ + return QStringList(QStringLiteral("ftp")); +} + QNetworkAccessBackend * QNetworkAccessFtpBackendFactory::create(QNetworkAccessManager::Operation op, const QNetworkRequest &request) const diff --git a/src/network/access/qnetworkaccessftpbackend_p.h b/src/network/access/qnetworkaccessftpbackend_p.h index 1bc377d80e..c006d450b8 100644 --- a/src/network/access/qnetworkaccessftpbackend_p.h +++ b/src/network/access/qnetworkaccessftpbackend_p.h @@ -111,6 +111,7 @@ private: class QNetworkAccessFtpBackendFactory: public QNetworkAccessBackendFactory { public: + virtual QStringList supportedSchemes() const Q_DECL_OVERRIDE; virtual QNetworkAccessBackend *create(QNetworkAccessManager::Operation op, const QNetworkRequest &request) const; }; diff --git a/src/network/access/qnetworkaccessmanager.cpp b/src/network/access/qnetworkaccessmanager.cpp index 10d19bb7aa..91655ef485 100644 --- a/src/network/access/qnetworkaccessmanager.cpp +++ b/src/network/access/qnetworkaccessmanager.cpp @@ -96,9 +96,11 @@ bool getProxyAuth(const QString& proxyHostname, const QString &scheme, QString& SecProtocolType protocolType = kSecProtocolTypeAny; if (scheme.compare(QLatin1String("ftp"),Qt::CaseInsensitive)==0) { protocolType = kSecProtocolTypeFTP; - } else if (scheme.compare(QLatin1String("http"),Qt::CaseInsensitive)==0) { + } else if (scheme.compare(QLatin1String("http"),Qt::CaseInsensitive)==0 + || scheme.compare(QLatin1String("preconnect-http"),Qt::CaseInsensitive)==0) { protocolType = kSecProtocolTypeHTTP; - } else if (scheme.compare(QLatin1String("https"),Qt::CaseInsensitive)==0) { + } else if (scheme.compare(QLatin1String("https"),Qt::CaseInsensitive)==0 + || scheme.compare(QLatin1String("preconnect-https"),Qt::CaseInsensitive)==0) { protocolType = kSecProtocolTypeHTTPS; } QByteArray proxyHostnameUtf8(proxyHostname.toUtf8()); @@ -431,6 +433,7 @@ static void ensureInitialized() QNetworkAccessManager::QNetworkAccessManager(QObject *parent) : QObject(*new QNetworkAccessManagerPrivate, parent) { + Q_D(QNetworkAccessManager); ensureInitialized(); qRegisterMetaType<QNetworkReply::NetworkError>(); @@ -447,6 +450,19 @@ QNetworkAccessManager::QNetworkAccessManager(QObject *parent) #endif qRegisterMetaType<QNetworkReply::NetworkError>(); qRegisterMetaType<QSharedPointer<char> >(); + +#ifndef QT_NO_BEARERMANAGEMENT + if (!d->networkSessionRequired) { + // if a session is required, we track online state through + // the QNetworkSession's signals + connect(&d->networkConfigurationManager, SIGNAL(onlineStateChanged(bool)), + SLOT(_q_onlineStateChanged(bool))); + // we would need all active configurations to check for + // d->networkConfigurationManager.isOnline(), which is asynchronous + // and potentially expensive. We can just check the configuration here + d->online = (d->networkConfiguration.state() & QNetworkConfiguration::Active); + } +#endif } /*! @@ -833,6 +849,11 @@ QNetworkReply *QNetworkAccessManager::deleteResource(const QNetworkRequest &requ To restore the default network configuration set the network configuration to the value returned from QNetworkConfigurationManager::defaultConfiguration(). + Setting a network configuration means that the QNetworkAccessManager instance will only + be using the specified one. In particular, if the default network configuration changes + (upon e.g. Wifi being available), this new configuration needs to be enabled + manually if desired. + \snippet code/src_network_access_qnetworkaccessmanager.cpp 2 If an invalid network configuration is set, a network session will not be created. In this @@ -844,7 +865,10 @@ QNetworkReply *QNetworkAccessManager::deleteResource(const QNetworkRequest &requ */ void QNetworkAccessManager::setConfiguration(const QNetworkConfiguration &config) { - d_func()->createSession(config); + Q_D(QNetworkAccessManager); + d->networkConfiguration = config; + d->customNetworkConfiguration = true; + d->createSession(config); } /*! @@ -926,19 +950,73 @@ QNetworkAccessManager::NetworkAccessibility QNetworkAccessManager::networkAccess { Q_D(const QNetworkAccessManager); - QSharedPointer<QNetworkSession> networkSession(d->getNetworkSession()); - if (networkSession) { - // d->online holds online/offline state of this network session. + if (d->networkSessionRequired) { + QSharedPointer<QNetworkSession> networkSession(d->getNetworkSession()); + if (networkSession) { + // d->online holds online/offline state of this network session. + if (d->online) + return d->networkAccessible; + else + return NotAccessible; + } else { + // Network accessibility is either disabled or unknown. + return (d->networkAccessible == NotAccessible) ? NotAccessible : UnknownAccessibility; + } + } else { if (d->online) return d->networkAccessible; else return NotAccessible; - } else { - // Network accessibility is either disabled or unknown. - return (d->networkAccessible == NotAccessible) ? NotAccessible : UnknownAccessibility; } } +#ifndef QT_NO_SSL +/*! + \since 5.2 + + Initiates a connection to the host given by \a hostName at port \a port, using + \a sslConfiguration. This function is useful to complete the TCP and SSL handshake + to a host before the HTTPS request is made, resulting in a lower network latency. + + \note This function has no possibility to report errors. + + \sa connectToHost(), get(), post(), put(), deleteResource() +*/ +void QNetworkAccessManager::connectToHostEncrypted(const QString &hostName, quint16 port, + const QSslConfiguration &sslConfiguration) +{ + QUrl url; + url.setHost(hostName); + url.setPort(port); + url.setScheme(QLatin1String("preconnect-https")); + QNetworkRequest request(url); + if (sslConfiguration != QSslConfiguration::defaultConfiguration()) + request.setSslConfiguration(sslConfiguration); + get(request); +} +#endif + +/*! + \since 5.2 + + Initiates a connection to the host given by \a hostName at port \a port. + This function is useful to complete the TCP handshake + to a host before the HTTP request is made, resulting in a lower network latency. + + \note This function has no possibility to report errors. + + \sa connectToHostEncrypted(), get(), post(), put(), deleteResource() +*/ +void QNetworkAccessManager::connectToHost(const QString &hostName, quint16 port) +{ + QUrl url; + url.setHost(hostName); + url.setPort(port); + url.setScheme(QLatin1String("preconnect-http")); + QNetworkRequest request(url); + get(request); +} + /*! \internal @@ -1050,10 +1128,10 @@ QNetworkReply *QNetworkAccessManager::createRequest(QNetworkAccessManager::Opera return new QDisabledNetworkReply(this, req, op); } - if (!d->networkSessionStrongRef && (d->initializeSession || !d->networkConfiguration.isEmpty())) { + if (!d->networkSessionStrongRef && (d->initializeSession || !d->networkConfiguration.identifier().isEmpty())) { QNetworkConfigurationManager manager; - if (!d->networkConfiguration.isEmpty()) { - d->createSession(manager.configurationFromIdentifier(d->networkConfiguration)); + if (!d->networkConfiguration.identifier().isEmpty()) { + d->createSession(d->networkConfiguration); } else { if (manager.capabilities() & QNetworkConfigurationManager::NetworkSessionRequired) d->createSession(manager.defaultConfiguration()); @@ -1083,9 +1161,9 @@ QNetworkReply *QNetworkAccessManager::createRequest(QNetworkAccessManager::Opera #ifndef QT_NO_HTTP // Since Qt 5 we use the new QNetworkReplyHttpImpl - if (scheme == QLatin1String("http") + if (scheme == QLatin1String("http") || scheme == QLatin1String("preconnect-http") #ifndef QT_NO_SSL - || scheme == QLatin1String("https") + || scheme == QLatin1String("https") || scheme == QLatin1String("preconnect-https") #endif ) { QNetworkReplyHttpImpl *reply = new QNetworkReplyHttpImpl(this, request, op, outgoingData); @@ -1130,6 +1208,57 @@ QNetworkReply *QNetworkAccessManager::createRequest(QNetworkAccessManager::Opera return reply; } +/*! + \since 5.2 + + Lists all the URL schemes supported by the access manager. + + \sa supportedSchemesImplementation() +*/ +QStringList QNetworkAccessManager::supportedSchemes() const +{ + QStringList schemes; + QNetworkAccessManager *self = const_cast<QNetworkAccessManager *>(this); // We know we call a const slot + QMetaObject::invokeMethod(self, "supportedSchemesImplementation", Qt::DirectConnection, + Q_RETURN_ARG(QStringList, schemes)); + schemes.removeDuplicates(); + return schemes; +} + +/*! + \since 5.2 + + Lists all the URL schemes supported by the access manager. + + You should not call this function directly; use + QNetworkAccessManager::supportedSchemes() instead. + + Reimplement this slot to provide your own supported schemes + in a QNetworkAccessManager subclass. It is for instance necessary + when your subclass provides support for new protocols. + + Because of binary compatibility constraints, the supportedSchemes() + method (introduced in Qt 5.2) is not virtual. Instead, supportedSchemes() + will dynamically detect and call this slot. + + \sa supportedSchemes() +*/ +QStringList QNetworkAccessManager::supportedSchemesImplementation() const +{ + Q_D(const QNetworkAccessManager); + + QStringList schemes = d->backendSupportedSchemes(); + // Those ones don't exist in backends +#ifndef QT_NO_HTTP + schemes << QStringLiteral("http"); +#ifndef QT_NO_SSL + if (QSslSocket::supportsSsl()) + schemes << QStringLiteral("https"); +#endif +#endif + schemes << QStringLiteral("data"); + return schemes; +} /*! \since 5.0 @@ -1403,7 +1532,7 @@ void QNetworkAccessManagerPrivate::_q_networkSessionClosed() Q_Q(QNetworkAccessManager); QSharedPointer<QNetworkSession> networkSession(getNetworkSession()); if (networkSession) { - networkConfiguration = networkSession->configuration().identifier(); + networkConfiguration = networkSession->configuration(); //disconnect from old session QObject::disconnect(networkSession.data(), SIGNAL(opened()), q, SIGNAL(networkSessionConnected())); @@ -1437,6 +1566,18 @@ void QNetworkAccessManagerPrivate::_q_networkSessionStateChanged(QNetworkSession } } } + +void QNetworkAccessManagerPrivate::_q_onlineStateChanged(bool isOnline) +{ + // 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. + if (customNetworkConfiguration) { + online = (networkConfiguration.state() & QNetworkConfiguration::Active); + } else { + online = isOnline; + } +} + #endif // QT_NO_BEARERMANAGEMENT QNetworkRequest QNetworkAccessManagerPrivate::prepareMultipart(const QNetworkRequest &request, QHttpMultiPart *multiPart) diff --git a/src/network/access/qnetworkaccessmanager.h b/src/network/access/qnetworkaccessmanager.h index 826c8e47d7..67b9bbcb07 100644 --- a/src/network/access/qnetworkaccessmanager.h +++ b/src/network/access/qnetworkaccessmanager.h @@ -43,6 +43,9 @@ #define QNETWORKACCESSMANAGER_H #include <QtCore/QObject> +#ifndef QT_NO_SSL +#include <QtNetwork/QSslConfiguration> +#endif QT_BEGIN_NAMESPACE @@ -97,6 +100,9 @@ public: explicit QNetworkAccessManager(QObject *parent = 0); ~QNetworkAccessManager(); + // ### Qt 6: turn into virtual + QStringList supportedSchemes() const; + void clearAccessCache(); #ifndef QT_NO_NETWORKPROXY @@ -132,6 +138,12 @@ public: NetworkAccessibility networkAccessible() const; #endif +#ifndef QT_NO_SSL + void connectToHostEncrypted(const QString &hostName, quint16 port = 443, + const QSslConfiguration &sslConfiguration = QSslConfiguration::defaultConfiguration()); +#endif + void connectToHost(const QString &hostName, quint16 port = 80); + Q_SIGNALS: #ifndef QT_NO_NETWORKPROXY void proxyAuthenticationRequired(const QNetworkProxy &proxy, QAuthenticator *authenticator); @@ -153,6 +165,9 @@ protected: virtual QNetworkReply *createRequest(Operation op, const QNetworkRequest &request, QIODevice *outgoingData = 0); +protected Q_SLOTS: + QStringList supportedSchemesImplementation() const; + private: friend class QNetworkReplyImplPrivate; friend class QNetworkReplyHttpImpl; @@ -165,6 +180,7 @@ private: #ifndef QT_NO_BEARERMANAGEMENT Q_PRIVATE_SLOT(d_func(), void _q_networkSessionClosed()) Q_PRIVATE_SLOT(d_func(), void _q_networkSessionStateChanged(QNetworkSession::State)) + Q_PRIVATE_SLOT(d_func(), void _q_onlineStateChanged(bool)) #endif }; diff --git a/src/network/access/qnetworkaccessmanager_p.h b/src/network/access/qnetworkaccessmanager_p.h index cf756dad7b..292755e7eb 100644 --- a/src/network/access/qnetworkaccessmanager_p.h +++ b/src/network/access/qnetworkaccessmanager_p.h @@ -60,6 +60,9 @@ #include "QtNetwork/qnetworkproxy.h" #include "QtNetwork/qnetworksession.h" #include "qnetworkaccessauthenticationmanager_p.h" +#ifndef QT_NO_BEARERMANAGEMENT +#include "QtNetwork/qnetworkconfigmanager.h" +#endif QT_BEGIN_NAMESPACE @@ -79,6 +82,10 @@ public: #endif #ifndef QT_NO_BEARERMANAGEMENT lastSessionState(QNetworkSession::Invalid), + networkConfiguration(networkConfigurationManager.defaultConfiguration()), + customNetworkConfiguration(false), + networkSessionRequired(networkConfigurationManager.capabilities() + & QNetworkConfigurationManager::NetworkSessionRequired), networkAccessible(QNetworkAccessManager::Accessible), activeReplyCount(0), online(false), @@ -117,6 +124,7 @@ public: #endif QNetworkAccessBackend *findBackend(QNetworkAccessManager::Operation op, const QNetworkRequest &request); + QStringList backendSupportedSchemes() const; #ifndef QT_NO_BEARERMANAGEMENT void createSession(const QNetworkConfiguration &config); @@ -127,6 +135,7 @@ public: void _q_networkSessionPreferredConfigurationChanged(const QNetworkConfiguration &config, bool isSeamless); void _q_networkSessionStateChanged(QNetworkSession::State state); + void _q_onlineStateChanged(bool isOnline); #endif QNetworkRequest prepareMultipart(const QNetworkRequest &request, QHttpMultiPart *multiPart); @@ -148,7 +157,12 @@ public: QSharedPointer<QNetworkSession> networkSessionStrongRef; QWeakPointer<QNetworkSession> networkSessionWeakRef; QNetworkSession::State lastSessionState; - QString networkConfiguration; + QNetworkConfigurationManager networkConfigurationManager; + QNetworkConfiguration networkConfiguration; + // we need to track whether the user set a config or not, + // because the default config might change + bool customNetworkConfiguration; + bool networkSessionRequired; QNetworkAccessManager::NetworkAccessibility networkAccessible; int activeReplyCount; bool online; diff --git a/src/network/access/qnetworkreplyhttpimpl.cpp b/src/network/access/qnetworkreplyhttpimpl.cpp index c7d3846465..ddef970966 100644 --- a/src/network/access/qnetworkreplyhttpimpl.cpp +++ b/src/network/access/qnetworkreplyhttpimpl.cpp @@ -629,10 +629,15 @@ void QNetworkReplyHttpImplPrivate::postRequest() QUrl url = request.url(); httpRequest.setUrl(url); - bool ssl = url.scheme().toLower() == QLatin1String("https"); + QString scheme = url.scheme().toLower(); + bool ssl = (scheme == QLatin1String("https") + || scheme == QLatin1String("preconnect-https")); q->setAttribute(QNetworkRequest::ConnectionEncryptedAttribute, ssl); httpRequest.setSsl(ssl); + bool preConnect = (scheme == QLatin1String("preconnect-http") + || scheme == QLatin1String("preconnect-https")); + httpRequest.setPreConnect(preConnect); #ifndef QT_NO_NETWORKPROXY QNetworkProxy transparentProxy, cacheProxy; |