summaryrefslogtreecommitdiffstats
path: root/src/network
diff options
context:
space:
mode:
Diffstat (limited to 'src/network')
-rw-r--r--src/network/access/access.pri7
-rw-r--r--src/network/access/qabstractnetworkcache.h1
-rw-r--r--src/network/access/qhsts_p.h1
-rw-r--r--src/network/access/qhttp2protocolhandler.cpp12
-rw-r--r--src/network/access/qhttpnetworkconnection.cpp54
-rw-r--r--src/network/access/qhttpnetworkconnection_p.h2
-rw-r--r--src/network/access/qhttpnetworkconnectionchannel.cpp76
-rw-r--r--src/network/access/qhttpnetworkconnectionchannel_p.h7
-rw-r--r--src/network/access/qhttpnetworkreply.cpp14
-rw-r--r--src/network/access/qhttpnetworkreply_p.h12
-rw-r--r--src/network/access/qhttpnetworkrequest.cpp14
-rw-r--r--src/network/access/qhttpnetworkrequest_p.h4
-rw-r--r--src/network/access/qhttpthreaddelegate.cpp19
-rw-r--r--src/network/access/qhttpthreaddelegate_p.h2
-rw-r--r--src/network/access/qnetworkaccessmanager.cpp6
-rw-r--r--src/network/access/qnetworkaccessmanager.h1
-rw-r--r--src/network/access/qnetworkreplyhttpimpl.cpp20
-rw-r--r--src/network/access/qnetworkrequest.cpp18
-rw-r--r--src/network/access/qnetworkrequest.h8
-rw-r--r--src/network/access/qspdyprotocolhandler_p.h232
-rw-r--r--src/network/bearer/bearer.pri3
-rw-r--r--src/network/bearer/qbearerengine_impl_p.h85
-rw-r--r--src/network/bearer/qnetworksession_impl.cpp439
-rw-r--r--src/network/bearer/qnetworksession_impl_p.h134
-rw-r--r--src/network/kernel/qnetworkinterface.h1
-rw-r--r--src/network/socket/qlocalserver_p.h9
-rw-r--r--src/network/socket/qlocalserver_win.cpp38
-rw-r--r--src/network/ssl/qssl.cpp3
-rw-r--r--src/network/ssl/qssl.h10
-rw-r--r--src/network/ssl/qsslconfiguration.cpp102
-rw-r--r--src/network/ssl/qsslconfiguration.h8
-rw-r--r--src/network/ssl/qsslconfiguration_p.h8
-rw-r--r--src/network/ssl/qsslcontext_openssl.cpp78
-rw-r--r--src/network/ssl/qsslsocket.cpp153
-rw-r--r--src/network/ssl/qsslsocket.h47
-rw-r--r--src/network/ssl/qsslsocket_mac.cpp54
-rw-r--r--src/network/ssl/qsslsocket_openssl.cpp290
-rw-r--r--src/network/ssl/qsslsocket_openssl_p.h13
-rw-r--r--src/network/ssl/qsslsocket_openssl_symbols.cpp8
-rw-r--r--src/network/ssl/qsslsocket_openssl_symbols_p.h4
-rw-r--r--src/network/ssl/qsslsocket_p.h1
-rw-r--r--src/network/ssl/qsslsocket_schannel.cpp6
-rw-r--r--src/network/ssl/qsslsocket_winrt.cpp12
43 files changed, 1382 insertions, 634 deletions
diff --git a/src/network/access/access.pri b/src/network/access/access.pri
index cfb20dcd71..083fbbf5fd 100644
--- a/src/network/access/access.pri
+++ b/src/network/access/access.pri
@@ -114,11 +114,4 @@ qtConfig(http) {
access/qhttpthreaddelegate_p.h \
access/qnetworkreplyhttpimpl_p.h \
access/qhttp2configuration.h
-
- qtConfig(ssl) {
- SOURCES += \
- access/qspdyprotocolhandler.cpp
- HEADERS += \
- access/qspdyprotocolhandler_p.h
- }
}
diff --git a/src/network/access/qabstractnetworkcache.h b/src/network/access/qabstractnetworkcache.h
index e357dfe58f..a4048c5b8f 100644
--- a/src/network/access/qabstractnetworkcache.h
+++ b/src/network/access/qabstractnetworkcache.h
@@ -52,7 +52,6 @@ QT_BEGIN_NAMESPACE
class QIODevice;
class QDateTime;
class QUrl;
-template<class T> class QList;
class QNetworkCacheMetaDataPrivate;
class Q_NETWORK_EXPORT QNetworkCacheMetaData
diff --git a/src/network/access/qhsts_p.h b/src/network/access/qhsts_p.h
index c219d9eab5..b5be4ff455 100644
--- a/src/network/access/qhsts_p.h
+++ b/src/network/access/qhsts_p.h
@@ -66,7 +66,6 @@
QT_BEGIN_NAMESPACE
-template<typename T> class QList;
template <typename T> class QVector;
class Q_AUTOTEST_EXPORT QHstsCache
diff --git a/src/network/access/qhttp2protocolhandler.cpp b/src/network/access/qhttp2protocolhandler.cpp
index dce51d4fd5..efbeb17d39 100644
--- a/src/network/access/qhttp2protocolhandler.cpp
+++ b/src/network/access/qhttp2protocolhandler.cpp
@@ -332,13 +332,13 @@ bool QHttp2ProtocolHandler::sendRequest()
// so we cannot create new streams.
m_channel->emitFinishedWithError(QNetworkReply::ProtocolUnknownError,
"GOAWAY received, cannot start a request");
- m_channel->spdyRequestsToSend.clear();
+ m_channel->h2RequestsToSend.clear();
return false;
}
// Process 'fake' (created by QNetworkAccessManager::connectToHostEncrypted())
// requests first:
- auto &requests = m_channel->spdyRequestsToSend;
+ auto &requests = m_channel->h2RequestsToSend;
for (auto it = requests.begin(), endIt = requests.end(); it != endIt;) {
const auto &pair = *it;
const QString scheme(pair.first.url().scheme());
@@ -862,7 +862,7 @@ void QHttp2ProtocolHandler::handleGOAWAY()
m_channel->emitFinishedWithError(QNetworkReply::ProtocolUnknownError,
"GOAWAY received, cannot start a request");
// Also, prevent further calls to sendRequest:
- m_channel->spdyRequestsToSend.clear();
+ m_channel->h2RequestsToSend.clear();
QNetworkReply::NetworkError error = QNetworkReply::NoError;
QString message;
@@ -1281,7 +1281,7 @@ quint32 QHttp2ProtocolHandler::createNewStream(const HttpMessagePair &message, b
const auto replyPrivate = reply->d_func();
replyPrivate->connection = m_connection;
replyPrivate->connectionChannel = m_channel;
- reply->setSpdyWasUsed(true);
+ reply->setHttp2WasUsed(true);
streamIDs.insert(reply, newStreamID);
connect(reply, SIGNAL(destroyed(QObject*)),
this, SLOT(_q_replyDestroyed(QObject*)));
@@ -1387,7 +1387,7 @@ void QHttp2ProtocolHandler::deleteActiveStream(quint32 streamID)
}
removeFromSuspended(streamID);
- if (m_channel->spdyRequestsToSend.size())
+ if (m_channel->h2RequestsToSend.size())
QMetaObject::invokeMethod(this, "sendRequest", Qt::QueuedConnection);
}
@@ -1506,7 +1506,7 @@ void QHttp2ProtocolHandler::initReplyFromPushPromise(const HttpMessagePair &mess
Q_ASSERT(promisedData.contains(cacheKey));
auto promise = promisedData.take(cacheKey);
Q_ASSERT(message.second);
- message.second->setSpdyWasUsed(true);
+ message.second->setHttp2WasUsed(true);
qCDebug(QT_HTTP2) << "found cached/promised response on stream" << promise.reservedID;
diff --git a/src/network/access/qhttpnetworkconnection.cpp b/src/network/access/qhttpnetworkconnection.cpp
index b9a4c874c0..04f63e8735 100644
--- a/src/network/access/qhttpnetworkconnection.cpp
+++ b/src/network/access/qhttpnetworkconnection.cpp
@@ -82,9 +82,6 @@ QHttpNetworkConnectionPrivate::QHttpNetworkConnectionPrivate(const QString &host
hostName(hostName), port(port), encrypt(encrypt), delayIpv4(true)
, activeChannelCount(type == QHttpNetworkConnection::ConnectionTypeHTTP2
|| type == QHttpNetworkConnection::ConnectionTypeHTTP2Direct
-#ifndef QT_NO_SSL
- || type == QHttpNetworkConnection::ConnectionTypeSPDY
-#endif
? 1 : defaultHttpChannelCount)
, channelCount(defaultHttpChannelCount)
#ifndef QT_NO_NETWORKPROXY
@@ -93,9 +90,9 @@ QHttpNetworkConnectionPrivate::QHttpNetworkConnectionPrivate(const QString &host
, preConnectRequests(0)
, connectionType(type)
{
- // We allocate all 6 channels even if it's SPDY or HTTP/2 enabled
- // connection: in case the protocol negotiation via NPN/ALPN fails,
- // we will have normally working HTTP/1.1.
+ // We allocate all 6 channels even if it's HTTP/2 enabled connection:
+ // in case the protocol negotiation via NPN/ALPN fails, we will have
+ // normally working HTTP/1.1.
Q_ASSERT(channelCount >= activeChannelCount);
channels = new QHttpNetworkConnectionChannel[channelCount];
}
@@ -641,10 +638,10 @@ QHttpNetworkReply* QHttpNetworkConnectionPrivate::queueRequest(const QHttpNetwor
break;
}
}
- else { // SPDY, HTTP/2 ('h2' mode)
+ else { // HTTP/2 ('h2' mode)
if (!pair.second->d_func()->requestIsPrepared)
prepareRequest(pair);
- channels[0].spdyRequestsToSend.insert(request.priority(), pair);
+ channels[0].h2RequestsToSend.insert(request.priority(), pair);
}
#ifndef Q_OS_WINRT
@@ -680,7 +677,7 @@ void QHttpNetworkConnectionPrivate::fillHttp2Queue()
for (auto &pair : highPriorityQueue) {
if (!pair.second->d_func()->requestIsPrepared)
prepareRequest(pair);
- channels[0].spdyRequestsToSend.insert(QHttpNetworkRequest::HighPriority, pair);
+ channels[0].h2RequestsToSend.insert(QHttpNetworkRequest::HighPriority, pair);
}
highPriorityQueue.clear();
@@ -688,7 +685,7 @@ void QHttpNetworkConnectionPrivate::fillHttp2Queue()
for (auto &pair : lowPriorityQueue) {
if (!pair.second->d_func()->requestIsPrepared)
prepareRequest(pair);
- channels[0].spdyRequestsToSend.insert(pair.first.priority(), pair);
+ channels[0].h2RequestsToSend.insert(pair.first.priority(), pair);
}
lowPriorityQueue.clear();
@@ -984,12 +981,12 @@ void QHttpNetworkConnectionPrivate::removeReply(QHttpNetworkReply *reply)
}
}
#ifndef QT_NO_SSL
- // is the reply inside the SPDY pipeline of this channel already?
- QMultiMap<int, HttpMessagePair>::iterator it = channels[i].spdyRequestsToSend.begin();
- QMultiMap<int, HttpMessagePair>::iterator end = channels[i].spdyRequestsToSend.end();
+ // is the reply inside the H2 pipeline of this channel already?
+ QMultiMap<int, HttpMessagePair>::iterator it = channels[i].h2RequestsToSend.begin();
+ QMultiMap<int, HttpMessagePair>::iterator end = channels[i].h2RequestsToSend.end();
for (; it != end; ++it) {
if (it.value().second == reply) {
- channels[i].spdyRequestsToSend.remove(it.key());
+ channels[i].h2RequestsToSend.remove(it.key());
QMetaObject::invokeMethod(q, "_q_startNextRequest", Qt::QueuedConnection);
return;
@@ -1068,9 +1065,8 @@ void QHttpNetworkConnectionPrivate::_q_startNextRequest()
break;
}
case QHttpNetworkConnection::ConnectionTypeHTTP2Direct:
- case QHttpNetworkConnection::ConnectionTypeHTTP2:
- case QHttpNetworkConnection::ConnectionTypeSPDY: {
- if (channels[0].spdyRequestsToSend.isEmpty() && channels[0].switchedToHttp2)
+ case QHttpNetworkConnection::ConnectionTypeHTTP2: {
+ if (channels[0].h2RequestsToSend.isEmpty() && channels[0].switchedToHttp2)
return;
if (networkLayerState == IPv4)
@@ -1079,7 +1075,7 @@ void QHttpNetworkConnectionPrivate::_q_startNextRequest()
channels[0].networkLayerPreference = QAbstractSocket::IPv6Protocol;
channels[0].ensureConnection();
if (channels[0].socket && channels[0].socket->state() == QAbstractSocket::ConnectedState
- && !channels[0].pendingEncrypt && channels[0].spdyRequestsToSend.size())
+ && !channels[0].pendingEncrypt && channels[0].h2RequestsToSend.size())
channels[0].sendRequest();
break;
}
@@ -1234,19 +1230,18 @@ void QHttpNetworkConnectionPrivate::_q_hostLookupFinished(const QHostInfo &info)
if (dequeueRequest(channels[0].socket)) {
emitReplyError(channels[0].socket, channels[0].reply, QNetworkReply::HostNotFoundError);
networkLayerState = QHttpNetworkConnectionPrivate::Unknown;
- } else if (connectionType == QHttpNetworkConnection::ConnectionTypeSPDY
- || connectionType == QHttpNetworkConnection::ConnectionTypeHTTP2
+ } else if (connectionType == QHttpNetworkConnection::ConnectionTypeHTTP2
|| connectionType == QHttpNetworkConnection::ConnectionTypeHTTP2Direct) {
- for (const HttpMessagePair &spdyPair : qAsConst(channels[0].spdyRequestsToSend)) {
+ for (const HttpMessagePair &h2Pair : qAsConst(channels[0].h2RequestsToSend)) {
// emit error for all replies
- QHttpNetworkReply *currentReply = spdyPair.second;
+ QHttpNetworkReply *currentReply = h2Pair.second;
Q_ASSERT(currentReply);
emitReplyError(channels[0].socket, currentReply, QNetworkReply::HostNotFoundError);
}
} else {
// Should not happen: we start a host lookup before sending a request,
- // so it's natural to have requests either in SPDY/HTTP/2 queue,
- // or in low/high priority queues.
+ // so it's natural to have requests either in HTTP/2 queue, or in low/high
+ // priority queues.
qWarning("QHttpNetworkConnectionPrivate::_q_hostLookupFinished"
" could not de-queue request, failed to report HostNotFoundError");
networkLayerState = QHttpNetworkConnectionPrivate::Unknown;
@@ -1576,17 +1571,12 @@ void QHttpNetworkConnectionPrivate::emitProxyAuthenticationRequired(const QHttpN
pauseConnection();
QHttpNetworkReply *reply;
if (connectionType == QHttpNetworkConnection::ConnectionTypeHTTP2
- || connectionType == QHttpNetworkConnection::ConnectionTypeHTTP2Direct
-#if QT_CONFIG(ssl)
- || connectionType == QHttpNetworkConnection::ConnectionTypeSPDY
-#endif
- ) {
-
+ || connectionType == QHttpNetworkConnection::ConnectionTypeHTTP2Direct) {
// we choose the reply to emit the proxyAuth signal from somewhat arbitrarily,
// but that does not matter because the signal will ultimately be emitted
// by the QNetworkAccessManager.
- Q_ASSERT(chan->spdyRequestsToSend.count() > 0);
- reply = chan->spdyRequestsToSend.cbegin().value().second;
+ Q_ASSERT(chan->h2RequestsToSend.count() > 0);
+ reply = chan->h2RequestsToSend.cbegin().value().second;
} else { // HTTP
reply = chan->reply;
}
diff --git a/src/network/access/qhttpnetworkconnection_p.h b/src/network/access/qhttpnetworkconnection_p.h
index 6808a0c0ac..fee84bb6c0 100644
--- a/src/network/access/qhttpnetworkconnection_p.h
+++ b/src/network/access/qhttpnetworkconnection_p.h
@@ -96,7 +96,6 @@ public:
enum ConnectionType {
ConnectionTypeHTTP,
- ConnectionTypeSPDY,
ConnectionTypeHTTP2,
ConnectionTypeHTTP2Direct
};
@@ -172,7 +171,6 @@ private:
friend class QHttpNetworkConnectionChannel;
friend class QHttp2ProtocolHandler;
friend class QHttpProtocolHandler;
- friend class QSpdyProtocolHandler;
Q_PRIVATE_SLOT(d_func(), void _q_startNextRequest())
Q_PRIVATE_SLOT(d_func(), void _q_hostLookupFinished(QHostInfo))
diff --git a/src/network/access/qhttpnetworkconnectionchannel.cpp b/src/network/access/qhttpnetworkconnectionchannel.cpp
index 47081b29d2..98809e460b 100644
--- a/src/network/access/qhttpnetworkconnectionchannel.cpp
+++ b/src/network/access/qhttpnetworkconnectionchannel.cpp
@@ -48,7 +48,6 @@
#include <private/qhttp2protocolhandler_p.h>
#include <private/qhttpprotocolhandler_p.h>
-#include <private/qspdyprotocolhandler_p.h>
#include <private/http2protocol_p.h>
#ifndef QT_NO_SSL
@@ -931,7 +930,7 @@ void QHttpNetworkConnectionChannel::_q_connected()
} else if (connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2Direct) {
state = QHttpNetworkConnectionChannel::IdleState;
protocolHandler.reset(new QHttp2ProtocolHandler(this));
- if (spdyRequestsToSend.count() > 0) {
+ if (h2RequestsToSend.count() > 0) {
// In case our peer has sent us its settings (window size, max concurrent streams etc.)
// let's give _q_receiveReply a chance to read them first ('invokeMethod', QueuedConnection).
QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection);
@@ -1108,15 +1107,11 @@ void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socket
|| !connection->d_func()->lowPriorityQueue.isEmpty());
if (connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2
- || connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2Direct
-#ifndef QT_NO_SSL
- || connection->connectionType() == QHttpNetworkConnection::ConnectionTypeSPDY
-#endif
- ) {
- QList<HttpMessagePair> spdyPairs = spdyRequestsToSend.values();
- for (int a = 0; a < spdyPairs.count(); ++a) {
+ || connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2Direct) {
+ QList<HttpMessagePair> h2Pairs = h2RequestsToSend.values();
+ for (int a = 0; a < h2Pairs.count(); ++a) {
// emit error for all replies
- QHttpNetworkReply *currentReply = spdyPairs.at(a).second;
+ QHttpNetworkReply *currentReply = h2Pairs.at(a).second;
Q_ASSERT(currentReply);
emit currentReply->finishedWithError(errorCode, errorString);
}
@@ -1143,12 +1138,8 @@ void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socket
void QHttpNetworkConnectionChannel::_q_proxyAuthenticationRequired(const QNetworkProxy &proxy, QAuthenticator* auth)
{
if (connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2
- || connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2Direct
-#ifndef QT_NO_SSL
- || connection->connectionType() == QHttpNetworkConnection::ConnectionTypeSPDY
-#endif
- ) {
- if (spdyRequestsToSend.count() > 0)
+ || connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2Direct) {
+ if (h2RequestsToSend.count() > 0)
connection->d_func()->emitProxyAuthenticationRequired(this, proxy, auth);
} else { // HTTP
// Need to dequeue the request before we can emit the error.
@@ -1171,9 +1162,9 @@ void QHttpNetworkConnectionChannel::emitFinishedWithError(QNetworkReply::Network
{
if (reply)
emit reply->finishedWithError(error, QHttpNetworkConnectionChannel::tr(message));
- QList<HttpMessagePair> spdyPairs = spdyRequestsToSend.values();
- for (int a = 0; a < spdyPairs.count(); ++a) {
- QHttpNetworkReply *currentReply = spdyPairs.at(a).second;
+ QList<HttpMessagePair> h2Pairs = h2RequestsToSend.values();
+ for (int a = 0; a < h2Pairs.count(); ++a) {
+ QHttpNetworkReply *currentReply = h2Pairs.at(a).second;
Q_ASSERT(currentReply);
emit currentReply->finishedWithError(error, QHttpNetworkConnectionChannel::tr(message));
}
@@ -1195,12 +1186,6 @@ void QHttpNetworkConnectionChannel::_q_encrypted()
QByteArray nextProtocol = sslSocket->sslConfiguration().nextNegotiatedProtocol();
if (nextProtocol == QSslConfiguration::NextProtocolHttp1_1) {
// fall through to create a QHttpProtocolHandler
- } else if (nextProtocol == QSslConfiguration::NextProtocolSpdy3_0) {
- protocolHandler.reset(new QSpdyProtocolHandler(this));
- connection->setConnectionType(QHttpNetworkConnection::ConnectionTypeSPDY);
- // no need to re-queue requests, if SPDY was enabled on the request it
- // has gone to the SPDY queue already
- break;
} else if (nextProtocol == QSslConfiguration::ALPNProtocolHTTP2) {
switchedToHttp2 = true;
protocolHandler.reset(new QHttp2ProtocolHandler(this));
@@ -1229,8 +1214,6 @@ void QHttpNetworkConnectionChannel::_q_encrypted()
// it again on other channels that our connection can create/open.
if (connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2)
protocols.removeAll(QSslConfiguration::ALPNProtocolHTTP2);
- else if (connection->connectionType() == QHttpNetworkConnection::ConnectionTypeSPDY)
- protocols.removeAll(QSslConfiguration::NextProtocolSpdy3_0);
if (nProtocols > protocols.size()) {
sslConfiguration->setAllowedNextProtocols(protocols);
@@ -1240,13 +1223,13 @@ void QHttpNetworkConnectionChannel::_q_encrypted()
}
connection->setConnectionType(QHttpNetworkConnection::ConnectionTypeHTTP);
- // We use only one channel for SPDY or HTTP/2, but normally six for
+ // We use only one channel for HTTP/2, but normally six for
// HTTP/1.1 - let's restore this number to the reserved number of
// channels:
if (connection->d_func()->activeChannelCount < connection->d_func()->channelCount) {
connection->d_func()->activeChannelCount = connection->d_func()->channelCount;
- // re-queue requests from SPDY queue to HTTP queue, if any
- requeueSpdyRequests();
+ // re-queue requests from HTTP/2 queue to HTTP queue, if any
+ requeueHttp2Requests();
}
break;
}
@@ -1266,11 +1249,9 @@ void QHttpNetworkConnectionChannel::_q_encrypted()
state = QHttpNetworkConnectionChannel::IdleState;
pendingEncrypt = false;
- if (connection->connectionType() == QHttpNetworkConnection::ConnectionTypeSPDY ||
- connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2 ||
+ if (connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2 ||
connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2Direct) {
- // we call setSpdyWasUsed(true) on the replies in the SPDY handler when the request is sent
- if (spdyRequestsToSend.count() > 0) {
+ if (h2RequestsToSend.count() > 0) {
// In case our peer has sent us its settings (window size, max concurrent streams etc.)
// let's give _q_receiveReply a chance to read them first ('invokeMethod', QueuedConnection).
QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection);
@@ -1279,7 +1260,7 @@ void QHttpNetworkConnectionChannel::_q_encrypted()
if (!reply)
connection->d_func()->dequeueRequest(socket);
if (reply) {
- reply->setSpdyWasUsed(false);
+ reply->setHttp2WasUsed(false);
Q_ASSERT(reply->d_func()->connectionChannel == this);
emit reply->encrypted();
}
@@ -1288,13 +1269,12 @@ void QHttpNetworkConnectionChannel::_q_encrypted()
}
}
-void QHttpNetworkConnectionChannel::requeueSpdyRequests()
+void QHttpNetworkConnectionChannel::requeueHttp2Requests()
{
- QList<HttpMessagePair> spdyPairs = spdyRequestsToSend.values();
- for (int a = 0; a < spdyPairs.count(); ++a) {
- connection->d_func()->requeueRequest(spdyPairs.at(a));
- }
- spdyRequestsToSend.clear();
+ QList<HttpMessagePair> h2Pairs = h2RequestsToSend.values();
+ for (int a = 0; a < h2Pairs.count(); ++a)
+ connection->d_func()->requeueRequest(h2Pairs.at(a));
+ h2RequestsToSend.clear();
}
void QHttpNetworkConnectionChannel::_q_sslErrors(const QList<QSslError> &errors)
@@ -1312,11 +1292,11 @@ void QHttpNetworkConnectionChannel::_q_sslErrors(const QList<QSslError> &errors)
emit reply->sslErrors(errors);
}
#ifndef QT_NO_SSL
- else { // SPDY
- QList<HttpMessagePair> spdyPairs = spdyRequestsToSend.values();
- for (int a = 0; a < spdyPairs.count(); ++a) {
+ else { // HTTP/2
+ QList<HttpMessagePair> h2Pairs = h2RequestsToSend.values();
+ for (int a = 0; a < h2Pairs.count(); ++a) {
// emit SSL errors for all replies
- QHttpNetworkReply *currentReply = spdyPairs.at(a).second;
+ QHttpNetworkReply *currentReply = h2Pairs.at(a).second;
Q_ASSERT(currentReply);
emit currentReply->sslErrors(errors);
}
@@ -1336,10 +1316,10 @@ void QHttpNetworkConnectionChannel::_q_preSharedKeyAuthenticationRequired(QSslPr
if (reply)
emit reply->preSharedKeyAuthenticationRequired(authenticator);
} else {
- QList<HttpMessagePair> spdyPairs = spdyRequestsToSend.values();
- for (int a = 0; a < spdyPairs.count(); ++a) {
+ QList<HttpMessagePair> h2Pairs = h2RequestsToSend.values();
+ for (int a = 0; a < h2Pairs.count(); ++a) {
// emit SSL errors for all replies
- QHttpNetworkReply *currentReply = spdyPairs.at(a).second;
+ QHttpNetworkReply *currentReply = h2Pairs.at(a).second;
Q_ASSERT(currentReply);
emit currentReply->preSharedKeyAuthenticationRequired(authenticator);
}
diff --git a/src/network/access/qhttpnetworkconnectionchannel_p.h b/src/network/access/qhttpnetworkconnectionchannel_p.h
index 270b3eb9ba..44ad2d7959 100644
--- a/src/network/access/qhttpnetworkconnectionchannel_p.h
+++ b/src/network/access/qhttpnetworkconnectionchannel_p.h
@@ -123,10 +123,7 @@ public:
bool authenticationCredentialsSent;
bool proxyCredentialsSent;
QScopedPointer<QAbstractProtocolHandler> protocolHandler;
- // SPDY or HTTP/2 requests; SPDY is TLS-only, but
- // HTTP/2 can be cleartext also, that's why it's
- // outside of QT_NO_SSL section. Sorted by priority:
- QMultiMap<int, HttpMessagePair> spdyRequestsToSend;
+ QMultiMap<int, HttpMessagePair> h2RequestsToSend;
bool switchedToHttp2 = false;
#ifndef QT_NO_SSL
bool ignoreAllSslErrors;
@@ -135,7 +132,7 @@ public:
void ignoreSslErrors();
void ignoreSslErrors(const QList<QSslError> &errors);
void setSslConfiguration(const QSslConfiguration &config);
- void requeueSpdyRequests(); // when we wanted SPDY but got HTTP
+ void requeueHttp2Requests(); // when we wanted HTTP/2 but got HTTP/1.1
#endif
// to emit the signal for all in-flight replies:
void emitFinishedWithError(QNetworkReply::NetworkError error, const char *message);
diff --git a/src/network/access/qhttpnetworkreply.cpp b/src/network/access/qhttpnetworkreply.cpp
index af456c3607..1ba52ac6d6 100644
--- a/src/network/access/qhttpnetworkreply.cpp
+++ b/src/network/access/qhttpnetworkreply.cpp
@@ -287,14 +287,14 @@ bool QHttpNetworkReply::isPipeliningUsed() const
return d_func()->pipeliningUsed;
}
-bool QHttpNetworkReply::isSpdyUsed() const
+bool QHttpNetworkReply::isHttp2Used() const
{
- return d_func()->spdyUsed;
+ return d_func()->h2Used;
}
-void QHttpNetworkReply::setSpdyWasUsed(bool spdy)
+void QHttpNetworkReply::setHttp2WasUsed(bool h2)
{
- d_func()->spdyUsed = spdy;
+ d_func()->h2Used = h2;
}
qint64 QHttpNetworkReply::removedContentLength() const
@@ -324,15 +324,11 @@ QHttpNetworkReplyPrivate::QHttpNetworkReplyPrivate(const QUrl &newUrl)
forceConnectionCloseEnabled(false),
lastChunkRead(false),
currentChunkSize(0), currentChunkRead(0), readBufferMaxSize(0),
- windowSizeDownload(65536), // 64K initial window size according to SPDY standard
- windowSizeUpload(65536), // 64K initial window size according to SPDY standard
- currentlyReceivedDataInWindow(0),
- currentlyUploadedDataInWindow(0),
totallyUploadedData(0),
removedContentLength(-1),
connection(nullptr),
autoDecompress(false), responseData(), requestIsPrepared(false)
- ,pipeliningUsed(false), spdyUsed(false), downstreamLimited(false)
+ ,pipeliningUsed(false), h2Used(false), downstreamLimited(false)
,userProvidedDownloadBuffer(nullptr)
#ifndef QT_NO_COMPRESS
,inflateStrm(nullptr)
diff --git a/src/network/access/qhttpnetworkreply_p.h b/src/network/access/qhttpnetworkreply_p.h
index 12cfe359aa..82128f656e 100644
--- a/src/network/access/qhttpnetworkreply_p.h
+++ b/src/network/access/qhttpnetworkreply_p.h
@@ -137,8 +137,8 @@ public:
bool isFinished() const;
bool isPipeliningUsed() const;
- bool isSpdyUsed() const;
- void setSpdyWasUsed(bool spdy);
+ bool isHttp2Used() const;
+ void setHttp2WasUsed(bool h2Used);
qint64 removedContentLength() const;
bool isRedirecting() const;
@@ -251,11 +251,7 @@ public:
qint64 currentChunkSize;
qint64 currentChunkRead;
qint64 readBufferMaxSize;
- qint32 windowSizeDownload; // only for SPDY
- qint32 windowSizeUpload; // only for SPDY
- qint32 currentlyReceivedDataInWindow; // only for SPDY
- qint32 currentlyUploadedDataInWindow; // only for SPDY
- qint64 totallyUploadedData; // only for SPDY
+ qint64 totallyUploadedData; // HTTP/2
qint64 removedContentLength;
QPointer<QHttpNetworkConnection> connection;
QPointer<QHttpNetworkConnectionChannel> connectionChannel;
@@ -267,7 +263,7 @@ public:
bool requestIsPrepared;
bool pipeliningUsed;
- bool spdyUsed;
+ bool h2Used;
bool downstreamLimited;
char* userProvidedDownloadBuffer;
diff --git a/src/network/access/qhttpnetworkrequest.cpp b/src/network/access/qhttpnetworkrequest.cpp
index 5fb8885bdf..0b03e6e69e 100644
--- a/src/network/access/qhttpnetworkrequest.cpp
+++ b/src/network/access/qhttpnetworkrequest.cpp
@@ -45,7 +45,7 @@ QT_BEGIN_NAMESPACE
QHttpNetworkRequestPrivate::QHttpNetworkRequestPrivate(QHttpNetworkRequest::Operation op,
QHttpNetworkRequest::Priority pri, const QUrl &newUrl)
: QHttpNetworkHeaderPrivate(newUrl), operation(op), priority(pri), uploadByteDevice(nullptr),
- autoDecompress(false), pipeliningAllowed(false), spdyAllowed(false), http2Allowed(false),
+ autoDecompress(false), pipeliningAllowed(false), http2Allowed(false),
http2Direct(false), withCredentials(true), preConnect(false), redirectCount(0),
redirectPolicy(QNetworkRequest::ManualRedirectPolicy)
{
@@ -59,7 +59,6 @@ QHttpNetworkRequestPrivate::QHttpNetworkRequestPrivate(const QHttpNetworkRequest
uploadByteDevice(other.uploadByteDevice),
autoDecompress(other.autoDecompress),
pipeliningAllowed(other.pipeliningAllowed),
- spdyAllowed(other.spdyAllowed),
http2Allowed(other.http2Allowed),
http2Direct(other.http2Direct),
withCredentials(other.withCredentials),
@@ -83,7 +82,6 @@ bool QHttpNetworkRequestPrivate::operator==(const QHttpNetworkRequestPrivate &ot
&& (uploadByteDevice == other.uploadByteDevice)
&& (autoDecompress == other.autoDecompress)
&& (pipeliningAllowed == other.pipeliningAllowed)
- && (spdyAllowed == other.spdyAllowed)
&& (http2Allowed == other.http2Allowed)
&& (http2Direct == other.http2Direct)
// we do not clear the customVerb in setOperation
@@ -339,16 +337,6 @@ void QHttpNetworkRequest::setPipeliningAllowed(bool b)
d->pipeliningAllowed = b;
}
-bool QHttpNetworkRequest::isSPDYAllowed() const
-{
- return d->spdyAllowed;
-}
-
-void QHttpNetworkRequest::setSPDYAllowed(bool b)
-{
- d->spdyAllowed = b;
-}
-
bool QHttpNetworkRequest::isHTTP2Allowed() const
{
return d->http2Allowed;
diff --git a/src/network/access/qhttpnetworkrequest_p.h b/src/network/access/qhttpnetworkrequest_p.h
index fb4896195b..f263e348ef 100644
--- a/src/network/access/qhttpnetworkrequest_p.h
+++ b/src/network/access/qhttpnetworkrequest_p.h
@@ -116,9 +116,6 @@ public:
bool isPipeliningAllowed() const;
void setPipeliningAllowed(bool b);
- bool isSPDYAllowed() const;
- void setSPDYAllowed(bool b);
-
bool isHTTP2Allowed() const;
void setHTTP2Allowed(bool b);
@@ -176,7 +173,6 @@ public:
mutable QNonContiguousByteDevice* uploadByteDevice;
bool autoDecompress;
bool pipeliningAllowed;
- bool spdyAllowed;
bool http2Allowed;
bool http2Direct;
bool withCredentials;
diff --git a/src/network/access/qhttpthreaddelegate.cpp b/src/network/access/qhttpthreaddelegate.cpp
index f3125a3a95..6322c773ac 100644
--- a/src/network/access/qhttpthreaddelegate.cpp
+++ b/src/network/access/qhttpthreaddelegate.cpp
@@ -236,7 +236,7 @@ QHttpThreadDelegate::QHttpThreadDelegate(QObject *parent) :
, synchronous(false)
, incomingStatusCode(0)
, isPipeliningUsed(false)
- , isSpdyUsed(false)
+ , isHttp2Used(false)
, incomingContentLength(-1)
, removedContentLength(-1)
, incomingErrorCode(QNetworkReply::NoError)
@@ -320,17 +320,6 @@ void QHttpThreadDelegate::startRequest()
}
}
-#ifndef QT_NO_SSL
- if (!isH2 && httpRequest.isSPDYAllowed() && ssl) {
- connectionType = QHttpNetworkConnection::ConnectionTypeSPDY;
- urlCopy.setScheme(QStringLiteral("spdy")); // to differentiate SPDY requests from HTTPS requests
- QList<QByteArray> nextProtocols;
- nextProtocols << QSslConfiguration::NextProtocolSpdy3_0
- << QSslConfiguration::NextProtocolHttp1_1;
- incomingSslConfiguration->setAllowedNextProtocols(nextProtocols);
- }
-#endif // QT_NO_SSL
-
#ifndef QT_NO_NETWORKPROXY
if (transparentProxy.type() != QNetworkProxy::NoProxy)
cacheKey = makeCacheKey(urlCopy, &transparentProxy, httpRequest.peerVerifyName());
@@ -652,7 +641,7 @@ void QHttpThreadDelegate::headerChangedSlot()
isPipeliningUsed = httpReply->isPipeliningUsed();
incomingContentLength = httpReply->contentLength();
removedContentLength = httpReply->removedContentLength();
- isSpdyUsed = httpReply->isSpdyUsed();
+ isHttp2Used = httpReply->isHttp2Used();
emit downloadMetaData(incomingHeaders,
incomingStatusCode,
@@ -661,7 +650,7 @@ void QHttpThreadDelegate::headerChangedSlot()
downloadBuffer,
incomingContentLength,
removedContentLength,
- isSpdyUsed);
+ isHttp2Used);
}
void QHttpThreadDelegate::synchronousHeaderChangedSlot()
@@ -677,7 +666,7 @@ void QHttpThreadDelegate::synchronousHeaderChangedSlot()
incomingStatusCode = httpReply->statusCode();
incomingReasonPhrase = httpReply->reasonPhrase();
isPipeliningUsed = httpReply->isPipeliningUsed();
- isSpdyUsed = httpReply->isSpdyUsed();
+ isHttp2Used = httpReply->isHttp2Used();
incomingContentLength = httpReply->contentLength();
}
diff --git a/src/network/access/qhttpthreaddelegate_p.h b/src/network/access/qhttpthreaddelegate_p.h
index 355d1afc30..208b2cb149 100644
--- a/src/network/access/qhttpthreaddelegate_p.h
+++ b/src/network/access/qhttpthreaddelegate_p.h
@@ -112,7 +112,7 @@ public:
int incomingStatusCode;
QString incomingReasonPhrase;
bool isPipeliningUsed;
- bool isSpdyUsed;
+ bool isHttp2Used;
qint64 incomingContentLength;
qint64 removedContentLength;
QNetworkReply::NetworkError incomingErrorCode;
diff --git a/src/network/access/qnetworkaccessmanager.cpp b/src/network/access/qnetworkaccessmanager.cpp
index ff916ff283..68bd107a83 100644
--- a/src/network/access/qnetworkaccessmanager.cpp
+++ b/src/network/access/qnetworkaccessmanager.cpp
@@ -1237,12 +1237,10 @@ void QNetworkAccessManager::connectToHostEncrypted(const QString &hostName, quin
if (sslConfiguration != QSslConfiguration::defaultConfiguration())
request.setSslConfiguration(sslConfiguration);
- // There is no way to enable SPDY/HTTP2 via a request, so we need to check
- // the ssl configuration whether SPDY/HTTP2 is allowed here.
+ // There is no way to enable HTTP2 via a request, so we need to check
+ // the ssl configuration whether HTTP2 is allowed here.
if (sslConfiguration.allowedNextProtocols().contains(QSslConfiguration::ALPNProtocolHTTP2))
request.setAttribute(QNetworkRequest::Http2AllowedAttribute, true);
- else if (sslConfiguration.allowedNextProtocols().contains(QSslConfiguration::NextProtocolSpdy3_0))
- request.setAttribute(QNetworkRequest::SpdyAllowedAttribute, true);
request.setPeerVerifyName(peerName);
get(request);
diff --git a/src/network/access/qnetworkaccessmanager.h b/src/network/access/qnetworkaccessmanager.h
index aa4765a043..a883bf93fb 100644
--- a/src/network/access/qnetworkaccessmanager.h
+++ b/src/network/access/qnetworkaccessmanager.h
@@ -56,7 +56,6 @@ class QIODevice;
class QAbstractNetworkCache;
class QAuthenticator;
class QByteArray;
-template<typename T> class QList;
class QNetworkCookie;
class QNetworkCookieJar;
class QNetworkReply;
diff --git a/src/network/access/qnetworkreplyhttpimpl.cpp b/src/network/access/qnetworkreplyhttpimpl.cpp
index 5a775142b0..002d9ec5d1 100644
--- a/src/network/access/qnetworkreplyhttpimpl.cpp
+++ b/src/network/access/qnetworkreplyhttpimpl.cpp
@@ -775,9 +775,6 @@ void QNetworkReplyHttpImplPrivate::postRequest(const QNetworkRequest &newHttpReq
if (newHttpRequest.attribute(QNetworkRequest::HttpPipeliningAllowedAttribute).toBool())
httpRequest.setPipeliningAllowed(true);
- if (request.attribute(QNetworkRequest::SpdyAllowedAttribute).toBool())
- httpRequest.setSPDYAllowed(true);
-
if (request.attribute(QNetworkRequest::Http2AllowedAttribute).toBool())
httpRequest.setHTTP2Allowed(true);
@@ -969,7 +966,7 @@ void QNetworkReplyHttpImplPrivate::postRequest(const QNetworkRequest &newHttpReq
QSharedPointer<char>(),
delegate->incomingContentLength,
delegate->removedContentLength,
- delegate->isSpdyUsed);
+ delegate->isHttp2Used);
replyDownloadData(delegate->synchronousDownloadData);
httpError(delegate->incomingErrorCode, delegate->incomingErrorDetail);
} else {
@@ -981,7 +978,7 @@ void QNetworkReplyHttpImplPrivate::postRequest(const QNetworkRequest &newHttpReq
QSharedPointer<char>(),
delegate->incomingContentLength,
delegate->removedContentLength,
- delegate->isSpdyUsed);
+ delegate->isHttp2Used);
replyDownloadData(delegate->synchronousDownloadData);
}
@@ -1256,7 +1253,7 @@ void QNetworkReplyHttpImplPrivate::replyDownloadMetaData(const QList<QPair<QByte
QSharedPointer<char> db,
qint64 contentLength,
qint64 removedContentLength,
- bool spdyWasUsed)
+ bool h2Used)
{
Q_Q(QNetworkReplyHttpImpl);
Q_UNUSED(contentLength);
@@ -1282,16 +1279,7 @@ void QNetworkReplyHttpImplPrivate::replyDownloadMetaData(const QList<QPair<QByte
}
q->setAttribute(QNetworkRequest::HttpPipeliningWasUsedAttribute, pu);
- const QVariant http2Allowed = request.attribute(QNetworkRequest::Http2AllowedAttribute);
- const QVariant http2Direct = request.attribute(QNetworkRequest::Http2DirectAttribute);
- if ((http2Allowed.isValid() && http2Allowed.toBool())
- || (http2Direct.isValid() && http2Direct.toBool())) {
- q->setAttribute(QNetworkRequest::Http2WasUsedAttribute, spdyWasUsed);
- q->setAttribute(QNetworkRequest::SpdyWasUsedAttribute, false);
- } else {
- q->setAttribute(QNetworkRequest::SpdyWasUsedAttribute, spdyWasUsed);
- q->setAttribute(QNetworkRequest::Http2WasUsedAttribute, false);
- }
+ q->setAttribute(QNetworkRequest::Http2WasUsedAttribute, h2Used);
// reconstruct the HTTP header
QList<QPair<QByteArray, QByteArray> > headerMap = hm;
diff --git a/src/network/access/qnetworkrequest.cpp b/src/network/access/qnetworkrequest.cpp
index 70b09dba22..473aa42e1e 100644
--- a/src/network/access/qnetworkrequest.cpp
+++ b/src/network/access/qnetworkrequest.cpp
@@ -272,18 +272,6 @@ QT_BEGIN_NAMESPACE
The QNetworkSession ConnectInBackground property will be set according to
this attribute.
- \value SpdyAllowedAttribute
- Requests only, type: QMetaType::Bool (default: false)
- Indicates whether the QNetworkAccessManager code is
- allowed to use SPDY with this request. This applies only
- to SSL requests, and depends on the server supporting SPDY.
- Obsolete, use Http2 instead of Spdy.
-
- \value SpdyWasUsedAttribute
- Replies only, type: QMetaType::Bool
- Indicates whether SPDY was used for receiving
- this reply. Obsolete, use Http2 instead of Spdy.
-
\value Http2AllowedAttribute
Requests only, type: QMetaType::Bool (default: false)
Indicates whether the QNetworkAccessManager code is
@@ -295,12 +283,6 @@ QT_BEGIN_NAMESPACE
Indicates whether HTTP/2 was used for receiving this reply.
(This value was introduced in 5.9.)
- \value HTTP2AllowedAttribute
- Obsolete alias for Http2AllowedAttribute.
-
- \value HTTP2WasUsedAttribute
- Obsolete alias for Http2WasUsedAttribute.
-
\value EmitAllUploadProgressSignalsAttribute
Requests only, type: QMetaType::Bool (default: false)
Indicates whether all upload signals should be emitted.
diff --git a/src/network/access/qnetworkrequest.h b/src/network/access/qnetworkrequest.h
index dcd2c6b61f..cb15ca5aa5 100644
--- a/src/network/access/qnetworkrequest.h
+++ b/src/network/access/qnetworkrequest.h
@@ -89,18 +89,10 @@ public:
DownloadBufferAttribute, // internal
SynchronousRequestAttribute, // internal
BackgroundRequestAttribute,
-#if QT_DEPRECATED_SINCE(5, 15)
- SpdyAllowedAttribute,
- SpdyWasUsedAttribute,
-#endif // QT_DEPRECATED_SINCE(5, 15)
EmitAllUploadProgressSignalsAttribute = BackgroundRequestAttribute + 3,
FollowRedirectsAttribute,
Http2AllowedAttribute,
Http2WasUsedAttribute,
-#if QT_DEPRECATED_SINCE(5, 15)
- HTTP2AllowedAttribute Q_DECL_ENUMERATOR_DEPRECATED_X("Use Http2AllowedAttribute") = Http2AllowedAttribute,
- HTTP2WasUsedAttribute Q_DECL_ENUMERATOR_DEPRECATED_X("Use Http2WasUsedAttribute"),
-#endif // QT_DEPRECATED_SINCE(5, 15)
OriginalContentLengthAttribute,
RedirectPolicyAttribute,
Http2DirectAttribute,
diff --git a/src/network/access/qspdyprotocolhandler_p.h b/src/network/access/qspdyprotocolhandler_p.h
deleted file mode 100644
index 14e2ff388a..0000000000
--- a/src/network/access/qspdyprotocolhandler_p.h
+++ /dev/null
@@ -1,232 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2014 BlackBerry Limited. All rights reserved.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QSPDYPROTOCOLHANDLER_H
-#define QSPDYPROTOCOLHANDLER_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists for the convenience
-// of the Network Access API. This header file may change from
-// version to version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <QtNetwork/private/qtnetworkglobal_p.h>
-#include <private/qabstractprotocolhandler_p.h>
-#include <QtNetwork/qnetworkreply.h>
-#include <private/qbytedata_p.h>
-
-#include <zlib.h>
-
-QT_REQUIRE_CONFIG(http);
-
-#if !defined(QT_NO_SSL)
-
-QT_BEGIN_NAMESPACE
-
-class QHttpNetworkRequest;
-
-#ifndef HttpMessagePair
-typedef QPair<QHttpNetworkRequest, QHttpNetworkReply*> HttpMessagePair;
-#endif
-
-class QSpdyProtocolHandler : public QObject, public QAbstractProtocolHandler {
- Q_OBJECT
-public:
- QSpdyProtocolHandler(QHttpNetworkConnectionChannel *channel);
- ~QSpdyProtocolHandler();
-
- enum DataFrameFlag {
- DataFrame_FLAG_FIN = 0x01,
- DataFrame_FLAG_COMPRESS = 0x02
- };
-
- Q_DECLARE_FLAGS(DataFrameFlags, DataFrameFlag)
-
- enum ControlFrameFlag {
- ControlFrame_FLAG_FIN = 0x01,
- ControlFrame_FLAG_UNIDIRECTIONAL = 0x02
- };
-
- Q_DECLARE_FLAGS(ControlFrameFlags, ControlFrameFlag)
-
- enum SETTINGS_Flag {
- FLAG_SETTINGS_CLEAR_SETTINGS = 0x01
- };
-
- Q_DECLARE_FLAGS(SETTINGS_Flags, SETTINGS_Flag)
-
- enum SETTINGS_ID_Flag {
- FLAG_SETTINGS_PERSIST_VALUE = 0x01,
- FLAG_SETTINGS_PERSISTED = 0x02
- };
-
- Q_DECLARE_FLAGS(SETTINGS_ID_Flags, SETTINGS_ID_Flag)
-
- virtual void _q_receiveReply() override;
- virtual void _q_readyRead() override;
- virtual bool sendRequest() override;
-
-private slots:
- void _q_uploadDataReadyRead();
- void _q_replyDestroyed(QObject*);
- void _q_uploadDataDestroyed(QObject *);
-
-private:
-
- enum FrameType {
- FrameType_SYN_STREAM = 1,
- FrameType_SYN_REPLY = 2,
- FrameType_RST_STREAM = 3,
- FrameType_SETTINGS = 4,
- FrameType_PING = 6,
- FrameType_GOAWAY = 7,
- FrameType_HEADERS = 8,
- FrameType_WINDOW_UPDATE = 9,
- FrameType_CREDENTIAL // has a special type
- };
-
- enum StatusCode {
- StatusCode_PROTOCOL_ERROR = 1,
- StatusCode_INVALID_STREAM = 2,
- StatusCode_REFUSED_STREAM = 3,
- StatusCode_UNSUPPORTED_VERSION = 4,
- StatusCode_CANCEL = 5,
- StatusCode_INTERNAL_ERROR = 6,
- StatusCode_FLOW_CONTROL_ERROR = 7,
- StatusCode_STREAM_IN_USE = 8,
- StatusCode_STREAM_ALREADY_CLOSED = 9,
- StatusCode_INVALID_CREDENTIALS = 10,
- StatusCode_FRAME_TOO_LARGE = 11
- };
-
- enum SETTINGS_ID {
- SETTINGS_UPLOAD_BANDWIDTH = 1,
- SETTINGS_DOWNLOAD_BANDWIDTH = 2,
- SETTINGS_ROUND_TRIP_TIME = 3,
- SETTINGS_MAX_CONCURRENT_STREAMS = 4,
- SETTINGS_CURRENT_CWND = 5,
- SETTINGS_DOWNLOAD_RETRANS_RATE = 6,
- SETTINGS_INITIAL_WINDOW_SIZE = 7,
- SETTINGS_CLIENT_CERTIFICATE_VECTOR_SIZE = 8
- };
-
- enum GOAWAY_STATUS {
- GOAWAY_OK = 0,
- GOAWAY_PROTOCOL_ERROR = 1,
- GOAWAY_INTERNAL_ERROR = 11
- };
-
- enum RST_STREAM_STATUS_CODE {
- RST_STREAM_PROTOCOL_ERROR = 1,
- RST_STREAM_INVALID_STREAM = 2,
- RST_STREAM_REFUSED_STREAM = 3,
- RST_STREAM_UNSUPPORTED_VERSION = 4,
- RST_STREAM_CANCEL = 5,
- RST_STREAM_INTERNAL_ERROR = 6,
- RST_STREAM_FLOW_CONTROL_ERROR = 7,
- RST_STREAM_STREAM_IN_USE = 8,
- RST_STREAM_STREAM_ALREADY_CLOSED = 9,
- RST_STREAM_INVALID_CREDENTIALS = 10,
- RST_STREAM_FRAME_TOO_LARGE = 11
- };
-
- quint64 bytesAvailable() const;
- bool readNextChunk(qint64 length, char *sink);
-
- void sendControlFrame(FrameType type, ControlFrameFlags flags, const char *data, quint32 length);
-
- void sendSYN_STREAM(const HttpMessagePair &pair, qint32 streamID,
- qint32 associatedToStreamID);
- void sendRST_STREAM(qint32 streamID, RST_STREAM_STATUS_CODE statusCode);
- void sendPING(quint32 pingID);
-
- bool uploadData(qint32 streamID);
- Q_INVOKABLE void sendWINDOW_UPDATE(qint32 streamID, quint32 deltaWindowSize);
-
- qint64 sendDataFrame(qint32 streamID, DataFrameFlags flags, quint32 length,
- const char *data);
-
- QByteArray composeHeader(const QHttpNetworkRequest &request);
- bool uncompressHeader(const QByteArray &input, QByteArray *output);
-
- void handleControlFrame(const QByteArray &frameHeaders);
- void handleDataFrame(const QByteArray &frameHeaders);
-
- void handleSYN_STREAM(char, quint32, const QByteArray &frameData);
- void handleSYN_REPLY(char flags, quint32, const QByteArray &frameData);
- void handleRST_STREAM(char flags, quint32 length, const QByteArray &frameData);
- void handleSETTINGS(char flags, quint32 length, const QByteArray &frameData);
- void handlePING(char, quint32 length, const QByteArray &frameData);
- void handleGOAWAY(char flags, quint32, const QByteArray &frameData);
- void handleHEADERS(char flags, quint32, const QByteArray &frameData);
- void handleWINDOW_UPDATE(char, quint32, const QByteArray &frameData);
-
- qint32 generateNextStreamID();
- void parseHttpHeaders(char flags, const QByteArray &frameData);
-
- void replyFinished(QHttpNetworkReply *httpReply, qint32 streamID);
- void replyFinishedWithError(QHttpNetworkReply *httpReply, qint32 streamID,
- QNetworkReply::NetworkError errorCode, const char *errorMessage);
-
- qint32 m_nextStreamID;
- QHash<quint32, HttpMessagePair> m_inFlightStreams;
- qint32 m_maxConcurrentStreams;
- quint32 m_initialWindowSize;
- QByteDataBuffer m_spdyBuffer;
- bool m_waitingForCompleteStream;
- z_stream m_deflateStream;
- z_stream m_inflateStream;
- QHash<QObject *, qint32> m_streamIDs;
-};
-
-Q_DECLARE_OPERATORS_FOR_FLAGS(QSpdyProtocolHandler::DataFrameFlags)
-Q_DECLARE_OPERATORS_FOR_FLAGS(QSpdyProtocolHandler::ControlFrameFlags)
-Q_DECLARE_OPERATORS_FOR_FLAGS(QSpdyProtocolHandler::SETTINGS_Flags)
-Q_DECLARE_OPERATORS_FOR_FLAGS(QSpdyProtocolHandler::SETTINGS_ID_Flags)
-
-QT_END_NAMESPACE
-
-#endif // !defined(QT_NO_SSL)
-
-#endif // QSPDYPROTOCOLHANDLER_H
diff --git a/src/network/bearer/bearer.pri b/src/network/bearer/bearer.pri
index d58d5ec168..bcb7a5971e 100644
--- a/src/network/bearer/bearer.pri
+++ b/src/network/bearer/bearer.pri
@@ -6,11 +6,14 @@ HEADERS += bearer/qnetworkconfiguration.h \
bearer/qnetworkconfigmanager_p.h \
bearer/qnetworkconfiguration_p.h \
bearer/qnetworksession_p.h \
+ bearer/qnetworksession_impl_p.h \
bearer/qbearerengine_p.h \
+ bearer/qbearerengine_impl_p.h \
bearer/qbearerplugin_p.h \
bearer/qsharednetworksession_p.h
SOURCES += bearer/qnetworksession.cpp \
+ bearer/qnetworksession_impl.cpp \
bearer/qnetworkconfigmanager.cpp \
bearer/qnetworkconfiguration.cpp \
bearer/qnetworkconfigmanager_p.cpp \
diff --git a/src/network/bearer/qbearerengine_impl_p.h b/src/network/bearer/qbearerengine_impl_p.h
new file mode 100644
index 0000000000..4221b73276
--- /dev/null
+++ b/src/network/bearer/qbearerengine_impl_p.h
@@ -0,0 +1,85 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QBEARERENGINE_IMPL_H
+#define QBEARERENGINE_IMPL_H
+
+#include <QtNetwork/private/qbearerengine_p.h>
+
+#ifndef QT_NO_BEARERMANAGEMENT
+
+QT_BEGIN_NAMESPACE
+
+class Q_NETWORK_EXPORT QBearerEngineImpl : public QBearerEngine
+{
+ Q_OBJECT
+
+public:
+ enum ConnectionError {
+ InterfaceLookupError = 0,
+ ConnectError,
+ OperationNotSupported,
+ DisconnectionError,
+ };
+
+ QBearerEngineImpl(QObject *parent = nullptr) : QBearerEngine(parent) {}
+ ~QBearerEngineImpl() {}
+
+ virtual void connectToId(const QString &id) = 0;
+ virtual void disconnectFromId(const QString &id) = 0;
+
+ virtual QString getInterfaceFromId(const QString &id) = 0;
+
+ virtual QNetworkSession::State sessionStateForId(const QString &id) = 0;
+
+ virtual quint64 bytesWritten(const QString &) { return Q_UINT64_C(0); }
+ virtual quint64 bytesReceived(const QString &) { return Q_UINT64_C(0); }
+ virtual quint64 startTime(const QString &) { return Q_UINT64_C(0); }
+
+Q_SIGNALS:
+ void connectionError(const QString &id, QBearerEngineImpl::ConnectionError error);
+};
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(QBearerEngineImpl::ConnectionError)
+
+#endif // QT_NO_BEARERMANAGEMENT
+
+#endif // QBEARERENGINE_IMPL_H
diff --git a/src/network/bearer/qnetworksession_impl.cpp b/src/network/bearer/qnetworksession_impl.cpp
new file mode 100644
index 0000000000..45a00b45fd
--- /dev/null
+++ b/src/network/bearer/qnetworksession_impl.cpp
@@ -0,0 +1,439 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// see comment in ../platformdefs_win.h.
+#define WIN32_LEAN_AND_MEAN 1
+
+#include "qnetworksession_impl_p.h"
+#include "qbearerengine_impl_p.h"
+
+#include <QtNetwork/qnetworksession.h>
+#include <QtNetwork/private/qnetworkconfigmanager_p.h>
+
+#include <QtCore/qdatetime.h>
+#include <QtCore/qdebug.h>
+#include <QtCore/qmutex.h>
+#include <QtCore/qstringlist.h>
+
+#ifndef QT_NO_BEARERMANAGEMENT
+
+QT_BEGIN_NAMESPACE
+
+static QBearerEngineImpl *getEngineFromId(const QString &id)
+{
+ QNetworkConfigurationManagerPrivate *priv = qNetworkConfigurationManagerPrivate();
+ if (priv) {
+ const auto engines = priv->engines();
+ for (QBearerEngine *engine : engines) {
+ QBearerEngineImpl *engineImpl = qobject_cast<QBearerEngineImpl *>(engine);
+ if (engineImpl && engineImpl->hasIdentifier(id))
+ return engineImpl;
+ }
+ }
+
+ return nullptr;
+}
+
+class QNetworkSessionManagerPrivate : public QObject
+{
+ Q_OBJECT
+
+public:
+ QNetworkSessionManagerPrivate(QObject *parent = nullptr) : QObject(parent) {}
+ ~QNetworkSessionManagerPrivate() {}
+
+ inline void forceSessionClose(const QNetworkConfiguration &config)
+ { emit forcedSessionClose(config); }
+
+Q_SIGNALS:
+ void forcedSessionClose(const QNetworkConfiguration &config);
+};
+
+Q_GLOBAL_STATIC(QNetworkSessionManagerPrivate, sessionManager);
+
+void QNetworkSessionPrivateImpl::syncStateWithInterface()
+{
+ connect(sessionManager(), SIGNAL(forcedSessionClose(QNetworkConfiguration)),
+ this, SLOT(forcedSessionClose(QNetworkConfiguration)));
+
+ opened = false;
+ isOpen = false;
+ state = QNetworkSession::Invalid;
+ lastError = QNetworkSession::UnknownSessionError;
+
+ qRegisterMetaType<QBearerEngineImpl::ConnectionError>();
+
+ switch (publicConfig.type()) {
+ case QNetworkConfiguration::InternetAccessPoint:
+ activeConfig = publicConfig;
+ engine = getEngineFromId(activeConfig.identifier());
+ if (engine) {
+ qRegisterMetaType<QNetworkConfigurationPrivatePointer>();
+ connect(engine, SIGNAL(configurationChanged(QNetworkConfigurationPrivatePointer)),
+ this, SLOT(configurationChanged(QNetworkConfigurationPrivatePointer)),
+ Qt::QueuedConnection);
+ connect(engine, SIGNAL(connectionError(QString,QBearerEngineImpl::ConnectionError)),
+ this, SLOT(connectionError(QString,QBearerEngineImpl::ConnectionError)),
+ Qt::QueuedConnection);
+ }
+ break;
+ case QNetworkConfiguration::ServiceNetwork:
+ serviceConfig = publicConfig;
+ // Defer setting engine and signals until open().
+ Q_FALLTHROUGH();
+ case QNetworkConfiguration::UserChoice:
+ // Defer setting serviceConfig and activeConfig until open().
+ Q_FALLTHROUGH();
+ default:
+ engine = nullptr;
+ }
+
+ networkConfigurationsChanged();
+}
+
+void QNetworkSessionPrivateImpl::open()
+{
+ if (serviceConfig.isValid()) {
+ lastError = QNetworkSession::OperationNotSupportedError;
+ emit QNetworkSessionPrivate::error(lastError);
+ } else if (!isOpen) {
+ if ((activeConfig.state() & QNetworkConfiguration::Discovered) != QNetworkConfiguration::Discovered) {
+ lastError = QNetworkSession::InvalidConfigurationError;
+ state = QNetworkSession::Invalid;
+ emit stateChanged(state);
+ emit QNetworkSessionPrivate::error(lastError);
+ return;
+ }
+ opened = true;
+
+ if ((activeConfig.state() & QNetworkConfiguration::Active) != QNetworkConfiguration::Active &&
+ (activeConfig.state() & QNetworkConfiguration::Discovered) == QNetworkConfiguration::Discovered) {
+ state = QNetworkSession::Connecting;
+ emit stateChanged(state);
+
+ engine->connectToId(activeConfig.identifier());
+ }
+
+ isOpen = (activeConfig.state() & QNetworkConfiguration::Active) == QNetworkConfiguration::Active;
+ if (isOpen)
+ emit quitPendingWaitsForOpened();
+ }
+}
+
+void QNetworkSessionPrivateImpl::close()
+{
+ if (serviceConfig.isValid()) {
+ lastError = QNetworkSession::OperationNotSupportedError;
+ emit QNetworkSessionPrivate::error(lastError);
+ } else if (isOpen) {
+ opened = false;
+ isOpen = false;
+ emit closed();
+ }
+}
+
+void QNetworkSessionPrivateImpl::stop()
+{
+ if (serviceConfig.isValid()) {
+ lastError = QNetworkSession::OperationNotSupportedError;
+ emit QNetworkSessionPrivate::error(lastError);
+ } else {
+ if ((activeConfig.state() & QNetworkConfiguration::Active) == QNetworkConfiguration::Active) {
+ state = QNetworkSession::Closing;
+ emit stateChanged(state);
+
+ engine->disconnectFromId(activeConfig.identifier());
+
+ sessionManager()->forceSessionClose(activeConfig);
+ }
+
+ opened = false;
+ isOpen = false;
+ emit closed();
+ }
+}
+
+void QNetworkSessionPrivateImpl::migrate()
+{
+}
+
+void QNetworkSessionPrivateImpl::accept()
+{
+}
+
+void QNetworkSessionPrivateImpl::ignore()
+{
+}
+
+void QNetworkSessionPrivateImpl::reject()
+{
+}
+
+#ifndef QT_NO_NETWORKINTERFACE
+QNetworkInterface QNetworkSessionPrivateImpl::currentInterface() const
+{
+ if (!engine || state != QNetworkSession::Connected || !publicConfig.isValid())
+ return QNetworkInterface();
+
+ QString iface = engine->getInterfaceFromId(activeConfig.identifier());
+ if (iface.isEmpty())
+ return QNetworkInterface();
+ return QNetworkInterface::interfaceFromName(iface);
+}
+#endif
+
+QVariant QNetworkSessionPrivateImpl::sessionProperty(const QString &key) const
+{
+ if (key == QLatin1String("AutoCloseSessionTimeout")) {
+ if (engine && engine->requiresPolling() &&
+ !(engine->capabilities() & QNetworkConfigurationManager::CanStartAndStopInterfaces)) {
+ return sessionTimeout >= 0 ? sessionTimeout * 10000 : -1;
+ }
+ }
+
+ return QVariant();
+}
+
+void QNetworkSessionPrivateImpl::setSessionProperty(const QString &key, const QVariant &value)
+{
+ if (key == QLatin1String("AutoCloseSessionTimeout")) {
+ if (engine && engine->requiresPolling() &&
+ !(engine->capabilities() & QNetworkConfigurationManager::CanStartAndStopInterfaces)) {
+ int timeout = value.toInt();
+ if (timeout >= 0) {
+ connect(engine, SIGNAL(updateCompleted()),
+ this, SLOT(decrementTimeout()), Qt::UniqueConnection);
+ sessionTimeout = timeout / 10000; // convert to poll intervals
+ } else {
+ disconnect(engine, SIGNAL(updateCompleted()), this, SLOT(decrementTimeout()));
+ sessionTimeout = -1;
+ }
+ }
+ }
+}
+
+QString QNetworkSessionPrivateImpl::errorString() const
+{
+ switch (lastError) {
+ case QNetworkSession::UnknownSessionError:
+ return tr("Unknown session error.");
+ case QNetworkSession::SessionAbortedError:
+ return tr("The session was aborted by the user or system.");
+ case QNetworkSession::OperationNotSupportedError:
+ return tr("The requested operation is not supported by the system.");
+ case QNetworkSession::InvalidConfigurationError:
+ return tr("The specified configuration cannot be used.");
+ case QNetworkSession::RoamingError:
+ return tr("Roaming was aborted or is not possible.");
+ default:
+ break;
+ }
+
+ return QString();
+}
+
+QNetworkSession::SessionError QNetworkSessionPrivateImpl::error() const
+{
+ return lastError;
+}
+
+quint64 QNetworkSessionPrivateImpl::bytesWritten() const
+{
+ if (engine && state == QNetworkSession::Connected)
+ return engine->bytesWritten(activeConfig.identifier());
+ return Q_UINT64_C(0);
+}
+
+quint64 QNetworkSessionPrivateImpl::bytesReceived() const
+{
+ if (engine && state == QNetworkSession::Connected)
+ return engine->bytesReceived(activeConfig.identifier());
+ return Q_UINT64_C(0);
+}
+
+quint64 QNetworkSessionPrivateImpl::activeTime() const
+{
+ if (state == QNetworkSession::Connected && startTime != Q_UINT64_C(0))
+ return QDateTime::currentSecsSinceEpoch() - startTime;
+ return Q_UINT64_C(0);
+}
+
+QNetworkSession::UsagePolicies QNetworkSessionPrivateImpl::usagePolicies() const
+{
+ return currentPolicies;
+}
+
+void QNetworkSessionPrivateImpl::setUsagePolicies(QNetworkSession::UsagePolicies newPolicies)
+{
+ if (newPolicies != currentPolicies) {
+ currentPolicies = newPolicies;
+ emit usagePoliciesChanged(currentPolicies);
+ }
+}
+
+void QNetworkSessionPrivateImpl::updateStateFromServiceNetwork()
+{
+ QNetworkSession::State oldState = state;
+
+ const auto configs = serviceConfig.children();
+ for (const QNetworkConfiguration &config : configs) {
+ if ((config.state() & QNetworkConfiguration::Active) != QNetworkConfiguration::Active)
+ continue;
+
+ if (activeConfig != config) {
+ if (engine) {
+ disconnect(engine, SIGNAL(connectionError(QString,QBearerEngineImpl::ConnectionError)),
+ this, SLOT(connectionError(QString,QBearerEngineImpl::ConnectionError)));
+ }
+
+ activeConfig = config;
+ engine = getEngineFromId(activeConfig.identifier());
+
+ if (engine) {
+ connect(engine, SIGNAL(connectionError(QString,QBearerEngineImpl::ConnectionError)),
+ this, SLOT(connectionError(QString,QBearerEngineImpl::ConnectionError)),
+ Qt::QueuedConnection);
+ }
+ emit newConfigurationActivated();
+ }
+
+ state = QNetworkSession::Connected;
+ if (state != oldState)
+ emit stateChanged(state);
+
+ return;
+ }
+
+ if (serviceConfig.children().isEmpty())
+ state = QNetworkSession::NotAvailable;
+ else
+ state = QNetworkSession::Disconnected;
+
+ if (state != oldState)
+ emit stateChanged(state);
+}
+
+void QNetworkSessionPrivateImpl::updateStateFromActiveConfig()
+{
+ if (!engine)
+ return;
+
+ QNetworkSession::State oldState = state;
+ state = engine->sessionStateForId(activeConfig.identifier());
+
+ bool oldActive = isOpen;
+ isOpen = (state == QNetworkSession::Connected) ? opened : false;
+
+ if (!oldActive && isOpen)
+ emit quitPendingWaitsForOpened();
+ if (oldActive && !isOpen)
+ emit closed();
+
+ if (oldState != state)
+ emit stateChanged(state);
+}
+
+void QNetworkSessionPrivateImpl::networkConfigurationsChanged()
+{
+ if (serviceConfig.isValid())
+ updateStateFromServiceNetwork();
+ else
+ updateStateFromActiveConfig();
+
+ if (engine)
+ startTime = engine->startTime(activeConfig.identifier());
+}
+
+void QNetworkSessionPrivateImpl::configurationChanged(QNetworkConfigurationPrivatePointer config)
+{
+ if (serviceConfig.isValid() &&
+ (config->id == serviceConfig.identifier() || config->id == activeConfig.identifier())) {
+ updateStateFromServiceNetwork();
+ } else if (config->id == activeConfig.identifier()) {
+ updateStateFromActiveConfig();
+ }
+}
+
+void QNetworkSessionPrivateImpl::forcedSessionClose(const QNetworkConfiguration &config)
+{
+ if (activeConfig == config) {
+ opened = false;
+ isOpen = false;
+
+ emit closed();
+
+ lastError = QNetworkSession::SessionAbortedError;
+ emit QNetworkSessionPrivate::error(lastError);
+ }
+}
+
+void QNetworkSessionPrivateImpl::connectionError(const QString &id, QBearerEngineImpl::ConnectionError error)
+{
+ if (activeConfig.identifier() == id) {
+ networkConfigurationsChanged();
+ switch (error) {
+ case QBearerEngineImpl::OperationNotSupported:
+ lastError = QNetworkSession::OperationNotSupportedError;
+ opened = false;
+ break;
+ case QBearerEngineImpl::InterfaceLookupError:
+ case QBearerEngineImpl::ConnectError:
+ case QBearerEngineImpl::DisconnectionError:
+ default:
+ lastError = QNetworkSession::UnknownSessionError;
+ }
+
+ emit QNetworkSessionPrivate::error(lastError);
+ }
+}
+
+void QNetworkSessionPrivateImpl::decrementTimeout()
+{
+ if (--sessionTimeout <= 0) {
+ disconnect(engine, SIGNAL(updateCompleted()), this, SLOT(decrementTimeout()));
+ sessionTimeout = -1;
+ close();
+ }
+}
+
+QT_END_NAMESPACE
+
+#include "qnetworksession_impl.moc"
+
+#endif // QT_NO_BEARERMANAGEMENT
diff --git a/src/network/bearer/qnetworksession_impl_p.h b/src/network/bearer/qnetworksession_impl_p.h
new file mode 100644
index 0000000000..b174760152
--- /dev/null
+++ b/src/network/bearer/qnetworksession_impl_p.h
@@ -0,0 +1,134 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QNETWORKSESSION_IMPL_H
+#define QNETWORKSESSION_IMPL_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qbearerengine_impl_p.h"
+
+#include <QtNetwork/private/qnetworkconfigmanager_p.h>
+#include <QtNetwork/private/qnetworksession_p.h>
+
+#ifndef QT_NO_BEARERMANAGEMENT
+
+QT_BEGIN_NAMESPACE
+
+class QBearerEngineImpl;
+
+class Q_NETWORK_EXPORT QNetworkSessionPrivateImpl : public QNetworkSessionPrivate
+{
+ Q_OBJECT
+
+public:
+ QNetworkSessionPrivateImpl()
+ : engine(nullptr), startTime(0), lastError(QNetworkSession::UnknownSessionError), sessionTimeout(-1), currentPolicies(QNetworkSession::NoPolicy), opened(false)
+ {}
+ ~QNetworkSessionPrivateImpl()
+ {}
+
+ //called by QNetworkSession constructor and ensures
+ //that the state is immediately updated (w/o actually opening
+ //a session). Also this function should take care of
+ //notification hooks to discover future state changes.
+ void syncStateWithInterface() override;
+
+#ifndef QT_NO_NETWORKINTERFACE
+ QNetworkInterface currentInterface() const override;
+#endif
+ QVariant sessionProperty(const QString& key) const override;
+ void setSessionProperty(const QString& key, const QVariant& value) override;
+
+ void open() override;
+ void close() override;
+ void stop() override;
+ void migrate() override;
+ void accept() override;
+ void ignore() override;
+ void reject() override;
+
+ QString errorString() const override; //must return translated string
+ QNetworkSession::SessionError error() const override;
+
+ quint64 bytesWritten() const override;
+ quint64 bytesReceived() const override;
+ quint64 activeTime() const override;
+
+ QNetworkSession::UsagePolicies usagePolicies() const override;
+ void setUsagePolicies(QNetworkSession::UsagePolicies) override;
+
+private Q_SLOTS:
+ void networkConfigurationsChanged();
+ void configurationChanged(QNetworkConfigurationPrivatePointer config);
+ void forcedSessionClose(const QNetworkConfiguration &config);
+ void connectionError(const QString &id, QBearerEngineImpl::ConnectionError error);
+ void decrementTimeout();
+
+private:
+ void updateStateFromServiceNetwork();
+ void updateStateFromActiveConfig();
+
+private:
+ QBearerEngineImpl *engine;
+
+ quint64 startTime;
+
+ QNetworkSession::SessionError lastError;
+
+ int sessionTimeout;
+ QNetworkSession::UsagePolicies currentPolicies;
+
+ bool opened;
+};
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_BEARERMANAGEMENT
+
+#endif // QNETWORKSESSION_IMPL_H
diff --git a/src/network/kernel/qnetworkinterface.h b/src/network/kernel/qnetworkinterface.h
index 4caedaa38f..c65ea58860 100644
--- a/src/network/kernel/qnetworkinterface.h
+++ b/src/network/kernel/qnetworkinterface.h
@@ -50,7 +50,6 @@
QT_BEGIN_NAMESPACE
class QDeadlineTimer;
-template<typename T> class QList;
class QNetworkAddressEntryPrivate;
class Q_NETWORK_EXPORT QNetworkAddressEntry
diff --git a/src/network/socket/qlocalserver_p.h b/src/network/socket/qlocalserver_p.h
index 92616e59ce..f331a3f10d 100644
--- a/src/network/socket/qlocalserver_p.h
+++ b/src/network/socket/qlocalserver_p.h
@@ -99,15 +99,18 @@ public:
QMap<quintptr, QTcpSocket*> socketMap;
#elif defined(Q_OS_WIN)
struct Listener {
- HANDLE handle;
+ Listener() = default;
+ HANDLE handle = nullptr;
OVERLAPPED overlapped;
- bool connected;
+ bool connected = false;
+ private:
+ Q_DISABLE_COPY(Listener)
};
void setError(const QString &function);
bool addListener();
- QList<Listener> listeners;
+ std::vector<std::unique_ptr<Listener>> listeners;
HANDLE eventHandle;
QWinEventNotifier *connectionEventNotifier;
#else
diff --git a/src/network/socket/qlocalserver_win.cpp b/src/network/socket/qlocalserver_win.cpp
index 2d71a7e730..6d92ebe93a 100644
--- a/src/network/socket/qlocalserver_win.cpp
+++ b/src/network/socket/qlocalserver_win.cpp
@@ -62,8 +62,8 @@ bool QLocalServerPrivate::addListener()
{
// The object must not change its address once the
// contained OVERLAPPED struct is passed to Windows.
- listeners << Listener();
- Listener &listener = listeners.last();
+ listeners.push_back(std::make_unique<Listener>());
+ auto &listener = listeners.back();
SECURITY_ATTRIBUTES sa;
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
@@ -175,7 +175,7 @@ bool QLocalServerPrivate::addListener()
sa.lpSecurityDescriptor = pSD.data();
}
- listener.handle = CreateNamedPipe(
+ listener->handle = CreateNamedPipe(
reinterpret_cast<const wchar_t *>(fullServerName.utf16()), // pipe name
PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, // read/write access
PIPE_TYPE_BYTE | // byte type pipe
@@ -187,32 +187,32 @@ bool QLocalServerPrivate::addListener()
3000, // client time-out
&sa);
- if (listener.handle == INVALID_HANDLE_VALUE) {
+ if (listener->handle == INVALID_HANDLE_VALUE) {
setError(QLatin1String("QLocalServerPrivate::addListener"));
- listeners.removeLast();
+ listeners.pop_back();
return false;
}
if (worldSID)
FreeSid(worldSID);
- memset(&listener.overlapped, 0, sizeof(listener.overlapped));
- listener.overlapped.hEvent = eventHandle;
+ memset(&listener->overlapped, 0, sizeof(OVERLAPPED));
+ listener->overlapped.hEvent = eventHandle;
// Beware! ConnectNamedPipe will reset the eventHandle to non-signaled.
// Callers of addListener must check all listeners for connections.
- if (!ConnectNamedPipe(listener.handle, &listener.overlapped)) {
+ if (!ConnectNamedPipe(listener->handle, &listener->overlapped)) {
switch (GetLastError()) {
case ERROR_IO_PENDING:
- listener.connected = false;
+ listener->connected = false;
break;
case ERROR_PIPE_CONNECTED:
- listener.connected = true;
+ listener->connected = true;
break;
default:
- CloseHandle(listener.handle);
+ CloseHandle(listener->handle);
setError(QLatin1String("QLocalServerPrivate::addListener"));
- listeners.removeLast();
+ listeners.pop_back();
return false;
}
} else {
@@ -284,12 +284,12 @@ void QLocalServerPrivate::_q_onNewConnection()
// Testing shows that there is indeed absolutely no guarantee which listener gets
// a client connection first, so there is no way around polling all of them.
- for (int i = 0; i < listeners.size(); ) {
- HANDLE handle = listeners[i].handle;
- if (listeners[i].connected
- || GetOverlappedResult(handle, &listeners[i].overlapped, &dummy, FALSE))
+ for (size_t i = 0; i < listeners.size(); ) {
+ HANDLE handle = listeners[i]->handle;
+ if (listeners[i]->connected
+ || GetOverlappedResult(handle, &listeners[i]->overlapped, &dummy, FALSE))
{
- listeners.removeAt(i);
+ listeners.erase(listeners.begin() + i);
addListener();
@@ -319,8 +319,8 @@ void QLocalServerPrivate::closeServer()
connectionEventNotifier->deleteLater();
connectionEventNotifier = 0;
CloseHandle(eventHandle);
- for (int i = 0; i < listeners.size(); ++i)
- CloseHandle(listeners[i].handle);
+ for (size_t i = 0; i < listeners.size(); ++i)
+ CloseHandle(listeners[i]->handle);
listeners.clear();
}
diff --git a/src/network/ssl/qssl.cpp b/src/network/ssl/qssl.cpp
index c9fa7f85d9..bfbe8eb90f 100644
--- a/src/network/ssl/qssl.cpp
+++ b/src/network/ssl/qssl.cpp
@@ -120,8 +120,6 @@ Q_LOGGING_CATEGORY(lcSsl, "qt.network.ssl");
Describes the protocol of the cipher.
- \value SslV3 SSLv3; not supported by QSslSocket.
- \value SslV2 SSLv2; not supported by QSslSocket.
\value TlsV1_0 TLSv1.0
\value TlsV1_0OrLater TLSv1.0 and later versions. This option is not available when using the WinRT backend due to platform limitations.
\value TlsV1 Obsolete, means the same as TlsV1_0
@@ -137,7 +135,6 @@ Q_LOGGING_CATEGORY(lcSsl, "qt.network.ssl");
\value TlsV1_3OrLater TLSv1.3 and later versions. (Since Qt 5.12)
\value UnknownProtocol The cipher's protocol cannot be determined.
\value AnyProtocol Any supported protocol. This value is used by QSslSocket only.
- \value TlsV1SslV3 Same as TlsV1_0.
\value SecureProtocols The default option, using protocols known to be secure.
*/
diff --git a/src/network/ssl/qssl.h b/src/network/ssl/qssl.h
index b28c2a87b9..1fd2cf9c6d 100644
--- a/src/network/ssl/qssl.h
+++ b/src/network/ssl/qssl.h
@@ -77,20 +77,10 @@ namespace QSsl {
#endif
enum SslProtocol {
-#if QT_DEPRECATED_SINCE(5, 15)
- SslV3,
- SslV2,
-#endif
TlsV1_0 = 2,
-#if QT_DEPRECATED_SINCE(5,0)
- TlsV1 = TlsV1_0,
-#endif
TlsV1_1,
TlsV1_2,
AnyProtocol,
-#if QT_DEPRECATED_SINCE(5, 15)
- TlsV1SslV3,
-#endif
SecureProtocols = AnyProtocol + 2,
TlsV1_0OrLater,
diff --git a/src/network/ssl/qsslconfiguration.cpp b/src/network/ssl/qsslconfiguration.cpp
index a2e694ec92..b6199a2b16 100644
--- a/src/network/ssl/qsslconfiguration.cpp
+++ b/src/network/ssl/qsslconfiguration.cpp
@@ -54,7 +54,6 @@ const QSsl::SslOptions QSslConfigurationPrivate::defaultSslOptions = QSsl::SslOp
|QSsl::SslOptionDisableSessionPersistence;
const char QSslConfiguration::ALPNProtocolHTTP2[] = "h2";
-const char QSslConfiguration::NextProtocolSpdy3_0[] = "spdy/3";
const char QSslConfiguration::NextProtocolHttp1_1[] = "http/1.1";
/*!
@@ -134,12 +133,6 @@ const char QSslConfiguration::NextProtocolHttp1_1[] = "http/1.1";
*/
/*!
- \variable QSslConfiguration::NextProtocolSpdy3_0
- \brief The value used for negotiating SPDY 3.0 during the Next
- Protocol Negotiation.
-*/
-
-/*!
\variable QSslConfiguration::NextProtocolHttp1_1
\brief The value used for negotiating HTTP 1.1 during the Next
Protocol Negotiation.
@@ -229,7 +222,9 @@ bool QSslConfiguration::operator==(const QSslConfiguration &other) const
d->nextNegotiatedProtocol == other.d->nextNegotiatedProtocol &&
d->nextProtocolNegotiationStatus == other.d->nextProtocolNegotiationStatus &&
d->dtlsCookieEnabled == other.d->dtlsCookieEnabled &&
- d->ocspStaplingEnabled == other.d->ocspStaplingEnabled;
+ d->ocspStaplingEnabled == other.d->ocspStaplingEnabled &&
+ d->reportFromCallback == other.d->reportFromCallback &&
+ d->missingCertIsFatal == other.d->missingCertIsFatal;
}
/*!
@@ -274,7 +269,9 @@ bool QSslConfiguration::isNull() const
d->nextAllowedProtocols.isEmpty() &&
d->nextNegotiatedProtocol.isNull() &&
d->nextProtocolNegotiationStatus == QSslConfiguration::NextProtocolNegotiationNone &&
- d->ocspStaplingEnabled == false);
+ d->ocspStaplingEnabled == false &&
+ d->reportFromCallback == false &&
+ d->missingCertIsFatal == false);
}
/*!
@@ -1033,7 +1030,7 @@ QByteArray QSslConfiguration::nextNegotiatedProtocol() const
Whether or not the negotiation succeeded can be queried through
nextProtocolNegotiationStatus().
- \sa nextNegotiatedProtocol(), nextProtocolNegotiationStatus(), allowedNextProtocols(), QSslConfiguration::NextProtocolSpdy3_0, QSslConfiguration::NextProtocolHttp1_1
+ \sa nextNegotiatedProtocol(), nextProtocolNegotiationStatus(), allowedNextProtocols(), QSslConfiguration::NextProtocolHttp1_1
*/
#if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
void QSslConfiguration::setAllowedNextProtocols(const QList<QByteArray> &protocols)
@@ -1051,7 +1048,7 @@ void QSslConfiguration::setAllowedNextProtocols(QList<QByteArray> protocols)
server through the Next Protocol Negotiation (NPN) or Application-Layer
Protocol Negotiation (ALPN) TLS extension, as set by setAllowedNextProtocols().
- \sa nextNegotiatedProtocol(), nextProtocolNegotiationStatus(), setAllowedNextProtocols(), QSslConfiguration::NextProtocolSpdy3_0, QSslConfiguration::NextProtocolHttp1_1
+ \sa nextNegotiatedProtocol(), nextProtocolNegotiationStatus(), setAllowedNextProtocols(), QSslConfiguration::NextProtocolHttp1_1
*/
QList<QByteArray> QSslConfiguration::allowedNextProtocols() const
{
@@ -1197,6 +1194,89 @@ bool QSslConfiguration::ocspStaplingEnabled() const
return d->ocspStaplingEnabled;
}
+/*!
+ \since 6.0
+
+ Returns true if a verification callback will emit QSslSocket::handshakeInterruptedOnError()
+ early, before concluding the handshake.
+
+ \note This function always returns false for all backends but OpenSSL.
+
+ \sa setHandshakeMustInterruptOnError(), QSslSocket::handshakeInterruptedOnError(), QSslSocket::continueInterruptedHandshake()
+*/
+bool QSslConfiguration::handshakeMustInterruptOnError() const
+{
+ return d->reportFromCallback;
+}
+
+/*!
+ \since 6.0
+
+ If \a interrupt is true and the underlying backend supports this option,
+ errors found during certificate verification are reported immediately
+ by emitting QSslSocket::handshakeInterruptedOnError(). This allows
+ to stop the unfinished handshake and send a proper alert message to
+ a peer. No special action is required from the application in this case.
+ QSslSocket will close the connection after sending the alert message.
+ If the application after inspecting the error wants to continue the
+ handshake, it must call QSslSocket::continueInterruptedHandshake()
+ from its slot function. The signal-slot connection must be direct.
+
+ \note When interrupting handshake is enabled, errors that would otherwise
+ be reported by QSslSocket::peerVerifyError() are instead only reported by
+ QSslSocket::handshakeInterruptedOnError().
+ \note Even if the handshake was continued, these errors will be
+ reported when emitting QSslSocket::sslErrors() signal (and thus must
+ be ignored in the corresponding function slot).
+
+ \sa handshakeMustInterruptOnError(), QSslSocket::handshakeInterruptedOnError(), QSslSocket::continueInterruptedHandshake()
+*/
+void QSslConfiguration::setHandshakeMustInterruptOnError(bool interrupt)
+{
+#if QT_CONFIG(openssl)
+ d->reportFromCallback = interrupt;
+#else
+ qCWarning(lcSsl, "This operation requires OpenSSL as TLS backend");
+#endif
+}
+
+/*!
+ \since 6.0
+
+ Returns true if errors with code QSslError::NoPeerCertificate
+ cannot be ignored.
+
+ \note Always returns false for all TLS backends but OpenSSL.
+
+ \sa QSslSocket::ignoreSslErrors(), setMissingCertificateIsFatal()
+*/
+bool QSslConfiguration::missingCertificateIsFatal() const
+{
+ return d->missingCertIsFatal;
+}
+
+/*!
+ \since 6.0
+
+ If \a cannotRecover is true, and verification mode in use is
+ QSslSocket::VerifyPeer or QSslSocket::AutoVerifyPeer (for a
+ client-side socket), the missing peer's certificate would be
+ treated as an unrecoverable error that cannot be ignored. A proper
+ alert message will be sent to the peer before closing the connection.
+
+ \note Only available if Qt was configured and built with OpenSSL backend.
+
+ \sa QSslSocket::ignoreSslErrors(), QSslSocket::PeerVerifyMode, missingCertificateIsFatal()
+*/
+void QSslConfiguration::setMissingCertificateIsFatal(bool cannotRecover)
+{
+#if QT_CONFIG(openssl)
+ d->missingCertIsFatal = cannotRecover;
+#else
+ qCWarning(lcSsl, "Handling a missing certificate as a fatal error requires an OpenSSL backend");
+#endif // openssl
+}
+
/*! \internal
*/
bool QSslConfigurationPrivate::peerSessionWasShared(const QSslConfiguration &configuration) {
diff --git a/src/network/ssl/qsslconfiguration.h b/src/network/ssl/qsslconfiguration.h
index 247f3aecc9..dc4587a835 100644
--- a/src/network/ssl/qsslconfiguration.h
+++ b/src/network/ssl/qsslconfiguration.h
@@ -66,7 +66,6 @@
QT_BEGIN_NAMESPACE
-template<typename T> class QList;
class QSslCertificate;
class QSslCipher;
class QSslKey;
@@ -173,6 +172,12 @@ public:
static void setDefaultDtlsConfiguration(const QSslConfiguration &configuration);
#endif // dtls
+ bool handshakeMustInterruptOnError() const;
+ void setHandshakeMustInterruptOnError(bool interrupt);
+
+ bool missingCertificateIsFatal() const;
+ void setMissingCertificateIsFatal(bool cannotRecover);
+
void setOcspStaplingEnabled(bool enable);
bool ocspStaplingEnabled() const;
@@ -193,7 +198,6 @@ public:
NextProtocolNegotiationStatus nextProtocolNegotiationStatus() const;
static const char ALPNProtocolHTTP2[];
- static const char NextProtocolSpdy3_0[];
static const char NextProtocolHttp1_1[];
private:
diff --git a/src/network/ssl/qsslconfiguration_p.h b/src/network/ssl/qsslconfiguration_p.h
index 83126bb9a0..6ee3490df6 100644
--- a/src/network/ssl/qsslconfiguration_p.h
+++ b/src/network/ssl/qsslconfiguration_p.h
@@ -149,6 +149,14 @@ public:
const bool ocspStaplingEnabled = false;
#endif
+#if QT_CONFIG(openssl)
+ bool reportFromCallback = false;
+ bool missingCertIsFatal = false;
+#else
+ const bool reportFromCallback = false;
+ const bool missingCertIsFatal = false;
+#endif // openssl
+
// in qsslsocket.cpp:
static QSslConfiguration defaultConfiguration();
static void setDefaultConfiguration(const QSslConfiguration &configuration);
diff --git a/src/network/ssl/qsslcontext_openssl.cpp b/src/network/ssl/qsslcontext_openssl.cpp
index 562aa4f518..574f48a2b5 100644
--- a/src/network/ssl/qsslcontext_openssl.cpp
+++ b/src/network/ssl/qsslcontext_openssl.cpp
@@ -56,6 +56,7 @@ QT_BEGIN_NAMESPACE
// defined in qsslsocket_openssl.cpp:
extern int q_X509Callback(int ok, X509_STORE_CTX *ctx);
+extern "C" int q_X509CallbackDirect(int ok, X509_STORE_CTX *ctx);
extern QString getErrorsFromOpenSsl();
#if QT_CONFIG(dtls)
@@ -286,42 +287,31 @@ void QSslContext::initSslContext(QSslContext *sslContext, QSslSocket::SslMode mo
bool unsupportedProtocol = false;
bool isDtls = false;
init_context:
- if (sslContext->sslConfiguration.protocol() == QSsl::SslV2) {
- // SSL 2 is no longer supported, but chosen deliberately -> error
- sslContext->ctx = nullptr;
- unsupportedProtocol = true;
- } else if (sslContext->sslConfiguration.protocol() == QSsl::SslV3) {
- // SSL 3 is no longer supported, but chosen deliberately -> error
- sslContext->ctx = nullptr;
- unsupportedProtocol = true;
- } else {
- switch (sslContext->sslConfiguration.protocol()) {
- case QSsl::DtlsV1_0:
- case QSsl::DtlsV1_0OrLater:
- case QSsl::DtlsV1_2:
- case QSsl::DtlsV1_2OrLater:
+ switch (sslContext->sslConfiguration.protocol()) {
+ case QSsl::DtlsV1_0:
+ case QSsl::DtlsV1_0OrLater:
+ case QSsl::DtlsV1_2:
+ case QSsl::DtlsV1_2OrLater:
#if QT_CONFIG(dtls)
- isDtls = true;
- sslContext->ctx = q_SSL_CTX_new(client ? q_DTLS_client_method() : q_DTLS_server_method());
+ isDtls = true;
+ sslContext->ctx = q_SSL_CTX_new(client ? q_DTLS_client_method() : q_DTLS_server_method());
#else // dtls
- sslContext->ctx = nullptr;
- unsupportedProtocol = true;
- qCWarning(lcSsl, "DTLS protocol requested, but feature 'dtls' is disabled");
-
+ sslContext->ctx = nullptr;
+ unsupportedProtocol = true;
+ qCWarning(lcSsl, "DTLS protocol requested, but feature 'dtls' is disabled");
#endif // dtls
- break;
- case QSsl::TlsV1_3:
- case QSsl::TlsV1_3OrLater:
+ break;
+ case QSsl::TlsV1_3:
+ case QSsl::TlsV1_3OrLater:
#if !defined(TLS1_3_VERSION)
- qCWarning(lcSsl, "TLS 1.3 is not supported");
- sslContext->ctx = nullptr;
- unsupportedProtocol = true;
- break;
+ qCWarning(lcSsl, "TLS 1.3 is not supported");
+ sslContext->ctx = nullptr;
+ unsupportedProtocol = true;
+ break;
#endif // TLS1_3_VERSION
- default:
- // The ssl options will actually control the supported methods
- sslContext->ctx = q_SSL_CTX_new(client ? q_TLS_client_method() : q_TLS_server_method());
- }
+ default:
+ // The ssl options will actually control the supported methods
+ sslContext->ctx = q_SSL_CTX_new(client ? q_TLS_client_method() : q_TLS_server_method());
}
if (!sslContext->ctx) {
@@ -373,7 +363,6 @@ init_context:
#endif // TLS1_3_VERSION
break;
// Ranges:
- case QSsl::TlsV1SslV3:
case QSsl::AnyProtocol:
case QSsl::SecureProtocols:
case QSsl::TlsV1_0OrLater:
@@ -415,12 +404,6 @@ init_context:
Q_UNREACHABLE();
break;
#endif // TLS1_3_VERSION
- case QSsl::SslV2:
- case QSsl::SslV3:
- // These protocols are not supported, and we handle
- // them as an error (see the code above).
- Q_UNREACHABLE();
- break;
case QSsl::UnknownProtocol:
break;
}
@@ -589,11 +572,20 @@ init_context:
if (sslContext->sslConfiguration.peerVerifyMode() == QSslSocket::VerifyNone) {
q_SSL_CTX_set_verify(sslContext->ctx, SSL_VERIFY_NONE, nullptr);
} else {
- q_SSL_CTX_set_verify(sslContext->ctx, SSL_VERIFY_PEER,
-#if QT_CONFIG(dtls)
- isDtls ? dtlscallbacks::q_X509DtlsCallback :
-#endif // dtls
- q_X509Callback);
+ auto verificationCallback =
+ #if QT_CONFIG(dtls)
+ isDtls ? dtlscallbacks::q_X509DtlsCallback :
+ #endif // dtls
+ q_X509Callback;
+
+ if (!isDtls && configuration.handshakeMustInterruptOnError())
+ verificationCallback = q_X509CallbackDirect;
+
+ auto verificationMode = SSL_VERIFY_PEER;
+ if (!isDtls && sslContext->sslConfiguration.missingCertificateIsFatal())
+ verificationMode |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
+
+ q_SSL_CTX_set_verify(sslContext->ctx, verificationMode, verificationCallback);
}
#if QT_CONFIG(dtls)
diff --git a/src/network/ssl/qsslsocket.cpp b/src/network/ssl/qsslsocket.cpp
index 1b72be66fe..b0fb32bbaf 100644
--- a/src/network/ssl/qsslsocket.cpp
+++ b/src/network/ssl/qsslsocket.cpp
@@ -228,6 +228,74 @@
*/
/*!
+ \enum QAlertLevel
+ \brief Describes the level of an alert message
+ \relates QSslSocket
+ \since 6.0
+
+ \ingroup network
+ \ingroup ssl
+ \inmodule QtNetwork
+
+ This enum describes the level of an alert message that was sent
+ or received.
+
+ \value Warning Non-fatal alert message
+ \value Fatal Fatal alert message, the underlying backend will
+ handle such an alert properly and close the connection.
+ \value Unknown An alert of unknown level of severity.
+*/
+
+/*!
+ \enum QAlertType
+ \brief Enumerates possible codes that an alert message can have
+ \relates QSslSocket
+ \since 6.0
+
+ \ingroup network
+ \ingroup ssl
+ \inmodule QtNetwork
+
+ See \l{https://tools.ietf.org/html/rfc8446#page-85}{RFC 8446, section 6}
+ for the possible values and their meaning.
+
+ \value CloseNotify,
+ \value UnexpectedMessage
+ \value BadRecordMac
+ \value RecordOverflow
+ \value DecompressionFailure
+ \value HandshakeFailure
+ \value NoCertificate
+ \value BadCertificate
+ \value UnsupportedCertificate
+ \value CertificateRevoked
+ \value CertificateExpired
+ \value CertificateUnknown
+ \value IllegalParameter
+ \value UnknownCa
+ \value AccessDenied
+ \value DecodeError
+ \value DecryptError
+ \value ExportRestriction
+ \value ProtocolVersion
+ \value InsufficientSecurity
+ \value InternalError
+ \value InappropriateFallback
+ \value UserCancelled
+ \value NoRenegotiation
+ \value MissingExtension
+ \value UnsupportedExtension
+ \value CertificateUnobtainable
+ \value UnrecognizedName
+ \value BadCertificateStatusResponse
+ \value BadCertificateHashValue
+ \value UnknownPskIdentity
+ \value CertificateRequired
+ \value NoApplicationProtocol
+ \value UnknownAlertMessage
+*/
+
+/*!
\fn void QSslSocket::encrypted()
This signal is emitted when QSslSocket enters encrypted mode. After this
@@ -322,6 +390,48 @@
\sa QSslPreSharedKeyAuthenticator
*/
+/*!
+ \fn void QSslSocket::alertSent(QAlertLevel level, QAlertType type, const QString &description)
+
+ QSslSocket emits this signal if an alert message was sent to a peer. \a level
+ describes if it was a warning or a fatal error. \a type gives the code
+ of the alert message. When a textual description of the alert message is
+ available, it is supplied in \a description.
+
+ \note This signal is mostly informational and can be used for debugging
+ purposes, normally it does not require any actions from the application.
+ \note Not all backends support this functionality.
+
+ \sa alertReceived(), QAlertLevel, QAlertType
+*/
+
+/*!
+ \fn void QSslSocket::alertReceived(QAlertLevel level, QAlertType type, const QString &description)
+
+ QSslSocket emits this signal if an alert message was received from a peer.
+ \a level tells if the alert was fatal or it was a warning. \a type is the
+ code explaining why the alert was sent. When a textual description of
+ the alert message is available, it is supplied in \a description.
+
+ \note The signal is mostly for informational and debugging purposes and does not
+ require any handling in the application. If the alert was fatal, underlying
+ backend will handle it and close the connection.
+ \note Not all backends support this functionality.
+
+ \sa alertSent(), QAlertLevel, QAlertType
+*/
+
+/*!
+ \fn void QSslSocket::handshakeInterruptedOnError(const QSslError &error)
+
+ QSslSocket emits this signal if a certificate verification error was
+ found and if early error reporting was enabled in QSslConfiguration.
+ An application is expected to inspect the \a error and decide if
+ it wants to continue the handshake, or abort it and send an alert message
+ to the peer. The signal-slot connection must be direct.
+
+ \sa continueInterruptedHandshake(), sslErrors(), QSslConfiguration::setHandshakeMustInterruptOnError()
+*/
#include "qssl_p.h"
#include "qsslsocket.h"
#include "qsslcipher.h"
@@ -977,7 +1087,10 @@ void QSslSocket::setSslConfiguration(const QSslConfiguration &configuration)
#if QT_CONFIG(ocsp)
d->configuration.ocspStaplingEnabled = configuration.ocspStaplingEnabled();
#endif
-
+#if QT_CONFIG(openssl)
+ d->configuration.reportFromCallback = configuration.handshakeMustInterruptOnError();
+ d->configuration.missingCertIsFatal = configuration.missingCertificateIsFatal();
+#endif // openssl
// if the CA certificates were set explicitly (either via
// QSslConfiguration::setCaCertificates() or QSslSocket::setCaCertificates(),
// we cannot load the certificates on demand
@@ -2043,6 +2156,23 @@ void QSslSocket::ignoreSslErrors(const QList<QSslError> &errors)
d->ignoreErrorsList = errors;
}
+
+/*!
+ \since 6.0
+
+ If an application wants to conclude a handshake even after receiving
+ handshakeInterruptedOnError() signal, it must call this function.
+ This call must be done from a slot function attached to the signal.
+ The signal-slot connection must be direct.
+
+ \sa handshakeInterruptedOnError(), QSslConfiguration::setHandshakeMustInterruptOnError()
+*/
+void QSslSocket::continueInterruptedHandshake()
+{
+ Q_D(QSslSocket);
+ d->handshakeInterrupted = false;
+}
+
/*!
\internal
*/
@@ -2217,13 +2347,24 @@ void QSslSocketPrivate::init()
*/
bool QSslSocketPrivate::verifyProtocolSupported(const char *where)
{
- if (configuration.protocol == QSsl::SslV2 || configuration.protocol == QSsl::SslV3) {
- qCWarning(lcSsl) << where << "Attempted to use an unsupported protocol.";
+ QLatin1String protocolName("DTLS");
+ switch (configuration.protocol) {
+ case QSsl::UnknownProtocol:
+ // UnknownProtocol, according to our docs, is for cipher whose protocol is unknown.
+ // Should not be used when configuring QSslSocket.
+ protocolName = QLatin1String("UnknownProtocol");
+ Q_FALLTHROUGH();
+ case QSsl::DtlsV1_0:
+ case QSsl::DtlsV1_2:
+ case QSsl::DtlsV1_0OrLater:
+ case QSsl::DtlsV1_2OrLater:
+ qCWarning(lcSsl) << where << "QSslConfiguration with unexpected protocol" << protocolName;
setErrorAndEmit(QAbstractSocket::SslInvalidUserDataError,
QSslSocket::tr("Attempted to use an unsupported protocol."));
return false;
+ default:
+ return true;
}
- return true;
}
/*!
@@ -2434,6 +2575,10 @@ void QSslConfigurationPrivate::deepCopyDefaultConfiguration(QSslConfigurationPri
#if QT_CONFIG(ocsp)
ptr->ocspStaplingEnabled = global->ocspStaplingEnabled;
#endif
+#if QT_CONFIG(openssl)
+ ptr->reportFromCallback = global->reportFromCallback;
+ ptr->missingCertIsFatal = global->missingCertIsFatal;
+#endif
}
/*!
diff --git a/src/network/ssl/qsslsocket.h b/src/network/ssl/qsslsocket.h
index 843e2d15f5..8b0f317da4 100644
--- a/src/network/ssl/qsslsocket.h
+++ b/src/network/ssl/qsslsocket.h
@@ -63,6 +63,49 @@ class QSslEllipticCurve;
class QSslPreSharedKeyAuthenticator;
class QOcspResponse;
+enum class QAlertLevel {
+ Warning,
+ Fatal,
+ Unknown
+};
+
+enum class QAlertType {
+ CloseNotify,
+ UnexpectedMessage = 10,
+ BadRecordMac = 20,
+ RecordOverflow = 22,
+ DecompressionFailure = 30, // reserved
+ HandshakeFailure = 40,
+ NoCertificate = 41, // reserved
+ BadCertificate = 42,
+ UnsupportedCertificate = 43,
+ CertificateRevoked = 44,
+ CertificateExpired = 45,
+ CertificateUnknown = 46,
+ IllegalParameter = 47,
+ UnknownCa = 48,
+ AccessDenied = 49,
+ DecodeError = 50,
+ DecryptError = 51,
+ ExportRestriction = 60, // reserved
+ ProtocolVersion = 70,
+ InsufficientSecurity = 71,
+ InternalError = 80,
+ InappropriateFallback = 86,
+ UserCancelled = 90,
+ NoRenegotiation = 100,
+ MissingExtension = 109,
+ UnsupportedExtension = 110,
+ CertificateUnobtainable = 111, // reserved
+ UnrecognizedName = 112,
+ BadCertificateStatusResponse = 113,
+ BadCertificateHashValue = 114, // reserved
+ UnknownPskIdentity = 115,
+ CertificateRequired = 116,
+ NoApplicationProtocol = 120,
+ UnknownAlertMessage = 255
+};
+
class QSslSocketPrivate;
class Q_NETWORK_EXPORT QSslSocket : public QTcpSocket
{
@@ -201,6 +244,7 @@ public:
static QString sslLibraryBuildVersionString();
void ignoreSslErrors(const QList<QSslError> &errors);
+ void continueInterruptedHandshake();
public Q_SLOTS:
void startClientEncryption();
@@ -214,6 +258,9 @@ Q_SIGNALS:
void modeChanged(QSslSocket::SslMode newMode);
void encryptedBytesWritten(qint64 totalBytes);
void preSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator *authenticator);
+ void alertSent(QAlertLevel level, QAlertType type, const QString &description);
+ void alertReceived(QAlertLevel level, QAlertType type, const QString &description);
+ void handshakeInterruptedOnError(const QSslError &error);
protected:
qint64 readData(char *data, qint64 maxlen) override;
diff --git a/src/network/ssl/qsslsocket_mac.cpp b/src/network/ssl/qsslsocket_mac.cpp
index e0e065679d..fe1c43d992 100644
--- a/src/network/ssl/qsslsocket_mac.cpp
+++ b/src/network/ssl/qsslsocket_mac.cpp
@@ -496,10 +496,6 @@ QSsl::SslProtocol QSslSocketBackendPrivate::sessionProtocol() const
}
switch (protocol) {
- case kSSLProtocol2:
- return QSsl::SslV2;
- case kSSLProtocol3:
- return QSsl::SslV3;
case kTLSProtocol1:
return QSsl::TlsV1_0;
case kTLSProtocol11:
@@ -657,23 +653,6 @@ QSslCipher QSslSocketBackendPrivate::QSslCipher_from_SSLCipherSuite(SSLCipherSui
QSslCipher ciph;
switch (cipher) {
// Sorted as in CipherSuite.h (and groupped by their RFC)
- case SSL_RSA_WITH_NULL_MD5:
- ciph.d->name = QLatin1String("NULL-MD5");
- ciph.d->protocol = QSsl::SslV3;
- break;
- case SSL_RSA_WITH_NULL_SHA:
- ciph.d->name = QLatin1String("NULL-SHA");
- ciph.d->protocol = QSsl::SslV3;
- break;
- case SSL_RSA_WITH_RC4_128_MD5:
- ciph.d->name = QLatin1String("RC4-MD5");
- ciph.d->protocol = QSsl::SslV3;
- break;
- case SSL_RSA_WITH_RC4_128_SHA:
- ciph.d->name = QLatin1String("RC4-SHA");
- ciph.d->protocol = QSsl::SslV3;
- break;
-
// TLS addenda using AES, per RFC 3268
case TLS_RSA_WITH_AES_128_CBC_SHA:
ciph.d->name = QLatin1String("AES128-SHA");
@@ -822,12 +801,8 @@ QSslCipher QSslSocketBackendPrivate::QSslCipher_from_SSLCipherSuite(SSLCipherSui
ciph.d->isNull = false;
// protocol
- if (ciph.d->protocol == QSsl::SslV3) {
- ciph.d->protocolString = QLatin1String("SSLv3");
- } else {
- ciph.d->protocol = QSsl::TlsV1_2;
- ciph.d->protocolString = QLatin1String("TLSv1.2");
- }
+ ciph.d->protocol = QSsl::TlsV1_2;
+ ciph.d->protocolString = QLatin1String("TLSv1.2");
const auto bits = ciph.d->name.splitRef(QLatin1Char('-'));
if (bits.size() >= 2) {
@@ -1106,22 +1081,6 @@ bool QSslSocketBackendPrivate::setSessionProtocol()
{
Q_ASSERT_X(context, Q_FUNC_INFO, "invalid SSL context (null)");
- // QSsl::SslV2 == kSSLProtocol2 is disabled in Secure Transport and
- // always fails with errSSLIllegalParam:
- // if (version < MINIMUM_STREAM_VERSION || version > MAXIMUM_STREAM_VERSION)
- // return errSSLIllegalParam;
- // where MINIMUM_STREAM_VERSION is SSL_Version_3_0, MAXIMUM_STREAM_VERSION is TLS_Version_1_2.
- if (configuration.protocol == QSsl::SslV2) {
- qCDebug(lcSsl) << "protocol QSsl::SslV2 is disabled";
- return false;
- }
-
- // SslV3 is unsupported.
- if (configuration.protocol == QSsl::SslV3) {
- qCDebug(lcSsl) << "protocol QSsl::SslV3 is disabled";
- return false;
- }
-
// SecureTransport has kTLSProtocol13 constant and also, kTLSProtocolMaxSupported.
// Calling SSLSetProtocolVersionMax/Min with any of these two constants results
// in errInvalidParam and a failure to set the protocol version. This means
@@ -1162,13 +1121,6 @@ bool QSslSocketBackendPrivate::setSessionProtocol()
qCDebug(lcSsl) << plainSocket << "requesting : any";
#endif
err = SSLSetProtocolVersionMin(context, kTLSProtocol1);
- } else if (configuration.protocol == QSsl::TlsV1SslV3) {
- #ifdef QSSLSOCKET_DEBUG
- qCDebug(lcSsl) << plainSocket << "requesting : SSLv3 - TLSv1.2";
- #endif
- err = SSLSetProtocolVersionMin(context, kTLSProtocol1);
- if (err == errSecSuccess)
- err = SSLSetProtocolVersionMax(context, kTLSProtocol1);
} else if (configuration.protocol == QSsl::SecureProtocols) {
#ifdef QSSLSOCKET_DEBUG
qCDebug(lcSsl) << plainSocket << "requesting : TLSv1 - TLSv1.2";
@@ -1213,8 +1165,6 @@ bool QSslSocketBackendPrivate::verifySessionProtocol() const
bool protocolOk = false;
if (configuration.protocol == QSsl::AnyProtocol)
protocolOk = true;
- else if (configuration.protocol == QSsl::TlsV1SslV3)
- protocolOk = (sessionProtocol() == QSsl::TlsV1_0);
else if (configuration.protocol == QSsl::SecureProtocols)
protocolOk = (sessionProtocol() >= QSsl::TlsV1_0);
else if (configuration.protocol == QSsl::TlsV1_0OrLater)
diff --git a/src/network/ssl/qsslsocket_openssl.cpp b/src/network/ssl/qsslsocket_openssl.cpp
index 8fbbffcaca..f0775ba33b 100644
--- a/src/network/ssl/qsslsocket_openssl.cpp
+++ b/src/network/ssl/qsslsocket_openssl.cpp
@@ -98,6 +98,123 @@
QT_BEGIN_NAMESPACE
+namespace {
+
+QAlertLevel tlsAlertLevel(int value)
+{
+ if (const char *typeString = q_SSL_alert_type_string(value)) {
+ // Documented to return 'W' for warning, 'F' for fatal,
+ // 'U' for unknown.
+ switch (typeString[0]) {
+ case 'W':
+ return QAlertLevel::Warning;
+ case 'F':
+ return QAlertLevel::Fatal;
+ default:;
+ }
+ }
+
+ return QAlertLevel::Unknown;
+}
+
+QString tlsAlertDescription(int value)
+{
+ QString description = QLatin1String(q_SSL_alert_desc_string_long(value));
+ if (!description.size())
+ description = QLatin1String("no description provided");
+ return description;
+}
+
+QAlertType tlsAlertType(int value)
+{
+ // In case for some reason openssl gives us a value,
+ // which is not in our enum actually, we leave it to
+ // an application to handle (supposedly they have
+ // if or switch-statements).
+ return QAlertType(value & 0xff);
+}
+
+} // Unnamed namespace
+
+extern "C"
+{
+
+void qt_AlertInfoCallback(const SSL *connection, int from, int value)
+{
+ // Passed to SSL_set_info_callback()
+ // https://www.openssl.org/docs/man1.1.1/man3/SSL_set_info_callback.html
+
+ if (!connection) {
+#ifdef QSSLSOCKET_DEBUG
+ qCWarning(lcSsl, "Invalid 'connection' parameter (nullptr)");
+#endif // QSSLSOCKET_DEBUG
+ return;
+ }
+
+ const auto offset = QSslSocketBackendPrivate::s_indexForSSLExtraData
+ + QSslSocketBackendPrivate::socketOffsetInExData;
+ auto privateSocket =
+ static_cast<QSslSocketBackendPrivate *>(q_SSL_get_ex_data(connection, offset));
+ if (!privateSocket) {
+ // SSL_set_ex_data can fail:
+#ifdef QSSLSOCKET_DEBUG
+ qCWarning(lcSsl, "No external data (socket backend) found for parameter 'connection'");
+#endif // QSSLSOCKET_DEBUG
+ return;
+ }
+
+ if (!(from & SSL_CB_ALERT)) {
+ // We only want to know about alerts (at least for now).
+ return;
+ }
+
+ if (from & SSL_CB_WRITE)
+ privateSocket->alertMessageSent(value);
+ else
+ privateSocket->alertMessageReceived(value);
+}
+
+int q_X509CallbackDirect(int ok, X509_STORE_CTX *ctx)
+{
+ // Passed to SSL_CTX_set_verify()
+ // https://www.openssl.org/docs/man1.1.1/man3/SSL_CTX_set_verify.html
+ // Returns 0 to abort verification, 1 to continue.
+
+ // This is a new, experimental verification callback, reporting
+ // errors immediately and returning 0 or 1 depending on an application
+ // either ignoring or not ignoring verification errors as they come.
+ if (!ctx) {
+ qCWarning(lcSsl, "Invalid store context (nullptr)");
+ return 0;
+ }
+
+ if (!ok) {
+ // "Whenever a X509_STORE_CTX object is created for the verification of the
+ // peer's certificate during a handshake, a pointer to the SSL object is
+ // stored into the X509_STORE_CTX object to identify the connection affected.
+ // To retrieve this pointer the X509_STORE_CTX_get_ex_data() function can be
+ // used with the correct index."
+ SSL *ssl = static_cast<SSL *>(q_X509_STORE_CTX_get_ex_data(ctx, q_SSL_get_ex_data_X509_STORE_CTX_idx()));
+ if (!ssl) {
+ qCWarning(lcSsl, "No external data (SSL) found in X509 store object");
+ return 0;
+ }
+
+ const auto offset = QSslSocketBackendPrivate::s_indexForSSLExtraData
+ + QSslSocketBackendPrivate::socketOffsetInExData;
+ auto privateSocket = static_cast<QSslSocketBackendPrivate *>(q_SSL_get_ex_data(ssl, offset));
+ if (!privateSocket) {
+ qCWarning(lcSsl, "No external data (QSslSocketBackendPrivate) found in SSL object");
+ return 0;
+ }
+
+ return privateSocket->emitErrorFromCallback(ctx);
+ }
+ return 1;
+}
+
+} // extern "C"
+
Q_GLOBAL_STATIC(QRecursiveMutex, qt_opensslInitMutex)
bool QSslSocketPrivate::s_libraryLoaded = false;
@@ -250,11 +367,7 @@ QSslCipher QSslSocketBackendPrivate::QSslCipher_from_SSL_CIPHER(const SSL_CIPHER
QString protoString = descriptionList.at(1).toString();
ciph.d->protocolString = protoString;
ciph.d->protocol = QSsl::UnknownProtocol;
- if (protoString == QLatin1String("SSLv3"))
- ciph.d->protocol = QSsl::SslV3;
- else if (protoString == QLatin1String("SSLv2"))
- ciph.d->protocol = QSsl::SslV2;
- else if (protoString == QLatin1String("TLSv1"))
+ if (protoString == QLatin1String("TLSv1"))
ciph.d->protocol = QSsl::TlsV1_0;
else if (protoString == QLatin1String("TLSv1.1"))
ciph.d->protocol = QSsl::TlsV1_1;
@@ -409,12 +522,15 @@ int q_X509Callback(int ok, X509_STORE_CTX *ctx)
// Not found on store? Try SSL and its external data then. According to the OpenSSL's
// documentation:
//
- // "Whenever a X509_STORE_CTX object is created for the verification of the peers certificate
- // during a handshake, a pointer to the SSL object is stored into the X509_STORE_CTX object
- // to identify the connection affected. To retrieve this pointer the X509_STORE_CTX_get_ex_data()
- // function can be used with the correct index."
+ // "Whenever a X509_STORE_CTX object is created for the verification of the
+ // peer's certificate during a handshake, a pointer to the SSL object is
+ // stored into the X509_STORE_CTX object to identify the connection affected.
+ // To retrieve this pointer the X509_STORE_CTX_get_ex_data() function can be
+ // used with the correct index."
+ const auto offset = QSslSocketBackendPrivate::s_indexForSSLExtraData
+ + QSslSocketBackendPrivate::errorOffsetInExData;
if (SSL *ssl = static_cast<SSL *>(q_X509_STORE_CTX_get_ex_data(ctx, q_SSL_get_ex_data_X509_STORE_CTX_idx())))
- errors = ErrorListPtr(q_SSL_get_ex_data(ssl, QSslSocketBackendPrivate::s_indexForSSLExtraData + 1));
+ errors = ErrorListPtr(q_SSL_get_ex_data(ssl, offset));
}
if (!errors) {
@@ -460,20 +576,23 @@ void q_setDefaultDtlsCiphers(const QList<QSslCipher> &ciphers);
long QSslSocketBackendPrivate::setupOpenSslOptions(QSsl::SslProtocol protocol, QSsl::SslOptions sslOptions)
{
long options;
- if (protocol == QSsl::TlsV1SslV3)
- options = SSL_OP_ALL|SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3;
- else if (protocol == QSsl::SecureProtocols)
- options = SSL_OP_ALL|SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3;
- else if (protocol == QSsl::TlsV1_0OrLater)
- options = SSL_OP_ALL|SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3;
- else if (protocol == QSsl::TlsV1_1OrLater)
- options = SSL_OP_ALL|SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3|SSL_OP_NO_TLSv1;
- else if (protocol == QSsl::TlsV1_2OrLater)
- options = SSL_OP_ALL|SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3|SSL_OP_NO_TLSv1|SSL_OP_NO_TLSv1_1;
- else if (protocol == QSsl::TlsV1_3OrLater)
- options = SSL_OP_ALL|SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3|SSL_OP_NO_TLSv1|SSL_OP_NO_TLSv1_1|SSL_OP_NO_TLSv1_2;
- else
+ switch (protocol) {
+ case QSsl::SecureProtocols:
+ case QSsl::TlsV1_0OrLater:
+ options = SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3;
+ break;
+ case QSsl::TlsV1_1OrLater:
+ options = SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1;
+ break;
+ case QSsl::TlsV1_2OrLater:
+ options = SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1;
+ break;
+ case QSsl::TlsV1_3OrLater:
+ options = SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1 | SSL_OP_NO_TLSv1_2;
+ break;
+ default:
options = SSL_OP_ALL;
+ }
// This option is disabled by default, so we need to be able to clear it
if (sslOptions & QSsl::SslOptionDisableEmptyFragments)
@@ -531,10 +650,7 @@ bool QSslSocketBackendPrivate::initSslContext()
return false;
}
- if (configuration.protocol != QSsl::SslV2 &&
- configuration.protocol != QSsl::SslV3 &&
- configuration.protocol != QSsl::UnknownProtocol &&
- mode == QSslSocket::SslClientMode) {
+ if (configuration.protocol != QSsl::UnknownProtocol && mode == QSslSocket::SslClientMode) {
// Set server hostname on TLS extension. RFC4366 section 3.1 requires it in ACE format.
QString tlsHostName = verificationPeerName.isEmpty() ? q->peerName() : verificationPeerName;
if (tlsHostName.isEmpty())
@@ -1200,18 +1316,32 @@ bool QSslSocketBackendPrivate::startHandshake()
if (inSetAndEmitError)
return false;
+ pendingFatalAlert = false;
+ errorsReportedFromCallback = false;
QVector<QSslErrorEntry> lastErrors;
- q_SSL_set_ex_data(ssl, s_indexForSSLExtraData + 1, &lastErrors);
+ q_SSL_set_ex_data(ssl, s_indexForSSLExtraData + errorOffsetInExData, &lastErrors);
+
+ // SSL_set_ex_data can fail, but see the callback's code - we handle this there.
+ q_SSL_set_ex_data(ssl, s_indexForSSLExtraData + socketOffsetInExData, this);
+ q_SSL_set_info_callback(ssl, qt_AlertInfoCallback);
+
int result = (mode == QSslSocket::SslClientMode) ? q_SSL_connect(ssl) : q_SSL_accept(ssl);
- q_SSL_set_ex_data(ssl, s_indexForSSLExtraData + 1, nullptr);
+ q_SSL_set_ex_data(ssl, s_indexForSSLExtraData + errorOffsetInExData, nullptr);
+ // Note, unlike errors as external data on SSL object, we do not unset
+ // a callback/ex-data if alert notifications are enabled: an alert can
+ // arrive after the handshake, for example, this happens when the server
+ // does not find a ClientCert or does not like it.
- if (!lastErrors.isEmpty())
+ if (!lastErrors.isEmpty() || errorsReportedFromCallback)
storePeerCertificates();
- for (const auto &currentError : qAsConst(lastErrors)) {
- emit q->peerVerifyError(_q_OpenSSL_to_QSslError(currentError.code,
- configuration.peerCertificateChain.value(currentError.depth)));
- if (q->state() != QAbstractSocket::ConnectedState)
- break;
+
+ if (!errorsReportedFromCallback) {
+ for (const auto &currentError : qAsConst(lastErrors)) {
+ emit q->peerVerifyError(_q_OpenSSL_to_QSslError(currentError.code,
+ configuration.peerCertificateChain.value(currentError.depth)));
+ if (q->state() != QAbstractSocket::ConnectedState)
+ break;
+ }
}
errorList << lastErrors;
@@ -1235,6 +1365,10 @@ bool QSslSocketBackendPrivate::startHandshake()
{
const ScopedBool bg(inSetAndEmitError, true);
setErrorAndEmit(QAbstractSocket::SslHandshakeFailedError, errorString);
+ if (pendingFatalAlert) {
+ trySendFatalAlert();
+ pendingFatalAlert = false;
+ }
}
q->abort();
}
@@ -1704,6 +1838,88 @@ bool QSslSocketBackendPrivate::checkOcspStatus()
#endif // ocsp
+void QSslSocketBackendPrivate::alertMessageSent(int value)
+{
+ Q_Q(QSslSocket);
+
+ const auto level = tlsAlertLevel(value);
+ if (level == QAlertLevel::Fatal && !connectionEncrypted) {
+ // Note, this logic is handshake-time only:
+ pendingFatalAlert = true;
+ }
+
+ emit q->alertSent(level, tlsAlertType(value), tlsAlertDescription(value));
+}
+
+void QSslSocketBackendPrivate::alertMessageReceived(int value)
+{
+ Q_Q(QSslSocket);
+
+ emit q->alertReceived(tlsAlertLevel(value), tlsAlertType(value), tlsAlertDescription(value));
+}
+
+int QSslSocketBackendPrivate::emitErrorFromCallback(X509_STORE_CTX *ctx)
+{
+ // Returns 0 to abort verification, 1 to continue despite error (as
+ // OpenSSL expects from the verification callback).
+ Q_Q(QSslSocket);
+
+ Q_ASSERT(ctx);
+
+ using ScopedBool = QScopedValueRollback<bool>;
+ // While we are not setting, we are emitting and in general -
+ // we want to prevent accidental recursive startHandshake()
+ // calls:
+ const ScopedBool bg(inSetAndEmitError, true);
+
+ X509 *x509 = q_X509_STORE_CTX_get_current_cert(ctx);
+ if (!x509) {
+ qCWarning(lcSsl, "Could not obtain the certificate (that failed to verify)");
+ return 0;
+ }
+ const QSslCertificate certificate = QSslCertificatePrivate::QSslCertificate_from_X509(x509);
+
+ const auto errorAndDepth = QSslErrorEntry::fromStoreContext(ctx);
+ const QSslError tlsError = _q_OpenSSL_to_QSslError(errorAndDepth.code, certificate);
+
+ errorsReportedFromCallback = true;
+ handshakeInterrupted = true;
+ emit q->handshakeInterruptedOnError(tlsError);
+
+ // Conveniently so, we also can access 'lastErrors' external data set
+ // in startHandshake, we store it for the case an application later
+ // wants to check errors (ignored or not):
+ const auto offset = QSslSocketBackendPrivate::s_indexForSSLExtraData
+ + QSslSocketBackendPrivate::errorOffsetInExData;
+ if (auto errorList = static_cast<QVector<QSslErrorEntry>*>(q_SSL_get_ex_data(ssl, offset)))
+ errorList->append(errorAndDepth);
+
+ // An application is expected to ignore this error (by calling ignoreSslErrors)
+ // in its directly connected slot:
+ return !handshakeInterrupted;
+}
+
+void QSslSocketBackendPrivate::trySendFatalAlert()
+{
+ Q_ASSERT(pendingFatalAlert);
+
+ pendingFatalAlert = false;
+ QVarLengthArray<char, 4096> data;
+ int pendingBytes = 0;
+ while (plainSocket->isValid() && (pendingBytes = q_BIO_pending(writeBio)) > 0
+ && plainSocket->openMode() != QIODevice::NotOpen) {
+ // Read encrypted data from the write BIO into a buffer.
+ data.resize(pendingBytes);
+ const int bioReadBytes = q_BIO_read(writeBio, data.data(), pendingBytes);
+
+ // Write encrypted data from the buffer to the socket.
+ qint64 actualWritten = plainSocket->write(data.constData(), bioReadBytes);
+ if (actualWritten < 0)
+ return;
+ plainSocket->flush();
+ }
+}
+
void QSslSocketBackendPrivate::disconnectFromHost()
{
if (ssl) {
@@ -1747,10 +1963,6 @@ QSsl::SslProtocol QSslSocketBackendPrivate::sessionProtocol() const
int ver = q_SSL_version(ssl);
switch (ver) {
- case 0x2:
- return QSsl::SslV2;
- case 0x300:
- return QSsl::SslV3;
case 0x301:
return QSsl::TlsV1_0;
case 0x302:
diff --git a/src/network/ssl/qsslsocket_openssl_p.h b/src/network/ssl/qsslsocket_openssl_p.h
index 0370a7d2ac..06af9f5974 100644
--- a/src/network/ssl/qsslsocket_openssl_p.h
+++ b/src/network/ssl/qsslsocket_openssl_p.h
@@ -131,6 +131,10 @@ public:
SSL_SESSION *session;
QVector<QSslErrorEntry> errorList;
static int s_indexForSSLExtraData; // index used in SSL_get_ex_data to get the matching QSslSocketBackendPrivate
+ enum ExDataOffset {
+ errorOffsetInExData = 1,
+ socketOffsetInExData = 2
+ };
bool inSetAndEmitError = false;
@@ -157,6 +161,15 @@ public:
bool checkOcspStatus();
#endif
+ void alertMessageSent(int encoded);
+ void alertMessageReceived(int encoded);
+
+ int emitErrorFromCallback(X509_STORE_CTX *ctx);
+ void trySendFatalAlert();
+
+ bool pendingFatalAlert = false;
+ bool errorsReportedFromCallback = false;
+
// This decription will go to setErrorAndEmit(SslHandshakeError, ocspErrorDescription)
QString ocspErrorDescription;
// These will go to sslErrors()
diff --git a/src/network/ssl/qsslsocket_openssl_symbols.cpp b/src/network/ssl/qsslsocket_openssl_symbols.cpp
index 3504924888..5b0a70d495 100644
--- a/src/network/ssl/qsslsocket_openssl_symbols.cpp
+++ b/src/network/ssl/qsslsocket_openssl_symbols.cpp
@@ -156,6 +156,10 @@ DEFINEFUNC(void, OPENSSL_sk_free, OPENSSL_STACK *a, a, return, DUMMYARG)
DEFINEFUNC2(void *, OPENSSL_sk_value, OPENSSL_STACK *a, a, int b, b, return nullptr, return)
DEFINEFUNC(int, SSL_session_reused, SSL *a, a, return 0, return)
DEFINEFUNC2(unsigned long, SSL_CTX_set_options, SSL_CTX *ctx, ctx, unsigned long op, op, return 0, return)
+using info_callback = void (*) (const SSL *ssl, int type, int val);
+DEFINEFUNC2(void, SSL_set_info_callback, SSL *ssl, ssl, info_callback cb, cb, return, return)
+DEFINEFUNC(const char *, SSL_alert_type_string, int value, value, return nullptr, return)
+DEFINEFUNC(const char *, SSL_alert_desc_string_long, int value, value, return nullptr, return)
#ifdef TLS1_3_VERSION
DEFINEFUNC2(int, SSL_CTX_set_ciphersuites, SSL_CTX *ctx, ctx, const char *str, str, return 0, return)
DEFINEFUNC2(void, SSL_set_psk_use_session_callback, SSL *ssl, ssl, q_SSL_psk_use_session_cb_func_t callback, callback, return, DUMMYARG)
@@ -839,7 +843,9 @@ bool q_resolveOpenSslSymbols()
RESOLVEFUNC(OPENSSL_sk_value)
RESOLVEFUNC(DH_get0_pqg)
RESOLVEFUNC(SSL_CTX_set_options)
-
+ RESOLVEFUNC(SSL_set_info_callback)
+ RESOLVEFUNC(SSL_alert_type_string)
+ RESOLVEFUNC(SSL_alert_desc_string_long)
#ifdef TLS1_3_VERSION
RESOLVEFUNC(SSL_CTX_set_ciphersuites)
RESOLVEFUNC(SSL_set_psk_use_session_callback)
diff --git a/src/network/ssl/qsslsocket_openssl_symbols_p.h b/src/network/ssl/qsslsocket_openssl_symbols_p.h
index baf1a43113..ac6aa1760f 100644
--- a/src/network/ssl/qsslsocket_openssl_symbols_p.h
+++ b/src/network/ssl/qsslsocket_openssl_symbols_p.h
@@ -719,6 +719,10 @@ int q_OCSP_id_cmp(OCSP_CERTID *a, OCSP_CERTID *b);
void *q_CRYPTO_malloc(size_t num, const char *file, int line);
#define q_OPENSSL_malloc(num) q_CRYPTO_malloc(num, "", 0)
+void q_SSL_set_info_callback(SSL *ssl, void (*cb) (const SSL *ssl, int type, int val));
+const char *q_SSL_alert_type_string(int value);
+const char *q_SSL_alert_desc_string_long(int value);
+
QT_END_NAMESPACE
#endif
diff --git a/src/network/ssl/qsslsocket_p.h b/src/network/ssl/qsslsocket_p.h
index 1abd18bb32..4b020b6a73 100644
--- a/src/network/ssl/qsslsocket_p.h
+++ b/src/network/ssl/qsslsocket_p.h
@@ -208,6 +208,7 @@ protected:
bool paused;
bool flushTriggered;
QVector<QOcspResponse> ocspResponses;
+ bool handshakeInterrupted = false;
};
#if QT_CONFIG(securetransport) || QT_CONFIG(schannel)
diff --git a/src/network/ssl/qsslsocket_schannel.cpp b/src/network/ssl/qsslsocket_schannel.cpp
index 31b0db4818..2db5c48ff2 100644
--- a/src/network/ssl/qsslsocket_schannel.cpp
+++ b/src/network/ssl/qsslsocket_schannel.cpp
@@ -226,12 +226,6 @@ DWORD toSchannelProtocol(QSsl::SslProtocol protocol)
protocols = SP_PROT_TLS1_0 | SP_PROT_TLS1_1 | SP_PROT_TLS1_2;
// @future Add TLS 1.3 when supported by Windows!
break;
- case QSsl::SslV2:
- case QSsl::SslV3:
- return DWORD(-1); // Not supported
- case QSsl::TlsV1SslV3:
- protocols = SP_PROT_TLS1_0;
- break;
case QSsl::TlsV1_0:
protocols = SP_PROT_TLS1_0;
break;
diff --git a/src/network/ssl/qsslsocket_winrt.cpp b/src/network/ssl/qsslsocket_winrt.cpp
index f3ca3dc257..5f5201fc82 100644
--- a/src/network/ssl/qsslsocket_winrt.cpp
+++ b/src/network/ssl/qsslsocket_winrt.cpp
@@ -230,13 +230,7 @@ void QSslSocketBackendPrivate::startClientEncryption()
QSsl::SslProtocol protocol = q->protocol();
switch (q->protocol()) {
- case QSsl::SslV2:
- case QSsl::SslV3:
- setErrorAndEmit(QAbstractSocket::SslInvalidUserDataError,
- QStringLiteral("unsupported protocol"));
- return;
case QSsl::AnyProtocol:
- case QSsl::TlsV1SslV3:
protectionLevel = SocketProtectionLevel_Tls10;
break;
case QSsl::TlsV1_0:
@@ -270,7 +264,7 @@ void QSslSocketBackendPrivate::startClientEncryption()
}
// Sync custom certificates
- const QSet<QSslCertificate> caCertificates = configuration.caCertificates.toSet();
+ const QSet<QSslCertificate> caCertificates(configuration.caCertificates.constBegin(), configuration.caCertificates.constEnd());
const QSet<QSslCertificate> newCertificates = caCertificates - previousCaCertificates;
const QSet<QSslCertificate> oldCertificates = previousCaCertificates - caCertificates;
g->syncCaCertificates(newCertificates, oldCertificates);
@@ -393,7 +387,7 @@ void QSslSocketBackendPrivate::continueHandshake()
hr = control2->get_IgnorableServerCertificateErrors(&ignoreList);
Q_ASSERT_SUCCEEDED(hr);
- QSet<QSslError> ignoreErrors = ignoreErrorsList.toSet();
+ QSet<QSslError> ignoreErrors(ignoreErrorsList.constBegin(), ignoreErrorsList.constEnd());
for (int i = ChainValidationResult_Untrusted; i < ChainValidationResult_OtherErrors + 1; ++i) {
// Populate the native ignore list - break to add, continue to skip
switch (i) {
@@ -596,7 +590,7 @@ HRESULT QSslSocketBackendPrivate::onSslUpgrade(IAsyncAction *action, AsyncStatus
}
}
- sslErrors = errors.toList();
+ sslErrors = QList<QSslError>(errors.constBegin(), errors.constEnd());
// Peer validation
if (!configuration.peerCertificate.isNull()) {