Fix race condition when preparing upload folder

Before any upload is submitted the upload is registered in a list of
known uploads; this is needed to retrieve the upload object at several
points of the upload process. When a chunked upload is submitted first a
directory to upload all the chunks is created and, once that is done,
the chunks are sent; in order to send a chunk the upload object needs to
be retrieved from the list of known uploads.

When all the active uploads were finished the list of known uploads was
cleared. However, an upload is not active until it actually starts
sending the data, so while waiting for the upload directory to be
created the upload is already in the list of known uploads yet not
active. Due to all this, if the active uploads finished while another
pending upload was waiting for the upload directory to be created that
pending upload would be removed from the list of known uploads too, and
once the directory was created and thus the chunks were sent a field of
a null upload object would be accessed thus causing a failure.

Instead of removing all the known uploads at once when the active
uploads finish now each upload is explicitly removed when it finishes.

Signed-off-by: Daniel Calviño Sánchez <danxuliu@gmail.com>
This commit is contained in:
Daniel Calviño Sánchez 2018-04-19 09:52:50 +02:00 committed by Roeland Jago Douma
parent 74b5ab8d39
commit 375a55b0ad
No known key found for this signature in database
GPG Key ID: F941078878347C0C
1 changed files with 17 additions and 1 deletions

View File

@ -576,7 +576,6 @@ OC.Uploader.prototype = _.extend({
* Clear uploads
*/
clear: function() {
this._uploads = {};
this._knownDirs = {};
},
/**
@ -595,6 +594,19 @@ OC.Uploader.prototype = _.extend({
return null;
},
/**
* Removes an upload from the list of known uploads.
*
* @param {OC.FileUpload} upload the upload to remove.
*/
removeUpload: function(upload) {
if (!upload || !upload.data || !upload.data.uploadId) {
return;
}
delete this._uploads[upload.data.uploadId];
},
showUploadCancelMessage: _.debounce(function() {
OC.Notification.show(t('files', 'Upload cancelled.'), {timeout : 7, type: 'error'});
}, 500),
@ -959,6 +971,8 @@ OC.Uploader.prototype = _.extend({
}
self.log('fail', e, upload);
self.removeUpload(upload);
if (data.textStatus === 'abort') {
self.showUploadCancelMessage();
} else if (status === 412) {
@ -996,6 +1010,8 @@ OC.Uploader.prototype = _.extend({
var that = $(this);
self.log('done', e, upload);
self.removeUpload(upload);
var status = upload.getResponseStatus();
if (status < 200 || status >= 300) {
// trigger fail handler