diff options
Diffstat (limited to 'src/network/access/qhttpnetworkconnectionchannel.cpp')
-rw-r--r-- | src/network/access/qhttpnetworkconnectionchannel.cpp | 180 |
1 files changed, 77 insertions, 103 deletions
diff --git a/src/network/access/qhttpnetworkconnectionchannel.cpp b/src/network/access/qhttpnetworkconnectionchannel.cpp index c8bea484a9..e178d65356 100644 --- a/src/network/access/qhttpnetworkconnectionchannel.cpp +++ b/src/network/access/qhttpnetworkconnectionchannel.cpp @@ -1,49 +1,12 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// Copyright (C) 2014 BlackBerry Limited. All rights reserved. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #include "qhttpnetworkconnectionchannel_p.h" #include "qhttpnetworkconnection_p.h" #include "qhttp2configuration.h" #include "private/qnoncontiguousbytedevice_p.h" -#include <qpair.h> #include <qdebug.h> #include <private/qhttp2protocolhandler_p.h> @@ -58,6 +21,9 @@ #include "private/qnetconmonitor_p.h" +#include <memory> +#include <utility> + QT_BEGIN_NAMESPACE namespace @@ -125,14 +91,14 @@ void QHttpNetworkConnectionChannel::init() // After some back and forth in all the last years, this is now a DirectConnection because otherwise // the state inside the *Socket classes gets messed up, also in conjunction with the socket notifiers // which behave slightly differently on Windows vs Linux - QObject::connect(socket, SIGNAL(bytesWritten(qint64)), - this, SLOT(_q_bytesWritten(qint64)), + QObject::connect(socket, &QIODevice::bytesWritten, + this, &QHttpNetworkConnectionChannel::_q_bytesWritten, Qt::DirectConnection); - QObject::connect(socket, SIGNAL(connected()), - this, SLOT(_q_connected()), + QObject::connect(socket, &QAbstractSocket::connected, + this, &QHttpNetworkConnectionChannel::_q_connected, Qt::DirectConnection); - QObject::connect(socket, SIGNAL(readyRead()), - this, SLOT(_q_readyRead()), + QObject::connect(socket, &QIODevice::readyRead, + this, &QHttpNetworkConnectionChannel::_q_readyRead, Qt::DirectConnection); // The disconnected() and error() signals may already come @@ -142,17 +108,17 @@ void QHttpNetworkConnectionChannel::init() // but cannot be caught because the user did not have a chance yet // to connect to QNetworkReply's signals. qRegisterMetaType<QAbstractSocket::SocketError>(); - QObject::connect(socket, SIGNAL(disconnected()), - this, SLOT(_q_disconnected()), + QObject::connect(socket, &QAbstractSocket::disconnected, + this, &QHttpNetworkConnectionChannel::_q_disconnected, Qt::DirectConnection); - QObject::connect(socket, SIGNAL(errorOccurred(QAbstractSocket::SocketError)), - this, SLOT(_q_error(QAbstractSocket::SocketError)), + QObject::connect(socket, &QAbstractSocket::errorOccurred, + this, &QHttpNetworkConnectionChannel::_q_error, Qt::DirectConnection); #ifndef QT_NO_NETWORKPROXY - QObject::connect(socket, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)), - this, SLOT(_q_proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)), + QObject::connect(socket, &QAbstractSocket::proxyAuthenticationRequired, + this, &QHttpNetworkConnectionChannel::_q_proxyAuthenticationRequired, Qt::DirectConnection); #endif @@ -160,17 +126,17 @@ void QHttpNetworkConnectionChannel::init() QSslSocket *sslSocket = qobject_cast<QSslSocket*>(socket); if (sslSocket) { // won't be a sslSocket if encrypt is false - QObject::connect(sslSocket, SIGNAL(encrypted()), - this, SLOT(_q_encrypted()), + QObject::connect(sslSocket, &QSslSocket::encrypted, + this, &QHttpNetworkConnectionChannel::_q_encrypted, Qt::DirectConnection); - QObject::connect(sslSocket, SIGNAL(sslErrors(QList<QSslError>)), - this, SLOT(_q_sslErrors(QList<QSslError>)), + QObject::connect(sslSocket, &QSslSocket::sslErrors, + this, &QHttpNetworkConnectionChannel::_q_sslErrors, Qt::DirectConnection); - QObject::connect(sslSocket, SIGNAL(preSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator*)), - this, SLOT(_q_preSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator*)), + QObject::connect(sslSocket, &QSslSocket::preSharedKeyAuthenticationRequired, + this, &QHttpNetworkConnectionChannel::_q_preSharedKeyAuthenticationRequired, Qt::DirectConnection); - QObject::connect(sslSocket, SIGNAL(encryptedBytesWritten(qint64)), - this, SLOT(_q_encryptedBytesWritten(qint64)), + QObject::connect(sslSocket, &QSslSocket::encryptedBytesWritten, + this, &QHttpNetworkConnectionChannel::_q_encryptedBytesWritten, Qt::DirectConnection); if (ignoreAllSslErrors) @@ -242,7 +208,7 @@ void QHttpNetworkConnectionChannel::abort() bool QHttpNetworkConnectionChannel::sendRequest() { - Q_ASSERT(!protocolHandler.isNull()); + Q_ASSERT(protocolHandler); return protocolHandler->sendRequest(); } @@ -255,7 +221,7 @@ bool QHttpNetworkConnectionChannel::sendRequest() void QHttpNetworkConnectionChannel::sendRequestDelayed() { QMetaObject::invokeMethod(this, [this] { - Q_ASSERT(!protocolHandler.isNull()); + Q_ASSERT(protocolHandler); if (reply) protocolHandler->sendRequest(); }, Qt::ConnectionType::QueuedConnection); @@ -263,13 +229,13 @@ void QHttpNetworkConnectionChannel::sendRequestDelayed() void QHttpNetworkConnectionChannel::_q_receiveReply() { - Q_ASSERT(!protocolHandler.isNull()); + Q_ASSERT(protocolHandler); protocolHandler->_q_receiveReply(); } void QHttpNetworkConnectionChannel::_q_readyRead() { - Q_ASSERT(!protocolHandler.isNull()); + Q_ASSERT(protocolHandler); protocolHandler->_q_readyRead(); } @@ -358,9 +324,9 @@ bool QHttpNetworkConnectionChannel::ensureConnection() QHttpNetworkReply *potentialReply = connection->d_func()->predictNextRequestsReply(); if (potentialReply) { - QMetaObject::invokeMethod(potentialReply, "socketConnecting", Qt::QueuedConnection); - } else if (h2RequestsToSend.count() > 0) { - QMetaObject::invokeMethod(h2RequestsToSend.values().at(0).second, "socketConnecting", Qt::QueuedConnection); + QMetaObject::invokeMethod(potentialReply, "socketStartedConnecting", Qt::QueuedConnection); + } else if (!h2RequestsToSend.isEmpty()) { + QMetaObject::invokeMethod(std::as_const(h2RequestsToSend).first().second, "socketStartedConnecting", Qt::QueuedConnection); } #ifndef QT_NO_NETWORKPROXY @@ -378,8 +344,8 @@ bool QHttpNetworkConnectionChannel::ensureConnection() if (connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2Direct || (connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2 - && h2RequestsToSend.count() > 0)) { - value = h2RequestsToSend.first().first.headerField("user-agent"); + && !h2RequestsToSend.isEmpty())) { + value = std::as_const(h2RequestsToSend).first().first.headerField("user-agent"); } else { value = connection->d_func()->predictNextRequest().headerField("user-agent"); } @@ -388,7 +354,9 @@ bool QHttpNetworkConnectionChannel::ensureConnection() } if (!value.isEmpty()) { QNetworkProxy proxy(socket->proxy()); - proxy.setRawHeader("User-Agent", value); //detaches + auto h = proxy.headers(); + h.replaceOrAppend(QHttpHeaders::WellKnownHeader::UserAgent, value); + proxy.setHeaders(std::move(h)); socket->setProxy(proxy); } } @@ -478,18 +446,18 @@ void QHttpNetworkConnectionChannel::allDone() // trick with ProtocolHandlerDeleter, a QObject-derived class. // These dances below just make it somewhat exception-safe. // 1. Create a new owner: - QAbstractProtocolHandler *oldHandler = protocolHandler.data(); - QScopedPointer<ProtocolHandlerDeleter> deleter(new ProtocolHandlerDeleter(oldHandler)); + QAbstractProtocolHandler *oldHandler = protocolHandler.get(); + auto deleter = std::make_unique<ProtocolHandlerDeleter>(oldHandler); // 2. Retire the old one: - protocolHandler.take(); + Q_UNUSED(protocolHandler.release()); // 3. Call 'deleteLater': deleter->deleteLater(); // 3. Give up the ownerthip: - deleter.take(); + Q_UNUSED(deleter.release()); connection->fillHttp2Queue(); protocolHandler.reset(new QHttp2ProtocolHandler(this)); - QHttp2ProtocolHandler *h2c = static_cast<QHttp2ProtocolHandler *>(protocolHandler.data()); + QHttp2ProtocolHandler *h2c = static_cast<QHttp2ProtocolHandler *>(protocolHandler.get()); QMetaObject::invokeMethod(h2c, "_q_receiveReply", Qt::QueuedConnection); QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection); // If we only had one request sent with H2 allowed, we may fail to send @@ -607,7 +575,7 @@ void QHttpNetworkConnectionChannel::detectPipeliningSupport() // called when the connection broke and we need to queue some pipelined requests again void QHttpNetworkConnectionChannel::requeueCurrentlyPipelinedRequests() { - for (int i = 0; i < alreadyPipelinedRequests.length(); i++) + for (int i = 0; i < alreadyPipelinedRequests.size(); i++) connection->d_func()->requeueRequest(alreadyPipelinedRequests.at(i)); alreadyPipelinedRequests.clear(); @@ -863,7 +831,7 @@ void QHttpNetworkConnectionChannel::_q_disconnected() QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection); } state = QHttpNetworkConnectionChannel::IdleState; - if (alreadyPipelinedRequests.length()) { + if (alreadyPipelinedRequests.size()) { // If nothing was in a pipeline, no need in calling // _q_startNextRequest (which it does): requeueCurrentlyPipelinedRequests(); @@ -890,6 +858,8 @@ void QHttpNetworkConnectionChannel::_q_connected() connection->d_func()->networkLayerState = QHttpNetworkConnectionPrivate::IPv6; } connection->d_func()->networkLayerDetected(networkLayerPreference); + if (connection->d_func()->activeChannelCount > 1 && !connection->d_func()->encrypt) + QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection); } else { bool anyProtocol = networkLayerPreference == QAbstractSocket::AnyIPProtocol; if (((connection->d_func()->networkLayerState == QHttpNetworkConnectionPrivate::IPv4) @@ -942,7 +912,7 @@ void QHttpNetworkConnectionChannel::_q_connected() } else if (connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2Direct) { state = QHttpNetworkConnectionChannel::IdleState; protocolHandler.reset(new QHttp2ProtocolHandler(this)); - if (h2RequestsToSend.count() > 0) { + if (h2RequestsToSend.size() > 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); @@ -983,6 +953,10 @@ void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socket break; case QAbstractSocket::ConnectionRefusedError: errorCode = QNetworkReply::ConnectionRefusedError; +#ifndef QT_NO_NETWORKPROXY + if (connection->d_func()->networkProxy.type() != QNetworkProxy::NoProxy && !ssl) + errorCode = QNetworkReply::ProxyConnectionRefusedError; +#endif break; case QAbstractSocket::RemoteHostClosedError: // This error for SSL comes twice in a row, first from SSL layer ("The TLS/SSL connection has been closed") then from TCP layer. @@ -995,11 +969,11 @@ void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socket // we do not resend, but must report errors if any request is in progress (note, while // not in its sendRequest(), protocol handler switches the channel to IdleState, thus // this check is under this condition in 'if'): - if (protocolHandler.data()) { + if (protocolHandler) { if (connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2Direct || (connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2 && switchedToHttp2)) { - auto h2Handler = static_cast<QHttp2ProtocolHandler *>(protocolHandler.data()); + auto h2Handler = static_cast<QHttp2ProtocolHandler *>(protocolHandler.get()); h2Handler->handleConnectionClosure(); } } @@ -1064,6 +1038,9 @@ void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socket } errorCode = QNetworkReply::TimeoutError; break; + case QAbstractSocket::ProxyConnectionRefusedError: + errorCode = QNetworkReply::ProxyConnectionRefusedError; + break; case QAbstractSocket::ProxyAuthenticationRequiredError: errorCode = QNetworkReply::ProxyAuthenticationRequiredError; break; @@ -1121,16 +1098,15 @@ void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socket if (connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2 || connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2Direct) { - QList<HttpMessagePair> h2Pairs = h2RequestsToSend.values(); - for (int a = 0; a < h2Pairs.count(); ++a) { + const auto h2RequestsToSendCopy = std::exchange(h2RequestsToSend, {}); + for (const auto &httpMessagePair : h2RequestsToSendCopy) { // emit error for all replies - QHttpNetworkReply *currentReply = h2Pairs.at(a).second; + QHttpNetworkReply *currentReply = httpMessagePair.second; currentReply->d_func()->errorString = errorString; currentReply->d_func()->httpErrorCode = errorCode; Q_ASSERT(currentReply); emit currentReply->finishedWithError(errorCode, errorString); } - h2RequestsToSend.clear(); } // send the next request @@ -1154,9 +1130,9 @@ void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socket void QHttpNetworkConnectionChannel::_q_proxyAuthenticationRequired(const QNetworkProxy &proxy, QAuthenticator* auth) { if ((connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2 - && (switchedToHttp2 || h2RequestsToSend.count() > 0)) + && (switchedToHttp2 || h2RequestsToSend.size() > 0)) || connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2Direct) { - if (h2RequestsToSend.count() > 0) + if (h2RequestsToSend.size() > 0) connection->d_func()->emitProxyAuthenticationRequired(this, proxy, auth); } else { // HTTP // Need to dequeue the request before we can emit the error. @@ -1179,9 +1155,9 @@ void QHttpNetworkConnectionChannel::emitFinishedWithError(QNetworkReply::Network { if (reply) emit reply->finishedWithError(error, QHttpNetworkConnectionChannel::tr(message)); - QList<HttpMessagePair> h2Pairs = h2RequestsToSend.values(); - for (int a = 0; a < h2Pairs.count(); ++a) { - QHttpNetworkReply *currentReply = h2Pairs.at(a).second; + const auto h2RequestsToSendCopy = h2RequestsToSend; + for (const auto &httpMessagePair : h2RequestsToSendCopy) { + QHttpNetworkReply *currentReply = httpMessagePair.second; Q_ASSERT(currentReply); emit currentReply->finishedWithError(error, QHttpNetworkConnectionChannel::tr(message)); } @@ -1262,14 +1238,12 @@ void QHttpNetworkConnectionChannel::_q_encrypted() if (connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2 || connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2Direct) { - if (h2RequestsToSend.count() > 0) { + if (!h2RequestsToSend.isEmpty()) { // Similar to HTTP/1.1 counterpart below: - const auto &h2Pairs = h2RequestsToSend.values(); // (request, reply) - const auto &pair = h2Pairs.first(); + const auto &pair = std::as_const(h2RequestsToSend).first(); emit pair.second->encrypted(); // 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); } } else { // HTTP if (!reply) @@ -1282,14 +1256,14 @@ void QHttpNetworkConnectionChannel::_q_encrypted() if (reply) sendRequestDelayed(); } + QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection); } void QHttpNetworkConnectionChannel::requeueHttp2Requests() { - QList<HttpMessagePair> h2Pairs = h2RequestsToSend.values(); - for (int a = 0; a < h2Pairs.count(); ++a) - connection->d_func()->requeueRequest(h2Pairs.at(a)); - h2RequestsToSend.clear(); + const auto h2RequestsToSendCopy = std::exchange(h2RequestsToSend, {}); + for (const auto &httpMessagePair : h2RequestsToSendCopy) + connection->d_func()->requeueRequest(httpMessagePair); } void QHttpNetworkConnectionChannel::_q_sslErrors(const QList<QSslError> &errors) @@ -1308,10 +1282,10 @@ void QHttpNetworkConnectionChannel::_q_sslErrors(const QList<QSslError> &errors) } #ifndef QT_NO_SSL else { // HTTP/2 - QList<HttpMessagePair> h2Pairs = h2RequestsToSend.values(); - for (int a = 0; a < h2Pairs.count(); ++a) { + const auto h2RequestsToSendCopy = h2RequestsToSend; + for (const auto &httpMessagePair : h2RequestsToSendCopy) { // emit SSL errors for all replies - QHttpNetworkReply *currentReply = h2Pairs.at(a).second; + QHttpNetworkReply *currentReply = httpMessagePair.second; Q_ASSERT(currentReply); emit currentReply->sslErrors(errors); } @@ -1331,10 +1305,10 @@ void QHttpNetworkConnectionChannel::_q_preSharedKeyAuthenticationRequired(QSslPr if (reply) emit reply->preSharedKeyAuthenticationRequired(authenticator); } else { - QList<HttpMessagePair> h2Pairs = h2RequestsToSend.values(); - for (int a = 0; a < h2Pairs.count(); ++a) { + const auto h2RequestsToSendCopy = h2RequestsToSend; + for (const auto &httpMessagePair : h2RequestsToSendCopy) { // emit SSL errors for all replies - QHttpNetworkReply *currentReply = h2Pairs.at(a).second; + QHttpNetworkReply *currentReply = httpMessagePair.second; Q_ASSERT(currentReply); emit currentReply->preSharedKeyAuthenticationRequired(authenticator); } |