diff --git a/src/network/access/qabstractprotocolhandler_p.h b/src/network/access/qabstractprotocolhandler_p.h index da5eaeeb74c4..42925a169d34 100644 --- a/src/network/access/qabstractprotocolhandler_p.h +++ b/src/network/access/qabstractprotocolhandler_p.h @@ -17,6 +17,8 @@ #include +#include + QT_REQUIRE_CONFIG(http); QT_BEGIN_NAMESPACE @@ -34,6 +36,13 @@ public: virtual void _q_receiveReply() = 0; virtual void _q_readyRead() = 0; virtual bool sendRequest() = 0; + // Called when the reply is being destroyed and removing itself from any other internals + virtual bool tryRemoveReply(QHttpNetworkReply *reply) + { + Q_UNUSED(reply); + // base implementation is a noop + return false; + } void setReply(QHttpNetworkReply *reply); protected: diff --git a/src/network/access/qhttp2protocolhandler.cpp b/src/network/access/qhttp2protocolhandler.cpp index 87dc504ee126..a99921f52881 100644 --- a/src/network/access/qhttp2protocolhandler.cpp +++ b/src/network/access/qhttp2protocolhandler.cpp @@ -151,15 +151,6 @@ void QHttp2ProtocolHandler::handleConnectionClosure() h2Connection->handleConnectionClosure(); } -void QHttp2ProtocolHandler::_q_replyDestroyed(QObject *reply) -{ - QPointer stream = streamIDs.take(reply); - requestReplyPairs.remove(stream); - QObject::disconnect(stream, nullptr, this, nullptr); - if (stream && stream->isActive()) - stream->sendRST_STREAM(CANCEL); -} - void QHttp2ProtocolHandler::_q_uploadDataDestroyed(QObject *uploadData) { QPointer stream = streamIDs.take(uploadData); @@ -262,6 +253,25 @@ bool QHttp2ProtocolHandler::sendRequest() return true; } +/*! + \internal + This gets called during destruction of \a reply, so do not call any functions + on \a reply. We check if there is a stream associated with the reply and, + if there is, we remove the request-reply pair associated with this stream, + delete the stream and return \c{true}. Otherwise nothing happens and we + return \c{false}. +*/ +bool QHttp2ProtocolHandler::tryRemoveReply(QHttpNetworkReply *reply) +{ + QHttp2Stream *stream = streamIDs.take(reply); + if (stream) { + requestReplyPairs.remove(stream); + stream->deleteLater(); + return true; + } + return false; +} + bool QHttp2ProtocolHandler::sendHEADERS(QHttp2Stream *stream, QHttpNetworkRequest &request) { using namespace HPack; @@ -623,8 +633,6 @@ void QHttp2ProtocolHandler::connectStream(const HttpMessagePair &message, QHttp2 auto *replyPrivate = reply->d_func(); replyPrivate->connection = m_connection; replyPrivate->connectionChannel = m_channel; - connect(reply, &QObject::destroyed, this, &QHttp2ProtocolHandler::_q_replyDestroyed, - Qt::UniqueConnection); reply->setHttp2WasUsed(true); QPointer &oldStream = streamIDs[reply]; diff --git a/src/network/access/qhttp2protocolhandler_p.h b/src/network/access/qhttp2protocolhandler_p.h index ecbc6823dcfd..aca8a0b6f66b 100644 --- a/src/network/access/qhttp2protocolhandler_p.h +++ b/src/network/access/qhttp2protocolhandler_p.h @@ -61,7 +61,6 @@ public: Q_INVOKABLE void handleConnectionClosure(); private slots: - void _q_replyDestroyed(QObject *reply); void _q_uploadDataDestroyed(QObject *uploadData); private: @@ -70,6 +69,7 @@ private: void _q_readyRead() override; Q_INVOKABLE void _q_receiveReply() override; Q_INVOKABLE bool sendRequest() override; + bool tryRemoveReply(QHttpNetworkReply *reply) override; bool sendSETTINGS_ACK(); bool sendHEADERS(QHttp2Stream *stream, QHttpNetworkRequest &request); diff --git a/src/network/access/qhttpnetworkconnection.cpp b/src/network/access/qhttpnetworkconnection.cpp index cf7aad1930de..4f105af084a8 100644 --- a/src/network/access/qhttpnetworkconnection.cpp +++ b/src/network/access/qhttpnetworkconnection.cpp @@ -1002,6 +1002,13 @@ void QHttpNetworkConnectionPrivate::removeReply(QHttpNetworkReply *reply) QMetaObject::invokeMethod(q, "_q_startNextRequest", Qt::QueuedConnection); return; } + // Check if the h2 protocol handler already started processing it + if ((connectionType == QHttpNetworkConnection::ConnectionTypeHTTP2Direct + || channels[i].switchedToHttp2) + && channels[i].protocolHandler) { + if (channels[i].protocolHandler->tryRemoveReply(reply)) + return; + } } // remove from the high priority queue if (!highPriorityQueue.isEmpty()) {