Uploads: Don't delete unexisting chunks

Since commit 4dc49ff3, we store an entry in the upload info table even
for non chunked uploads. However, if this fails we don't want to remove
non-existant stale chunks if the upload fails.

Without this commit, we would send a DELETE command to clean non-existant
chunks in the dav/uploads/ namespace.
This commit is contained in:
Olivier Goffart 2018-04-04 17:33:14 +02:00 committed by Roeland Jago Douma
parent 27e1efb8a3
commit 012c638d4e
No known key found for this signature in database
GPG key ID: F941078878347C0C
5 changed files with 16 additions and 4 deletions

View file

@ -114,6 +114,12 @@ public:
int _errorCount;
bool _valid;
QByteArray _contentChecksum;
/**
* Returns true if this entry refers to a chunked upload that can be continued.
* (As opposed to a small file transfer which is stored in the db so we can detect the case
* when the upload succeeded, but the connection was dropped before we got the answer)
*/
bool isChunked() const { return _transferid != 0; }
};
struct PollInfo

View file

@ -83,7 +83,7 @@ void PropagateUploadFileNG::doStartUpload()
propagator()->_activeJobList.append(this);
const SyncJournalDb::UploadInfo progressInfo = propagator()->_journal->getUploadInfo(_item->_file);
if (progressInfo._valid && progressInfo._modtime == _item->_modtime) {
if (progressInfo._valid && progressInfo.isChunked() && progressInfo._modtime == _item->_modtime) {
_transferId = progressInfo._transferid;
auto url = chunkUrl();
auto job = new LsColJob(propagator()->account(), url, this);
@ -98,7 +98,7 @@ void PropagateUploadFileNG::doStartUpload()
this, &PropagateUploadFileNG::slotPropfindIterate);
job->start();
return;
} else if (progressInfo._valid) {
} else if (progressInfo._valid && progressInfo.isChunked()) {
// The upload info is stale. remove the stale chunks on the server
_transferId = progressInfo._transferid;
// Fire and forget. Any error will be ignored.

View file

@ -43,7 +43,7 @@ void PropagateUploadFileV1::doStartUpload()
const SyncJournalDb::UploadInfo progressInfo = propagator()->_journal->getUploadInfo(_item->_file);
if (progressInfo._valid && progressInfo._modtime == _item->_modtime
if (progressInfo._valid && progressInfo.isChunked() && progressInfo._modtime == _item->_modtime
&& (progressInfo._contentChecksum == _item->_checksumHeader || progressInfo._contentChecksum.isEmpty() || _item->_checksumHeader.isEmpty())) {
_startChunk = progressInfo._chunk;
_transferId = progressInfo._transferid;
@ -55,7 +55,7 @@ void PropagateUploadFileV1::doStartUpload()
SyncJournalDb::UploadInfo pi;
pi._valid = true;
pi._chunk = 0;
pi._transferid = _transferId;
pi._transferid = 0; // We set a null transfer id because it is not chunked.
pi._modtime = _item->_modtime;
pi._errorCount = 0;
pi._contentChecksum = _item->_checksumHeader;

View file

@ -303,6 +303,8 @@ void SyncEngine::deleteStaleUploadInfos(const SyncFileItemVector &syncItems)
// Delete the stales chunk on the server.
if (account()->capabilities().chunkingNg()) {
foreach (uint transferId, ids) {
if (!transferId)
continue; // Was not a chunked upload
QUrl url = Utility::concatUrlPath(account()->url(), QLatin1String("remote.php/dav/uploads/") + account()->davUser() + QLatin1Char('/') + QString::number(transferId));
(new DeleteJob(account(), url, this))->start();
}

View file

@ -389,6 +389,10 @@ private slots:
int responseDelay = AbstractNetworkJob::httpTimeout * 1000 * 1000; // much bigger than http timeout (so a timeout will occur)
// This will perform the operation on the server, but the reply will not come to the client
fakeFolder.setServerOverride([&](QNetworkAccessManager::Operation op, const QNetworkRequest &request, QIODevice *outgoingData) -> QNetworkReply * {
if (!chunking) {
Q_ASSERT(!request.url().path().contains("/uploads/")
&& "Should not touch uploads endpoint when not chunking");
}
if (!chunking && op == QNetworkAccessManager::PutOperation) {
checksumHeader = request.rawHeader("OC-Checksum");
return new DelayedReply<FakePutReply>(responseDelay, fakeFolder.remoteModifier(), op, request, outgoingData->readAll(), &fakeFolder.syncEngine());