Merge pull request #7056 from nextcloud/oc-28415-enable-chunking-in-authenticated-web-upload
[oc] Enable chunking for bigger files in authenticated web upload
This commit is contained in:
commit
1a2f9fe678
|
@ -55,3 +55,5 @@ $templateManager->registerTemplate('application/vnd.oasis.opendocument.spreadshe
|
||||||
'name' => $l->t('Recent'),
|
'name' => $l->t('Recent'),
|
||||||
];
|
];
|
||||||
});
|
});
|
||||||
|
|
||||||
|
\OCP\Util::connectHook('\OCP\Config', 'js', '\OCA\Files\App', 'extendJsConfig');
|
||||||
|
|
|
@ -93,7 +93,8 @@
|
||||||
direction: $('#defaultFileSortingDirection').val()
|
direction: $('#defaultFileSortingDirection').val()
|
||||||
},
|
},
|
||||||
config: this._filesConfig,
|
config: this._filesConfig,
|
||||||
enableUpload: true
|
enableUpload: true,
|
||||||
|
maxChunkSize: OC.appConfig.files && OC.appConfig.files.max_chunk_size
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
this.files.initialize();
|
this.files.initialize();
|
||||||
|
|
|
@ -220,8 +220,8 @@ OC.FileUpload.prototype = {
|
||||||
this.data.headers['If-None-Match'] = '*';
|
this.data.headers['If-None-Match'] = '*';
|
||||||
}
|
}
|
||||||
|
|
||||||
var userName = this.uploader.filesClient.getUserName();
|
var userName = this.uploader.davClient.getUserName();
|
||||||
var password = this.uploader.filesClient.getPassword();
|
var password = this.uploader.davClient.getPassword();
|
||||||
if (userName) {
|
if (userName) {
|
||||||
// copy username/password from DAV client
|
// copy username/password from DAV client
|
||||||
this.data.headers['Authorization'] =
|
this.data.headers['Authorization'] =
|
||||||
|
@ -234,7 +234,7 @@ OC.FileUpload.prototype = {
|
||||||
&& this.getFile().size > this.uploader.fileUploadParam.maxChunkSize
|
&& this.getFile().size > this.uploader.fileUploadParam.maxChunkSize
|
||||||
) {
|
) {
|
||||||
data.isChunked = true;
|
data.isChunked = true;
|
||||||
chunkFolderPromise = this.uploader.filesClient.createDirectory(
|
chunkFolderPromise = this.uploader.davClient.createDirectory(
|
||||||
'uploads/' + encodeURIComponent(OC.getCurrentUser().uid) + '/' + encodeURIComponent(this.getId())
|
'uploads/' + encodeURIComponent(OC.getCurrentUser().uid) + '/' + encodeURIComponent(this.getId())
|
||||||
);
|
);
|
||||||
// TODO: if fails, it means same id already existed, need to retry
|
// TODO: if fails, it means same id already existed, need to retry
|
||||||
|
@ -260,9 +260,18 @@ OC.FileUpload.prototype = {
|
||||||
}
|
}
|
||||||
|
|
||||||
var uid = OC.getCurrentUser().uid;
|
var uid = OC.getCurrentUser().uid;
|
||||||
return this.uploader.filesClient.move(
|
return this.uploader.davClient.move(
|
||||||
'uploads/' + encodeURIComponent(uid) + '/' + encodeURIComponent(this.getId()) + '/.file',
|
'uploads/' + encodeURIComponent(uid) + '/' + encodeURIComponent(this.getId()) + '/.file',
|
||||||
'files/' + encodeURIComponent(uid) + '/' + OC.joinPaths(this.getFullPath(), this.getFileName())
|
'files/' + encodeURIComponent(uid) + '/' + OC.joinPaths(this.getFullPath(), this.getFileName()),
|
||||||
|
true,
|
||||||
|
{'X-OC-Mtime': this.getFile().lastModified / 1000}
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
_deleteChunkFolder: function() {
|
||||||
|
// delete transfer directory for this upload
|
||||||
|
this.uploader.davClient.remove(
|
||||||
|
'uploads/' + encodeURIComponent(OC.getCurrentUser().uid) + '/' + encodeURIComponent(this.getId())
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -271,12 +280,20 @@ OC.FileUpload.prototype = {
|
||||||
*/
|
*/
|
||||||
abort: function() {
|
abort: function() {
|
||||||
if (this.data.isChunked) {
|
if (this.data.isChunked) {
|
||||||
// delete transfer directory for this upload
|
this._deleteChunkFolder();
|
||||||
this.uploader.filesClient.remove(
|
|
||||||
'uploads/' + encodeURIComponent(OC.getCurrentUser().uid) + '/' + encodeURIComponent(this.getId())
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
this.data.abort();
|
this.data.abort();
|
||||||
|
this.deleteUpload();
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fail the upload
|
||||||
|
*/
|
||||||
|
fail: function() {
|
||||||
|
this.deleteUpload();
|
||||||
|
if (this.data.isChunked) {
|
||||||
|
this._deleteChunkFolder();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -375,6 +392,13 @@ OC.Uploader.prototype = _.extend({
|
||||||
*/
|
*/
|
||||||
filesClient: null,
|
filesClient: null,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Webdav client pointing at the root "dav" endpoint
|
||||||
|
*
|
||||||
|
* @type OC.Files.Client
|
||||||
|
*/
|
||||||
|
davClient: null,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function that will allow us to know if Ajax uploads are supported
|
* Function that will allow us to know if Ajax uploads are supported
|
||||||
* @link https://github.com/New-Bamboo/example-ajax-upload/blob/master/public/index.html
|
* @link https://github.com/New-Bamboo/example-ajax-upload/blob/master/public/index.html
|
||||||
|
@ -721,6 +745,13 @@ OC.Uploader.prototype = _.extend({
|
||||||
|
|
||||||
this.fileList = options.fileList;
|
this.fileList = options.fileList;
|
||||||
this.filesClient = options.filesClient || OC.Files.getClient();
|
this.filesClient = options.filesClient || OC.Files.getClient();
|
||||||
|
this.davClient = new OC.Files.Client({
|
||||||
|
host: this.filesClient.getHost(),
|
||||||
|
root: OC.linkToRemoteBase('dav'),
|
||||||
|
useHTTPS: OC.getProtocol() === 'https',
|
||||||
|
userName: this.filesClient.getUserName(),
|
||||||
|
password: this.filesClient.getPassword()
|
||||||
|
});
|
||||||
|
|
||||||
$uploadEl = $($uploadEl);
|
$uploadEl = $($uploadEl);
|
||||||
this.$uploadEl = $uploadEl;
|
this.$uploadEl = $uploadEl;
|
||||||
|
@ -920,7 +951,7 @@ OC.Uploader.prototype = _.extend({
|
||||||
}
|
}
|
||||||
|
|
||||||
if (upload) {
|
if (upload) {
|
||||||
upload.deleteUpload();
|
upload.fail();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
|
@ -951,6 +982,10 @@ OC.Uploader.prototype = _.extend({
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (options.maxChunkSize) {
|
||||||
|
this.fileUploadParam.maxChunkSize = options.maxChunkSize;
|
||||||
|
}
|
||||||
|
|
||||||
// initialize jquery fileupload (blueimp)
|
// initialize jquery fileupload (blueimp)
|
||||||
var fileupload = this.$uploadEl.fileupload(this.fileUploadParam);
|
var fileupload = this.$uploadEl.fileupload(this.fileUploadParam);
|
||||||
|
|
||||||
|
@ -1041,7 +1076,6 @@ OC.Uploader.prototype = _.extend({
|
||||||
self.log('progress handle fileuploadstop', e, data);
|
self.log('progress handle fileuploadstop', e, data);
|
||||||
|
|
||||||
self.clear();
|
self.clear();
|
||||||
self._hideProgressBar();
|
|
||||||
self.trigger('stop', e, data);
|
self.trigger('stop', e, data);
|
||||||
});
|
});
|
||||||
fileupload.on('fileuploadfail', function(e, data) {
|
fileupload.on('fileuploadfail', function(e, data) {
|
||||||
|
@ -1096,7 +1130,7 @@ OC.Uploader.prototype = _.extend({
|
||||||
// modify the request to adjust it to our own chunking
|
// modify the request to adjust it to our own chunking
|
||||||
var upload = self.getUpload(data);
|
var upload = self.getUpload(data);
|
||||||
var range = data.contentRange.split(' ')[1];
|
var range = data.contentRange.split(' ')[1];
|
||||||
var chunkId = range.split('/')[0];
|
var chunkId = range.split('/')[0].split('-')[0];
|
||||||
data.url = OC.getRootPath() +
|
data.url = OC.getRootPath() +
|
||||||
'/remote.php/dav/uploads' +
|
'/remote.php/dav/uploads' +
|
||||||
'/' + encodeURIComponent(OC.getCurrentUser().uid) +
|
'/' + encodeURIComponent(OC.getCurrentUser().uid) +
|
||||||
|
@ -1108,7 +1142,20 @@ OC.Uploader.prototype = _.extend({
|
||||||
fileupload.on('fileuploaddone', function(e, data) {
|
fileupload.on('fileuploaddone', function(e, data) {
|
||||||
var upload = self.getUpload(data);
|
var upload = self.getUpload(data);
|
||||||
upload.done().then(function() {
|
upload.done().then(function() {
|
||||||
|
self._hideProgressBar();
|
||||||
self.trigger('done', e, upload);
|
self.trigger('done', e, upload);
|
||||||
|
}).fail(function(status) {
|
||||||
|
self._hideProgressBar();
|
||||||
|
if (status === 507) {
|
||||||
|
// not enough space
|
||||||
|
OC.Notification.show(t('files', 'Not enough free space'), {type: 'error'});
|
||||||
|
self.cancelUploads();
|
||||||
|
} else if (status === 409) {
|
||||||
|
OC.Notification.show(t('files', 'Target folder does not exist any more'), {type: 'error'});
|
||||||
|
} else {
|
||||||
|
OC.Notification.show(t('files', 'Error when assembling chunks, status code {status}', {status: status}), {type: 'error'});
|
||||||
|
}
|
||||||
|
self.trigger('fail', e, data);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
fileupload.on('fileuploaddrop', function(e, data) {
|
fileupload.on('fileuploaddrop', function(e, data) {
|
||||||
|
|
|
@ -357,7 +357,8 @@
|
||||||
this._uploader = new OC.Uploader($uploadEl, {
|
this._uploader = new OC.Uploader($uploadEl, {
|
||||||
fileList: this,
|
fileList: this,
|
||||||
filesClient: this.filesClient,
|
filesClient: this.filesClient,
|
||||||
dropZone: $('#content')
|
dropZone: $('#content'),
|
||||||
|
maxChunkSize: options.maxChunkSize
|
||||||
});
|
});
|
||||||
|
|
||||||
this.setupUploadEvents(this._uploader);
|
this.setupUploadEvents(this._uploader);
|
||||||
|
|
|
@ -54,4 +54,14 @@ class App {
|
||||||
return self::$navigationManager;
|
return self::$navigationManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function extendJsConfig($settings) {
|
||||||
|
$appConfig = json_decode($settings['array']['oc_appconfig'], true);
|
||||||
|
|
||||||
|
$maxChunkSize = (int)(\OC::$server->getConfig()->getAppValue('files', 'max_chunk_size', (10 * 1024 * 1024)));
|
||||||
|
$appConfig['files'] = [
|
||||||
|
'max_chunk_size' => $maxChunkSize
|
||||||
|
];
|
||||||
|
|
||||||
|
$settings['array']['oc_appconfig'] = json_encode($appConfig);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,6 +37,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
url += options.host + this._root;
|
url += options.host + this._root;
|
||||||
|
this._host = options.host;
|
||||||
this._defaultHeaders = options.defaultHeaders || {
|
this._defaultHeaders = options.defaultHeaders || {
|
||||||
'X-Requested-With': 'XMLHttpRequest',
|
'X-Requested-With': 'XMLHttpRequest',
|
||||||
'requesttoken': OC.requestToken
|
'requesttoken': OC.requestToken
|
||||||
|
@ -698,10 +699,11 @@
|
||||||
* @param {String} destinationPath destination path
|
* @param {String} destinationPath destination path
|
||||||
* @param {boolean} [allowOverwrite=false] true to allow overwriting,
|
* @param {boolean} [allowOverwrite=false] true to allow overwriting,
|
||||||
* false otherwise
|
* false otherwise
|
||||||
|
* @param {Object} [headers=null] additional headers
|
||||||
*
|
*
|
||||||
* @return {Promise} promise
|
* @return {Promise} promise
|
||||||
*/
|
*/
|
||||||
move: function(path, destinationPath, allowOverwrite) {
|
move: function(path, destinationPath, allowOverwrite, headers) {
|
||||||
if (!path) {
|
if (!path) {
|
||||||
throw 'Missing argument "path"';
|
throw 'Missing argument "path"';
|
||||||
}
|
}
|
||||||
|
@ -712,9 +714,9 @@
|
||||||
var self = this;
|
var self = this;
|
||||||
var deferred = $.Deferred();
|
var deferred = $.Deferred();
|
||||||
var promise = deferred.promise();
|
var promise = deferred.promise();
|
||||||
var headers = {
|
headers = _.extend({}, headers, {
|
||||||
'Destination' : this._buildUrl(destinationPath)
|
'Destination' : this._buildUrl(destinationPath)
|
||||||
};
|
});
|
||||||
|
|
||||||
if (!allowOverwrite) {
|
if (!allowOverwrite) {
|
||||||
headers.Overwrite = 'F';
|
headers.Overwrite = 'F';
|
||||||
|
@ -828,6 +830,16 @@
|
||||||
*/
|
*/
|
||||||
getBaseUrl: function() {
|
getBaseUrl: function() {
|
||||||
return this._client.baseUrl;
|
return this._client.baseUrl;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the host
|
||||||
|
*
|
||||||
|
* @since 13.0.0
|
||||||
|
* @return {String} base URL
|
||||||
|
*/
|
||||||
|
getHost: function() {
|
||||||
|
return this._host;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue