diff options
-rw-r--r-- | src/network/access/qhttp2protocolhandler.cpp | 25 | ||||
-rw-r--r-- | src/network/access/qhttp2protocolhandler_p.h | 2 | ||||
-rw-r--r-- | src/network/access/qhttpnetworkconnectionchannel.cpp | 13 |
3 files changed, 39 insertions, 1 deletions
diff --git a/src/network/access/qhttp2protocolhandler.cpp b/src/network/access/qhttp2protocolhandler.cpp index 5d7fc7506e..6609aa0594 100644 --- a/src/network/access/qhttp2protocolhandler.cpp +++ b/src/network/access/qhttp2protocolhandler.cpp @@ -55,6 +55,8 @@ #include <QtNetwork/qnetworkproxy.h> #endif +#include <qcoreapplication.h> + #include <algorithm> #include <vector> @@ -211,6 +213,29 @@ QHttp2ProtocolHandler::QHttp2ProtocolHandler(QHttpNetworkConnectionChannel *chan } } +void QHttp2ProtocolHandler::handleConnectionClosure() +{ + // The channel has just received RemoteHostClosedError and since it will + // not try (for HTTP/2) to re-connect, it's time to finish all replies + // with error. + + // Maybe we still have some data to read and can successfully finish + // a stream/request? + _q_receiveReply(); + + // Finish all still active streams. If we previously had GOAWAY frame, + // we probably already closed some (or all) streams with ContentReSend + // error, but for those still active, not having any data to finish, + // we now report RemoteHostClosedError. + const auto errorString = QCoreApplication::translate("QHttp", "Connection closed"); + for (auto it = activeStreams.begin(), eIt = activeStreams.end(); it != eIt; ++it) + finishStreamWithError(it.value(), QNetworkReply::RemoteHostClosedError, errorString); + + // Make sure we'll never try to read anything later: + activeStreams.clear(); + goingAway = true; +} + void QHttp2ProtocolHandler::_q_uploadDataReadyRead() { if (!sender()) // QueuedConnection, firing after sender (byte device) was deleted. diff --git a/src/network/access/qhttp2protocolhandler_p.h b/src/network/access/qhttp2protocolhandler_p.h index 9165808302..d91853f613 100644 --- a/src/network/access/qhttp2protocolhandler_p.h +++ b/src/network/access/qhttp2protocolhandler_p.h @@ -90,6 +90,8 @@ public: QHttp2ProtocolHandler &operator = (const QHttp2ProtocolHandler &rhs) = delete; QHttp2ProtocolHandler &operator = (QHttp2ProtocolHandler &&rhs) = delete; + Q_INVOKABLE void handleConnectionClosure(); + private slots: void _q_uploadDataReadyRead(); void _q_replyDestroyed(QObject* reply); diff --git a/src/network/access/qhttpnetworkconnectionchannel.cpp b/src/network/access/qhttpnetworkconnectionchannel.cpp index e7af7b648e..1fac24ab49 100644 --- a/src/network/access/qhttpnetworkconnectionchannel.cpp +++ b/src/network/access/qhttpnetworkconnectionchannel.cpp @@ -967,7 +967,18 @@ void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socket if (!reply && state == QHttpNetworkConnectionChannel::IdleState) { // Not actually an error, it is normal for Keep-Alive connections to close after some time if no request // is sent on them. No need to error the other replies below. Just bail out here. - // The _q_disconnected will handle the possibly pipelined replies + // The _q_disconnected will handle the possibly pipelined replies. HTTP/2 is special for now, + // 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 (connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2Direct + || connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2) { + auto h2Handler = static_cast<QHttp2ProtocolHandler *>(protocolHandler.data()); + h2Handler->handleConnectionClosure(); + protocolHandler.reset(); + } + } return; } else if (state != QHttpNetworkConnectionChannel::IdleState && state != QHttpNetworkConnectionChannel::ReadingState) { // Try to reconnect/resend before sending an error. |