diff options
3 files changed, 48 insertions, 1 deletions
diff --git a/src/network/access/qhttpnetworkconnectionchannel.cpp b/src/network/access/qhttpnetworkconnectionchannel.cpp index 0ac14c78f6..5726925cb0 100644 --- a/src/network/access/qhttpnetworkconnectionchannel.cpp +++ b/src/network/access/qhttpnetworkconnectionchannel.cpp @@ -251,6 +251,20 @@ bool QHttpNetworkConnectionChannel::sendRequest() return protocolHandler->sendRequest(); } +/* + * Invoke "protocolHandler->sendRequest" using a queued connection. + * It's used to return to the event loop before invoking sendRequest when + * there's a very real chance that the request could have been aborted + * (i.e. after having emitted 'encrypted'). + */ +void QHttpNetworkConnectionChannel::sendRequestDelayed() +{ + QMetaObject::invokeMethod(this, [this] { + Q_ASSERT(!protocolHandler.isNull()); + if (reply) + protocolHandler->sendRequest(); + }, Qt::ConnectionType::QueuedConnection); +} void QHttpNetworkConnectionChannel::_q_receiveReply() { @@ -1234,7 +1248,7 @@ void QHttpNetworkConnectionChannel::_q_encrypted() emit reply->encrypted(); } if (reply) - sendRequest(); + sendRequestDelayed(); } } diff --git a/src/network/access/qhttpnetworkconnectionchannel_p.h b/src/network/access/qhttpnetworkconnectionchannel_p.h index e9cdae5653..270b3eb9ba 100644 --- a/src/network/access/qhttpnetworkconnectionchannel_p.h +++ b/src/network/access/qhttpnetworkconnectionchannel_p.h @@ -174,6 +174,7 @@ public: void abort(); bool sendRequest(); + void sendRequestDelayed(); bool ensureConnection(); diff --git a/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp b/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp index 0ef3dc0b61..9c77e156d7 100644 --- a/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp +++ b/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp @@ -392,6 +392,7 @@ private Q_SLOTS: void ignoreSslErrorsListWithSlot_data(); void ignoreSslErrorsListWithSlot(); void encrypted(); + void abortOnEncrypted(); void sslConfiguration_data(); void sslConfiguration(); #ifdef QT_BUILD_INTERNAL @@ -6244,6 +6245,37 @@ void tst_QNetworkReply::encrypted() reply->deleteLater(); } +void tst_QNetworkReply::abortOnEncrypted() +{ + SslServer server; + server.listen(); + if (!server.isListening()) + QSKIP("Server fails to listen. Skipping since QTcpServer is covered in another test."); + + server.connect(&server, &SslServer::newEncryptedConnection, [&server]() { + connect(server.socket, &QTcpSocket::readyRead, server.socket, []() { + // This slot must not be invoked! + QVERIFY(false); + }); + }); + + QNetworkAccessManager nm; + QNetworkReply *reply = nm.get(QNetworkRequest(QUrl(QString("https://localhost:%1").arg(server.serverPort())))); + reply->ignoreSslErrors(); + + connect(reply, &QNetworkReply::encrypted, [reply, &nm]() { + reply->abort(); + nm.clearConnectionCache(); + }); + + QSignalSpy spyEncrypted(reply, &QNetworkReply::encrypted); + QTRY_COMPARE(spyEncrypted.count(), 1); + + // Wait for the socket to be closed again in order to be sure QTcpSocket::readyRead would have been emitted. + QTRY_VERIFY(server.socket != nullptr); + QTRY_COMPARE(server.socket->state(), QAbstractSocket::UnconnectedState); +} + void tst_QNetworkReply::sslConfiguration() { QNetworkRequest request(QUrl("https://" + QtNetworkSettings::serverName() + "/index.html")); |