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
This commit is contained in:
Olivier Goffart 2017-05-22 14:41:06 +02:00 committed by Olivier Goffart
parent 2ba46e05ee
commit 520923b5a7
7 changed files with 30 additions and 8 deletions

View file

@ -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);
}

View file

@ -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<QNetworkAccessManager> _am;
QScopedPointer<AbstractCredentials> _credentials;
bool _http2Supported = false;
/// Certificates that were explicitly rejected by the user
QList<QSslCertificate> _rejectedCertificates;

View file

@ -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<AbstractNetworkJob *>(sender())) {
if (auto reply = job->reply()) {
_account->setHttp2Supported(
reply->attribute(QNetworkRequest::HTTP2WasUsedAttribute).toBool());
}
}
#endif
return true;
}

View file

@ -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
}
if (max)
return max;
if (_account->isHttp2Supported())
return 20;
return 6; // (Qt cannot do more anyway)
}
PropagateItemJob::~PropagateItemJob()

View file

@ -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 {

View file

@ -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 {

View file

@ -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 {