summaryrefslogtreecommitdiffstats
path: root/src/network/access/qnetworkaccesshttpbackend.cpp
diff options
context:
space:
mode:
authorMarkus Goetz <markus@woboq.com>2015-04-28 09:57:36 (GMT)
committerDaniel Molkentin (ownCloud) <danimo@owncloud.com>2015-04-28 18:01:16 (GMT)
commitfa81aa6d027049e855b76f5408586a288f160575 (patch)
tree72007f902f5db5ee78703d3beedff0534260f31f /src/network/access/qnetworkaccesshttpbackend.cpp
parentec701869f5c7f70608e71331223b22454c3a3e4c (diff)
downloadQt-fa81aa6d027049e855b76f5408586a288f160575.zip
Qt-fa81aa6d027049e855b76f5408586a288f160575.tar.gz
Qt-fa81aa6d027049e855b76f5408586a288f160575.tar.bz2
QNAM: Fix upload corruptions when server closes connection
This patch fixes several upload corruptions if the server closes the connection while/before we send data into it. They happen inside multiple places in the HTTP layer and are explained in the comments. Corruptions are: * The upload byte device has an in-flight signal with pending upload data, if it gets reset (because server closes the connection) then the re-send of the request was sometimes taking this stale in-flight pending upload data. * Because some signals were DirectConnection and some were QueuedConnection, there was a chance that a direct signal overtakes a queued signal. The state machine then sent data down the socket which was buffered there (and sent later) although it did not match the current state of the state machine when it was actually sent. * A socket was seen as being able to have requests sent even though it was not encrypted yet. This relates to the previous corruption where data is stored inside the socket's buffer and then sent later. The included auto test produces all fixed corruptions, I detected no regressions via the other tests. This code also adds a bit of sanity checking to protect from possible further problems. [ChangeLog][QtNetwork] Fix HTTP(s) upload corruption when server closes connection (cherry picked from commit qtbase/cff39fba10ffc10ee4dcfdc66ff6528eb26462d3) Change-Id: I9793297be6cf3edfb75b65ba03b65f7a133ef194 Reviewed-by: Richard J. Moore <rich@kde.org>
Diffstat (limited to 'src/network/access/qnetworkaccesshttpbackend.cpp')
-rw-r--r--src/network/access/qnetworkaccesshttpbackend.cpp24
1 files changed, 17 insertions, 7 deletions
diff --git a/src/network/access/qnetworkaccesshttpbackend.cpp b/src/network/access/qnetworkaccesshttpbackend.cpp
index cc67258..fe2f627 100644
--- a/src/network/access/qnetworkaccesshttpbackend.cpp
+++ b/src/network/access/qnetworkaccesshttpbackend.cpp
@@ -193,6 +193,7 @@ QNetworkAccessHttpBackendFactory::create(QNetworkAccessManager::Operation op,
QNetworkAccessHttpBackend::QNetworkAccessHttpBackend()
: QNetworkAccessBackend()
, statusCode(0)
+ , uploadByteDevicePosition(false)
, pendingDownloadDataEmissions(new QAtomicInt())
, pendingDownloadProgressEmissions(new QAtomicInt())
, loadingFromCache(false)
@@ -610,9 +611,9 @@ void QNetworkAccessHttpBackend::postRequest()
forwardUploadDevice->setParent(delegate); // needed to make sure it is moved on moveToThread()
delegate->httpRequest.setUploadByteDevice(forwardUploadDevice);
- // From main thread to user thread:
- QObject::connect(this, SIGNAL(haveUploadData(QByteArray, bool, qint64)),
- forwardUploadDevice, SLOT(haveDataSlot(QByteArray, bool, qint64)), Qt::QueuedConnection);
+ // From user thread to http thread:
+ QObject::connect(this, SIGNAL(haveUploadData(qint64,QByteArray,bool,qint64)),
+ forwardUploadDevice, SLOT(haveDataSlot(qint64,QByteArray,bool,qint64)), Qt::QueuedConnection);
QObject::connect(uploadByteDevice.data(), SIGNAL(readyRead()),
forwardUploadDevice, SIGNAL(readyRead()),
Qt::QueuedConnection);
@@ -620,8 +621,8 @@ void QNetworkAccessHttpBackend::postRequest()
// From http thread to user thread:
QObject::connect(forwardUploadDevice, SIGNAL(wantData(qint64)),
this, SLOT(wantUploadDataSlot(qint64)));
- QObject::connect(forwardUploadDevice, SIGNAL(processedData(qint64)),
- this, SLOT(sentUploadDataSlot(qint64)));
+ QObject::connect(forwardUploadDevice,SIGNAL(processedData(qint64, qint64)),
+ this, SLOT(sentUploadDataSlot(qint64,qint64)));
connect(forwardUploadDevice, SIGNAL(resetData(bool*)),
this, SLOT(resetUploadDataSlot(bool*)),
Qt::BlockingQueuedConnection); // this is the only one with BlockingQueued!
@@ -915,12 +916,21 @@ void QNetworkAccessHttpBackend::replySslConfigurationChanged(const QSslConfigura
void QNetworkAccessHttpBackend::resetUploadDataSlot(bool *r)
{
*r = uploadByteDevice->reset();
+ if (*r) {
+ // reset our own position which is used for the inter-thread communication
+ uploadByteDevicePosition = 0;
+ }
}
// Coming from QNonContiguousByteDeviceThreadForwardImpl in HTTP thread
-void QNetworkAccessHttpBackend::sentUploadDataSlot(qint64 amount)
+void QNetworkAccessHttpBackend::sentUploadDataSlot(qint64 pos, qint64 amount)
{
+ if (uploadByteDevicePosition + amount != pos) {
+ // Sanity check, should not happen.
+ error(QNetworkReply::UnknownNetworkError, "");
+ }
uploadByteDevice->advanceReadPointer(amount);
+ uploadByteDevicePosition += amount;
}
// Coming from QNonContiguousByteDeviceThreadForwardImpl in HTTP thread
@@ -933,7 +943,7 @@ void QNetworkAccessHttpBackend::wantUploadDataSlot(qint64 maxSize)
QByteArray dataArray(data, currentUploadDataLength);
// Communicate back to HTTP thread
- emit haveUploadData(dataArray, uploadByteDevice->atEnd(), uploadByteDevice->size());
+ emit haveUploadData(uploadByteDevicePosition, dataArray, uploadByteDevice->atEnd(), uploadByteDevice->size());
}
/*