From 520923b5a7670cd5fba1363968b9a6d5e815ff0a Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Mon, 22 May 2017 14:41:06 +0200 Subject: [PATCH] HTTP/2 Support We need Qt 5.9 for HTTP2 because, even if Qt 5.8 already has support for it, there is some critical bug in the HTTP2 implementation which make it unusable [ https://codereview.qt-project.org/186050 and https://codereview.qt-project.org/186066 ] When using HTTP2, we can use many more parallel network request, this is especially good for small file handling Lower the priority of the GET and PUT propagation jobs, so the quota or selective sync ui PROPFIND will not be blocked by them --- src/libsync/accessmanager.cpp | 5 +++++ src/libsync/account.h | 5 +++++ src/libsync/connectionvalidator.cpp | 10 +++++++++- src/libsync/owncloudpropagator.cpp | 12 ++++++------ src/libsync/propagatedownload.cpp | 2 ++ src/libsync/propagateupload.cpp | 2 ++ src/libsync/syncengine.cpp | 2 +- 7 files changed, 30 insertions(+), 8 deletions(-) diff --git a/src/libsync/accessmanager.cpp b/src/libsync/accessmanager.cpp index 4c19c20a1..e9f485d93 100644 --- a/src/libsync/accessmanager.cpp +++ b/src/libsync/accessmanager.cpp @@ -93,6 +93,11 @@ QNetworkReply *AccessManager::createRequest(QNetworkAccessManager::Operation op, qInfo(lcAccessManager) << op << verb << newRequest.url().toString() << "has X-Request-ID" << requestId; newRequest.setRawHeader("X-Request-ID", requestId); +#if QT_VERSION >= QT_VERSION_CHECK(5, 9, 0) + // only enable HTTP2 with Qt 5.9 because Qt 5.8.0 has too many bugs (only use one connection if the server does not support HTTP2) + newRequest.setAttribute(QNetworkRequest::HTTP2AllowedAttribute, true); +#endif + return QNetworkAccessManager::createRequest(op, newRequest, outgoingData); } diff --git a/src/libsync/account.h b/src/libsync/account.h index b34342d45..de1cd0293 100644 --- a/src/libsync/account.h +++ b/src/libsync/account.h @@ -189,6 +189,10 @@ public: /** Detects a specific bug in older server versions */ bool rootEtagChangesNotOnlySubFolderEtags(); + /** True when the server supports HTTP2 */ + bool isHttp2Supported() { return _http2Supported; } + void setHttp2Supported(bool value) { _http2Supported = value; }; + void clearCookieJar(); void lendCookieJarTo(QNetworkAccessManager *guest); QString cookieJarPath(); @@ -247,6 +251,7 @@ private: QuotaInfo *_quotaInfo; QSharedPointer _am; QScopedPointer _credentials; + bool _http2Supported = false; /// Certificates that were explicitly rejected by the user QList _rejectedCertificates; diff --git a/src/libsync/connectionvalidator.cpp b/src/libsync/connectionvalidator.cpp index 0b5897f1f..9eff065de 100644 --- a/src/libsync/connectionvalidator.cpp +++ b/src/libsync/connectionvalidator.cpp @@ -282,10 +282,18 @@ bool ConnectionValidator::setAndCheckServerVersion(const QString &version) reportResult(ServerVersionMismatch); return false; } - // We attempt to work with servers >= 5.0.0 but warn users. // Check usages of Account::serverVersionUnsupported() for details. +#if QT_VERSION >= QT_VERSION_CHECK(5, 9, 0) + // Record that the server supports HTTP/2 + if (auto job = qobject_cast(sender())) { + if (auto reply = job->reply()) { + _account->setHttp2Supported( + reply->attribute(QNetworkRequest::HTTP2WasUsedAttribute).toBool()); + } + } +#endif return true; } diff --git a/src/libsync/owncloudpropagator.cpp b/src/libsync/owncloudpropagator.cpp index 016f0cdc8..e76e00e8e 100644 --- a/src/libsync/owncloudpropagator.cpp +++ b/src/libsync/owncloudpropagator.cpp @@ -84,18 +84,18 @@ int OwncloudPropagator::maximumActiveTransferJob() // disable parallelism when there is a network limit. return 1; } - return qCeil(hardMaximumActiveJob() / 2.); + return qMax(3, qCeil(hardMaximumActiveJob() / 2.)); } /* The maximum number of active jobs in parallel */ int OwncloudPropagator::hardMaximumActiveJob() { static int max = qgetenv("OWNCLOUD_MAX_PARALLEL").toUInt(); - if (!max) { - max = 6; //default (Qt cannot do more anyway) - // TODO: increase this number when using HTTP2 - } - return max; + if (max) + return max; + if (_account->isHttp2Supported()) + return 20; + return 6; // (Qt cannot do more anyway) } PropagateItemJob::~PropagateItemJob() diff --git a/src/libsync/propagatedownload.cpp b/src/libsync/propagatedownload.cpp index b5d6ac004..2a6ca1439 100644 --- a/src/libsync/propagatedownload.cpp +++ b/src/libsync/propagatedownload.cpp @@ -118,6 +118,8 @@ void GETFileJob::start() req.setRawHeader(it.key(), it.value()); } + req.setPriority(QNetworkRequest::LowPriority); // Long downloads must not block non-propagation jobs. + if (_directDownloadUrl.isEmpty()) { sendRequest("GET", makeDavUrl(path()), req); } else { diff --git a/src/libsync/propagateupload.cpp b/src/libsync/propagateupload.cpp index 757aee1c4..1cd026627 100644 --- a/src/libsync/propagateupload.cpp +++ b/src/libsync/propagateupload.cpp @@ -79,6 +79,8 @@ void PUTFileJob::start() req.setRawHeader(it.key(), it.value()); } + req.setPriority(QNetworkRequest::LowPriority); // Long uploads must not block non-propagation jobs. + if (_url.isValid()) { sendRequest("PUT", _url, req, _device); } else { diff --git a/src/libsync/syncengine.cpp b/src/libsync/syncengine.cpp index 8fa6eb7b7..967f5ca6a 100644 --- a/src/libsync/syncengine.cpp +++ b/src/libsync/syncengine.cpp @@ -852,7 +852,7 @@ void SyncEngine::startSync() _discoveryMainThread->setParent(this); connect(this, SIGNAL(finished(bool)), _discoveryMainThread, SLOT(deleteLater())); qCInfo(lcEngine) << "Server" << account()->serverVersion() - << QString("rootEtagChangesNotOnlySubFolderEtags=%1").arg(account()->rootEtagChangesNotOnlySubFolderEtags()); + << (account()->isHttp2Supported() ? "Using HTTP/2" : ""); if (account()->rootEtagChangesNotOnlySubFolderEtags()) { connect(_discoveryMainThread, SIGNAL(etag(QString)), this, SLOT(slotRootEtagReceived(QString))); } else { -- 2.30.2