mirror of
https://github.com/nextcloud/desktop.git
synced 2025-10-26 11:17:43 +00:00
Blacklist: remember the X-Request-ID
Issue #6420 Store the X-Request-ID in the SyncFileItem and also in the blacklist. Note that for consistency reason, the X-Request-ID is also in the SyncFileItem if the request succeeds. Currently there is no UI to access it, but it can be queried with sql commands
This commit is contained in:
parent
7da4bb4c20
commit
09cacc4cd4
@ -568,7 +568,7 @@ bool SyncJournalDb::checkConnect()
|
||||
return sqlFail("prepare _deleteUploadInfoQuery", _deleteUploadInfoQuery);
|
||||
}
|
||||
|
||||
QByteArray sql("SELECT lastTryEtag, lastTryModtime, retrycount, errorstring, lastTryTime, ignoreDuration, renameTarget, errorCategory "
|
||||
QByteArray sql("SELECT lastTryEtag, lastTryModtime, retrycount, errorstring, lastTryTime, ignoreDuration, renameTarget, errorCategory, requestId "
|
||||
"FROM blacklist WHERE path=?1");
|
||||
if (Utility::fsCasePreserving()) {
|
||||
// if the file system is case preserving we have to check the blacklist
|
||||
@ -798,6 +798,16 @@ bool SyncJournalDb::updateErrorBlacklistTableStructure()
|
||||
commitInternal("update database structure: add errorCategory col");
|
||||
}
|
||||
|
||||
if (columns.indexOf("requestId") == -1) {
|
||||
SqlQuery query(_db);
|
||||
query.prepare("ALTER TABLE blacklist ADD COLUMN requestId VARCHAR(36);");
|
||||
if (!query.exec()) {
|
||||
sqlFail("updateBlacklistTableStructure: Add requestId", query);
|
||||
re = false;
|
||||
}
|
||||
commitInternal("update database structure: add errorCategory col");
|
||||
}
|
||||
|
||||
SqlQuery query(_db);
|
||||
query.prepare("CREATE INDEX IF NOT EXISTS blacklist_index ON blacklist(path collate nocase);");
|
||||
if (!query.exec()) {
|
||||
@ -1538,8 +1548,6 @@ SyncJournalErrorBlacklistRecord SyncJournalDb::errorBlacklistEntry(const QString
|
||||
if (file.isEmpty())
|
||||
return entry;
|
||||
|
||||
// SELECT lastTryEtag, lastTryModtime, retrycount, errorstring
|
||||
|
||||
if (checkConnect()) {
|
||||
_getErrorBlacklistQuery.reset_and_clear_bindings();
|
||||
_getErrorBlacklistQuery.bindValue(1, file);
|
||||
@ -1554,6 +1562,7 @@ SyncJournalErrorBlacklistRecord SyncJournalDb::errorBlacklistEntry(const QString
|
||||
entry._renameTarget = _getErrorBlacklistQuery.stringValue(6);
|
||||
entry._errorCategory = static_cast<SyncJournalErrorBlacklistRecord::Category>(
|
||||
_getErrorBlacklistQuery.intValue(7));
|
||||
entry._requestId = _getErrorBlacklistQuery.baValue(8);
|
||||
entry._file = file;
|
||||
}
|
||||
}
|
||||
@ -1673,8 +1682,8 @@ void SyncJournalDb::setErrorBlacklistEntry(const SyncJournalErrorBlacklistRecord
|
||||
|
||||
if (!_setErrorBlacklistQuery.initOrReset(QByteArrayLiteral(
|
||||
"INSERT OR REPLACE INTO blacklist "
|
||||
"(path, lastTryEtag, lastTryModtime, retrycount, errorstring, lastTryTime, ignoreDuration, renameTarget, errorCategory) "
|
||||
"VALUES ( ?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9)"), _db)) {
|
||||
"(path, lastTryEtag, lastTryModtime, retrycount, errorstring, lastTryTime, ignoreDuration, renameTarget, errorCategory, requestId) "
|
||||
"VALUES ( ?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10)"), _db)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1687,6 +1696,7 @@ void SyncJournalDb::setErrorBlacklistEntry(const SyncJournalErrorBlacklistRecord
|
||||
_setErrorBlacklistQuery.bindValue(7, item._ignoreDuration);
|
||||
_setErrorBlacklistQuery.bindValue(8, item._renameTarget);
|
||||
_setErrorBlacklistQuery.bindValue(9, item._errorCategory);
|
||||
_setErrorBlacklistQuery.bindValue(10, item._requestId);
|
||||
_setErrorBlacklistQuery.exec();
|
||||
}
|
||||
|
||||
|
||||
@ -102,6 +102,9 @@ public:
|
||||
QString _file;
|
||||
QString _renameTarget;
|
||||
|
||||
/// The last X-Request-ID of the request that failled
|
||||
QByteArray _requestId;
|
||||
|
||||
bool isValid() const;
|
||||
};
|
||||
|
||||
|
||||
@ -275,6 +275,11 @@ QByteArray AbstractNetworkJob::responseTimestamp()
|
||||
return _responseTimestamp;
|
||||
}
|
||||
|
||||
QByteArray AbstractNetworkJob::requestId()
|
||||
{
|
||||
return _reply ? _reply->request().rawHeader("X-Request-ID") : QByteArray();
|
||||
}
|
||||
|
||||
QString AbstractNetworkJob::errorString() const
|
||||
{
|
||||
if (_timedout) {
|
||||
|
||||
@ -69,6 +69,8 @@ public:
|
||||
bool followRedirects() const { return _followRedirects; }
|
||||
|
||||
QByteArray responseTimestamp();
|
||||
/* Content of the X-Request-ID header. (Only set after the request is sent) */
|
||||
QByteArray requestId();
|
||||
|
||||
qint64 timeoutMsec() const { return _timer.interval(); }
|
||||
bool timedOut() const { return _timedout; }
|
||||
|
||||
@ -139,6 +139,7 @@ static SyncJournalErrorBlacklistRecord createBlacklistEntry(
|
||||
entry._lastTryTime = Utility::qDateTimeToTime_t(QDateTime::currentDateTimeUtc());
|
||||
entry._renameTarget = item._renameTarget;
|
||||
entry._retryCount = old._retryCount + 1;
|
||||
entry._requestId = item._requestId;
|
||||
|
||||
static qint64 minBlacklistTime(getMinBlacklistTime());
|
||||
static qint64 maxBlacklistTime(qMax(getMaxBlacklistTime(), minBlacklistTime));
|
||||
|
||||
@ -590,9 +590,12 @@ void PropagateDownloadFile::slotGetFinished()
|
||||
GETFileJob *job = _job;
|
||||
ASSERT(job);
|
||||
|
||||
_item->_httpErrorCode = job->reply()->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||
_item->_responseTimeStamp = job->responseTimestamp();
|
||||
_item->_requestId = job->requestId();
|
||||
|
||||
QNetworkReply::NetworkError err = job->reply()->error();
|
||||
if (err != QNetworkReply::NoError) {
|
||||
_item->_httpErrorCode = job->reply()->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||
|
||||
// If we sent a 'Range' header and get 416 back, we want to retry
|
||||
// without the header.
|
||||
@ -671,7 +674,6 @@ void PropagateDownloadFile::slotGetFinished()
|
||||
// so make sure we have the up-to-date time
|
||||
_item->_modtime = job->lastModified();
|
||||
}
|
||||
_item->_responseTimeStamp = job->responseTimestamp();
|
||||
|
||||
_tmpFile.close();
|
||||
_tmpFile.flush();
|
||||
|
||||
@ -130,6 +130,8 @@ void PropagateRemoteDelete::slotDeleteJobFinished()
|
||||
QNetworkReply::NetworkError err = _job->reply()->error();
|
||||
const int httpStatus = _job->reply()->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||
_item->_httpErrorCode = httpStatus;
|
||||
_item->_responseTimeStamp = _job->responseTimestamp();
|
||||
_item->_requestId = _job->requestId();
|
||||
|
||||
if (err != QNetworkReply::NoError && err != QNetworkReply::ContentNotFoundError) {
|
||||
SyncFileItem::Status status = classifyError(err, _item->_httpErrorCode,
|
||||
@ -138,8 +140,6 @@ void PropagateRemoteDelete::slotDeleteJobFinished()
|
||||
return;
|
||||
}
|
||||
|
||||
_item->_responseTimeStamp = _job->responseTimestamp();
|
||||
|
||||
// A 404 reply is also considered a success here: We want to make sure
|
||||
// a file is gone from the server. It not being there in the first place
|
||||
// is ok. This will happen for files that are in the DB but not on
|
||||
|
||||
@ -193,6 +193,8 @@ void PropagateRemoteMkdir::slotMkcolJobFinished()
|
||||
|
||||
QNetworkReply::NetworkError err = _job->reply()->error();
|
||||
_item->_httpErrorCode = _job->reply()->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||
_item->_responseTimeStamp = _job->responseTimestamp();
|
||||
_item->_requestId = _job->requestId();
|
||||
|
||||
if (_item->_httpErrorCode == 405) {
|
||||
// This happens when the directory already exists. Nothing to do.
|
||||
@ -212,7 +214,6 @@ void PropagateRemoteMkdir::slotMkcolJobFinished()
|
||||
return;
|
||||
}
|
||||
|
||||
_item->_responseTimeStamp = _job->responseTimestamp();
|
||||
_item->_fileId = _job->reply()->rawHeader("OC-FileId");
|
||||
|
||||
if (_item->_fileId.isEmpty()) {
|
||||
|
||||
@ -116,6 +116,8 @@ void PropagateRemoteMove::slotMoveJobFinished()
|
||||
|
||||
QNetworkReply::NetworkError err = _job->reply()->error();
|
||||
_item->_httpErrorCode = _job->reply()->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||
_item->_responseTimeStamp = _job->responseTimestamp();
|
||||
_item->_requestId = _job->requestId();
|
||||
|
||||
if (err != QNetworkReply::NoError) {
|
||||
SyncFileItem::Status status = classifyError(err, _item->_httpErrorCode,
|
||||
@ -124,8 +126,6 @@ void PropagateRemoteMove::slotMoveJobFinished()
|
||||
return;
|
||||
}
|
||||
|
||||
_item->_responseTimeStamp = _job->responseTimestamp();
|
||||
|
||||
if (_item->_httpErrorCode != 201) {
|
||||
// Normally we expect "201 Created"
|
||||
// If it is not the case, it might be because of a proxy or gateway intercepting the request, so we must
|
||||
|
||||
@ -113,6 +113,7 @@ bool PollJob::finished()
|
||||
QNetworkReply::NetworkError err = reply()->error();
|
||||
if (err != QNetworkReply::NoError) {
|
||||
_item->_httpErrorCode = reply()->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||
_item->_requestId = requestId();
|
||||
_item->_status = classifyError(err, _item->_httpErrorCode);
|
||||
_item->_errorString = errorString();
|
||||
|
||||
|
||||
@ -185,6 +185,7 @@ void PropagateUploadFileNG::slotPropfindFinishedWithError()
|
||||
auto httpErrorCode = job->reply()->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||
auto status = classifyError(err, httpErrorCode, &propagator()->_anotherSyncNeeded);
|
||||
if (status == SyncFileItem::FatalError) {
|
||||
_item->_requestId = job->requestId();
|
||||
propagator()->_activeJobList.removeOne(this);
|
||||
abortWithError(status, job->errorStringParsingBody());
|
||||
return;
|
||||
@ -203,6 +204,7 @@ void PropagateUploadFileNG::slotDeleteJobFinished()
|
||||
const int httpStatus = job->reply()->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||
SyncFileItem::Status status = classifyError(err, httpStatus);
|
||||
if (status == SyncFileItem::FatalError) {
|
||||
_item->_requestId = job->requestId();
|
||||
abortWithError(status, job->errorString());
|
||||
return;
|
||||
} else {
|
||||
@ -262,6 +264,7 @@ void PropagateUploadFileNG::slotMkColFinished(QNetworkReply::NetworkError)
|
||||
_item->_httpErrorCode = job->reply()->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||
|
||||
if (err != QNetworkReply::NoError || _item->_httpErrorCode != 201) {
|
||||
_item->_requestId = job->requestId();
|
||||
SyncFileItem::Status status = classifyError(err, _item->_httpErrorCode,
|
||||
&propagator()->_anotherSyncNeeded);
|
||||
abortWithError(status, job->errorStringParsingBody());
|
||||
@ -368,6 +371,7 @@ void PropagateUploadFileNG::slotPutFinished()
|
||||
|
||||
if (err != QNetworkReply::NoError) {
|
||||
_item->_httpErrorCode = job->reply()->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||
_item->_requestId = job->requestId();
|
||||
commonErrorHandling(job);
|
||||
return;
|
||||
}
|
||||
@ -448,6 +452,8 @@ void PropagateUploadFileNG::slotMoveJobFinished()
|
||||
slotJobDestroyed(job); // remove it from the _jobs list
|
||||
QNetworkReply::NetworkError err = job->reply()->error();
|
||||
_item->_httpErrorCode = job->reply()->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||
_item->_responseTimeStamp = job->responseTimestamp();
|
||||
_item->_requestId = job->requestId();
|
||||
|
||||
if (err != QNetworkReply::NoError) {
|
||||
commonErrorHandling(job);
|
||||
@ -478,7 +484,6 @@ void PropagateUploadFileNG::slotMoveJobFinished()
|
||||
abortWithError(SyncFileItem::NormalError, tr("Missing ETag from server"));
|
||||
return;
|
||||
}
|
||||
_item->_responseTimeStamp = job->responseTimestamp();
|
||||
finalize();
|
||||
}
|
||||
|
||||
|
||||
@ -201,6 +201,8 @@ void PropagateUploadFileV1::slotPutFinished()
|
||||
}
|
||||
|
||||
_item->_httpErrorCode = job->reply()->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||
_item->_responseTimeStamp = job->responseTimestamp();
|
||||
_item->_requestId = job->requestId();
|
||||
QNetworkReply::NetworkError err = job->reply()->error();
|
||||
if (err != QNetworkReply::NoError) {
|
||||
commonErrorHandling(job);
|
||||
@ -306,8 +308,6 @@ void PropagateUploadFileV1::slotPutFinished()
|
||||
|
||||
_item->_etag = etag;
|
||||
|
||||
_item->_responseTimeStamp = job->responseTimestamp();
|
||||
|
||||
if (job->reply()->rawHeader("X-OC-MTime") != "accepted") {
|
||||
// X-OC-MTime is supported since owncloud 5.0. But not when chunking.
|
||||
// Normally Owncloud 6 always puts X-OC-MTime
|
||||
|
||||
@ -221,6 +221,7 @@ public:
|
||||
RemotePermissions _remotePerm;
|
||||
QString _errorString; // Contains a string only in case of error
|
||||
QByteArray _responseTimeStamp;
|
||||
QByteArray _requestId; // X-Request-Id of the failed request
|
||||
quint32 _affectedItems = 1; // the number of affected items by the operation on this item.
|
||||
// usually this value is 1, but for removes on dirs, it might be much higher.
|
||||
|
||||
|
||||
@ -51,7 +51,9 @@ private slots:
|
||||
auto &modifier = remote ? fakeFolder.remoteModifier() : fakeFolder.localModifier();
|
||||
|
||||
int counter = 0;
|
||||
fakeFolder.setServerOverride([&](QNetworkAccessManager::Operation op, const QNetworkRequest &, QIODevice *) -> QNetworkReply * {
|
||||
QByteArray reqId;
|
||||
fakeFolder.setServerOverride([&](QNetworkAccessManager::Operation op, const QNetworkRequest &req, QIODevice *) -> QNetworkReply * {
|
||||
reqId = req.rawHeader("X-Request-ID");
|
||||
if (!remote && op == QNetworkAccessManager::PutOperation)
|
||||
++counter;
|
||||
if (remote && op == QNetworkAccessManager::GetOperation)
|
||||
@ -82,6 +84,7 @@ private slots:
|
||||
QCOMPARE(entry._retryCount, 1);
|
||||
QCOMPARE(counter, 1);
|
||||
QVERIFY(entry._ignoreDuration > 0);
|
||||
QCOMPARE(entry._requestId, reqId);
|
||||
|
||||
if (remote)
|
||||
QCOMPARE(journalRecord(fakeFolder, "A")._etag, initialEtag);
|
||||
@ -102,6 +105,7 @@ private slots:
|
||||
QCOMPARE(entry._retryCount, 1);
|
||||
QCOMPARE(counter, 1);
|
||||
QVERIFY(entry._ignoreDuration > 0);
|
||||
QCOMPARE(entry._requestId, reqId);
|
||||
|
||||
if (remote)
|
||||
QCOMPARE(journalRecord(fakeFolder, "A")._etag, initialEtag);
|
||||
@ -128,6 +132,7 @@ private slots:
|
||||
QCOMPARE(entry._retryCount, 2);
|
||||
QCOMPARE(counter, 2);
|
||||
QVERIFY(entry._ignoreDuration > 0);
|
||||
QCOMPARE(entry._requestId, reqId);
|
||||
|
||||
if (remote)
|
||||
QCOMPARE(journalRecord(fakeFolder, "A")._etag, initialEtag);
|
||||
@ -149,6 +154,7 @@ private slots:
|
||||
QCOMPARE(entry._retryCount, 3);
|
||||
QCOMPARE(counter, 3);
|
||||
QVERIFY(entry._ignoreDuration > 0);
|
||||
QCOMPARE(entry._requestId, reqId);
|
||||
|
||||
if (remote)
|
||||
QCOMPARE(journalRecord(fakeFolder, "A")._etag, initialEtag);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user