mirror of
https://github.com/nextcloud/desktop.git
synced 2024-12-16 19:04:43 +03:00
64 lines
3.4 KiB
Diff
64 lines
3.4 KiB
Diff
From bc32c0ebc0bc00db84ca2f28eb16ab2e5b53a1b6 Mon Sep 17 00:00:00 2001
|
|
From: Markus Goetz <markus@woboq.com>
|
|
Date: Fri, 24 Jul 2015 09:53:20 +0200
|
|
Subject: [PATCH] QNAM: Fix reply deadlocks on server closing connection
|
|
|
|
The _q_readyRead can also be called from readMoreLater() because we implemented
|
|
it so that bandwidth limited reading can be implemented.
|
|
This can lead to a race condition if the socket is closing at the specific moment
|
|
and then deadlock the channel: It will stay unusable with a zombie request.
|
|
The fix in QHttpProtocolaHandler checks if there is actually bytes available to read
|
|
from the socket and only then continue.
|
|
|
|
The fix in the HTTP channel needs to be done to properly finish the reply in
|
|
cases of a server replying with HTTP/1.0 or "Connection: close".
|
|
The delayed incovation of _q_receiveReply will properly finish up the reply.
|
|
|
|
Change-Id: I19ce2ae595f91d56386cc7406ccacc9935672b6b
|
|
Reviewed-by: Richard J. Moore <rich@kde.org>
|
|
---
|
|
src/network/access/qhttpnetworkconnectionchannel.cpp | 4 ++++
|
|
src/network/access/qhttpprotocolhandler.cpp | 7 ++++++-
|
|
2 files changed, 10 insertions(+), 1 deletion(-)
|
|
|
|
diff --git a/src/network/access/qhttpnetworkconnectionchannel.cpp b/src/network/access/qhttpnetworkconnectionchannel.cpp
|
|
index 7428f9b..257aa13 100644
|
|
--- a/src/network/access/qhttpnetworkconnectionchannel.cpp
|
|
+++ b/src/network/access/qhttpnetworkconnectionchannel.cpp
|
|
@@ -829,11 +829,15 @@ void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socket
|
|
|
|
if (!reply->d_func()->expectContent()) {
|
|
// No content expected, this is a valid way to have the connection closed by the server
|
|
+ // We need to invoke this asynchronously to make sure the state() of the socket is on QAbstractSocket::UnconnectedState
|
|
+ QMetaObject::invokeMethod(this, "_q_receiveReply", Qt::QueuedConnection);
|
|
return;
|
|
}
|
|
if (reply->contentLength() == -1 && !reply->d_func()->isChunked()) {
|
|
// There was no content-length header and it's not chunked encoding,
|
|
// so this is a valid way to have the connection closed by the server
|
|
+ // We need to invoke this asynchronously to make sure the state() of the socket is on QAbstractSocket::UnconnectedState
|
|
+ QMetaObject::invokeMethod(this, "_q_receiveReply", Qt::QueuedConnection);
|
|
return;
|
|
}
|
|
// ok, we got a disconnect even though we did not expect it
|
|
diff --git a/src/network/access/qhttpprotocolhandler.cpp b/src/network/access/qhttpprotocolhandler.cpp
|
|
index ab2e3da..a208315 100644
|
|
--- a/src/network/access/qhttpprotocolhandler.cpp
|
|
+++ b/src/network/access/qhttpprotocolhandler.cpp
|
|
@@ -237,7 +237,12 @@ void QHttpProtocolHandler::_q_readyRead()
|
|
}
|
|
|
|
if (m_channel->isSocketWaiting() || m_channel->isSocketReading()) {
|
|
- m_channel->state = QHttpNetworkConnectionChannel::ReadingState;
|
|
+ if (m_socket->bytesAvailable()) {
|
|
+ // We might get a spurious call from readMoreLater()
|
|
+ // call of the QHttpNetworkConnection even while the socket is disconnecting.
|
|
+ // Therefore check if there is actually bytes available before changing the channel state.
|
|
+ m_channel->state = QHttpNetworkConnectionChannel::ReadingState;
|
|
+ }
|
|
if (m_reply)
|
|
_q_receiveReply();
|
|
}
|
|
--
|
|
1.9.1
|
|
|