From a6500d80686b7b04aa0a9fbf2a3c084b99dda488 Mon Sep 17 00:00:00 2001 From: Jocelyn Turcotte Date: Mon, 27 Apr 2015 15:04:44 +0200 Subject: [PATCH] Work around the Qt PUT corruption bug with Qt < 5.4.2 #2425 Since QNonContiguousByteDeviceThreadForwardImpl::reset will call UploadDevice::reset with a BlockingQueuedConnection, this allows us to reset the HTTP channel along with its buffers before they get the chance to be reused with a subsequent request. --- src/libsync/propagateupload.cpp | 35 +++++++++++++++++++++++++++++++++ src/libsync/propagateupload.h | 15 ++++++++++++++ 2 files changed, 50 insertions(+) diff --git a/src/libsync/propagateupload.cpp b/src/libsync/propagateupload.cpp index ce112c9b5..4e6a308b6 100644 --- a/src/libsync/propagateupload.cpp +++ b/src/libsync/propagateupload.cpp @@ -32,6 +32,12 @@ #include "propagator_legacy.h" #endif +#if QT_VERSION < QT_VERSION_CHECK(5, 4, 2) +namespace { +const char owncloudShouldSoftCancelPropertyName[] = "owncloud-should-soft-cancel"; +} +#endif + namespace OCC { /** @@ -86,6 +92,16 @@ void PUTFileJob::start() { connect(reply(), SIGNAL(uploadProgress(qint64,qint64)), this, SIGNAL(uploadProgress(qint64,qint64))); connect(this, SIGNAL(networkActivity()), account().data(), SIGNAL(propagatorNetworkActivity())); + // For Qt versions not including https://codereview.qt-project.org/110150 + // Also do the runtime check if compiled with an old Qt but running with fixed one. +#if QT_VERSION < QT_VERSION_CHECK(4, 8, 7) + if (QLatin1String(qVersion()) < QLatin1String("4.8.7")) + connect(_device.data(), SIGNAL(wasReset()), this, SLOT(slotSoftAbort())); +#elif QT_VERSION > QT_VERSION_CHECK(5, 0, 0) && QT_VERSION < QT_VERSION_CHECK(5, 4, 2) + if (QLatin1String(qVersion()) < QLatin1String("5.4.2")) + connect(_device.data(), SIGNAL(wasReset()), this, SLOT(slotSoftAbort())); +#endif + AbstractNetworkJob::start(); } @@ -94,6 +110,13 @@ void PUTFileJob::slotTimeout() { reply()->abort(); } +#if QT_VERSION < QT_VERSION_CHECK(5, 4, 2) +void PUTFileJob::slotSoftAbort() { + reply()->setProperty(owncloudShouldSoftCancelPropertyName, true); + reply()->abort(); +} +#endif + void PollJob::start() { setTimeout(120 * 1000); @@ -471,6 +494,18 @@ void PropagateUploadFileQNAM::slotPutFinished() } QNetworkReply::NetworkError err = job->reply()->error(); + +#if QT_VERSION < QT_VERSION_CHECK(5, 4, 2) + if (err == QNetworkReply::OperationCanceledError && job->reply()->property(owncloudShouldSoftCancelPropertyName).isValid()) { + // Abort the job and try again later. + // This works around a bug in QNAM wich might reuse a non-empty buffer for the next request. + qDebug() << "Forcing job abort on HTTP connection reset with Qt < 5.4.2."; + _propagator->_anotherSyncNeeded = true; + done(SyncFileItem::SoftError, tr("Forcing job abort on HTTP connection reset with Qt < 5.4.2.")); + return; + } +#endif + if (err != QNetworkReply::NoError) { _item._httpErrorCode = job->reply()->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); if(checkForProblemsWithShared(_item._httpErrorCode, diff --git a/src/libsync/propagateupload.h b/src/libsync/propagateupload.h index 3e345fa23..f2e9b372b 100644 --- a/src/libsync/propagateupload.h +++ b/src/libsync/propagateupload.h @@ -40,11 +40,21 @@ public: bool isSequential() const Q_DECL_OVERRIDE; bool seek ( qint64 pos ) Q_DECL_OVERRIDE; +#if QT_VERSION < QT_VERSION_CHECK(5, 4, 2) + bool reset() Q_DECL_OVERRIDE { emit wasReset(); return QIODevice::reset(); } +#endif + void setBandwidthLimited(bool); bool isBandwidthLimited() { return _bandwidthLimited; } void setChoked(bool); bool isChoked() { return _choked; } void giveBandwidthQuota(qint64 bwq); + +signals: +#if QT_VERSION < QT_VERSION_CHECK(5, 4, 2) + void wasReset(); +#endif + private: // The file data @@ -95,6 +105,11 @@ public: signals: void finishedSignal(); void uploadProgress(qint64,qint64); + +private slots: +#if QT_VERSION < QT_VERSION_CHECK(5, 4, 2) + void slotSoftAbort(); +#endif }; /** -- 2.30.2