////////////////////////////////
var keepProxy;
+ var defaultErrorMessage = 'A network error occurred: either the server was unreachable, or there is a server configuration problem. Please check your browser debug console for a more specific error message (browser security features prevent us from showing the details here).';
function SliceReader(_slice) {
var that = this;
// resolve(locator) when the block is accepted by the
// proxy.
_deferred = $.Deferred();
- goSend();
+ if (proxyUriBase().match(/^http:/) &&
+ window.location.origin.match(/^https:/)) {
+ // In this case, requests will fail, and no ajax
+ // success/fail handlers will be called (!), which
+ // will leave our status saying "uploading" and the
+ // user waiting for something to happen. Better to
+ // give up now.
+ _deferred.reject({
+ textStatus: 'error',
+ err: 'There is a server configuration problem. Proxy ' + proxyUriBase() + ' cannot be used from origin ' + window.location.origin + ' due to the browser\'s mixed-content (https/http) policy.'
+ });
+ } else {
+ goSend();
+ }
return _deferred.promise();
}
function stop() {
that.state = 'Paused';
setProgress(_readPos);
_currentUploader = null;
- _deferred.reject(reason);
+ if (_deferred)
+ _deferred.reject(reason);
}
function onUploaderProgress(sliceDone, sliceSize) {
setProgress(_readPos + sliceDone);
}
function setProgress(bytesDone) {
var kBps;
- that.progress = Math.min(100, 100 * bytesDone / that.file.size)
+ if (that.file.size == 0)
+ that.progress = 100;
+ else
+ that.progress = Math.min(100, 100 * bytesDone / that.file.size);
if (bytesDone > _startByte) {
kBps = (bytesDone - _startByte) /
(Date.now() - _startTime);
} else {
that.statistics = that.state;
}
- if (that.state === 'Uploading' || that.state === 'Uploaded') {
+ if (that.state === 'Uploaded') {
// 'Uploaded' gets reported as 'finished', which is a
// little misleading because the collection hasn't
// been updated yet. But FileUploader's portion of the
$filter('date')(Date.now(), 'shortTime');
_finishTime = Date.now();
}
- _deferred.notify();
+ if (_deferred)
+ _deferred.notify();
}
}
function QueueUploader() {
$.extend(this, {
- state: 'Idle',
+ state: 'Idle', // Idle, Running, Stopped, Failed
stateReason: null,
statusSuccess: null,
go: go,
if (_deferred) {
_deferred.reject({});
}
- if (_deferredAppend) {
- _deferredAppend.reject({});
- }
for (var i=0; i<$scope.uploadQueue.length; i++)
$scope.uploadQueue[i].stop();
onQueueProgress();
return doQueueWork();
}
function doQueueWork() {
- if (!_deferred) {
- // Queue work has been stopped.
- return;
- }
- that.stateReason = null;
// If anything is not Done, do it.
if ($scope.uploadQueue.length > 0 &&
$scope.uploadQueue[0].state !== 'Done') {
- return $scope.uploadQueue[0].go().
- then(appendToCollection, null, onQueueProgress).
- then(doQueueWork, onQueueReject);
+ if (_deferred) {
+ that.stateReason = null;
+ return $scope.uploadQueue[0].go().
+ then(appendToCollection, null, onQueueProgress).
+ then(doQueueWork, onQueueReject);
+ } else {
+ // Queue work has been stopped. Just update the
+ // view.
+ onQueueProgress();
+ return;
+ }
}
- // If everything is Done, resolve the promise and clean up.
- return onQueueResolve();
+ // If everything is Done, resolve the promise and clean
+ // up. Note this can happen even after the _deferred
+ // promise has been rejected: specifically, when stop() is
+ // called too late to prevent completion of the last
+ // upload. In that case we want to update state to "Idle",
+ // rather than leave it at "Stopped".
+ onQueueResolve();
}
function onQueueReject(reason) {
if (!_deferred) {
return;
}
+ that.state = 'Failed';
that.stateReason = (
(reason.textStatus || 'Error') +
(reason.xhr && reason.xhr.options
? (' (from ' + reason.xhr.options.url + ')')
: '') +
': ' +
- (reason.err || ''));
+ (reason.err || defaultErrorMessage));
if (reason.xhr && reason.xhr.responseText)
that.stateReason += ' -- ' + reason.xhr.responseText;
_deferred.reject(reason);
function onQueueResolve() {
that.state = 'Idle';
that.stateReason = 'Done!';
- _deferred.resolve();
+ if (_deferred)
+ _deferred.resolve();
onQueueProgress();
}
function onQueueProgress() {
then(function(collection) {
var manifestText = '';
$.each(uploads, function(_, upload) {
+ var locators = upload.locators;
+ if (locators.length === 0) {
+ // Every stream must have at least one
+ // data locator, even if it is zero bytes
+ // long:
+ locators = ['d41d8cd98f00b204e9800998ecf8427e+0'];
+ }
filename = ArvadosClient.uniqueNameForManifest(
collection.manifest_text,
'.', upload.file.name);
collection.manifest_text += '. ' +
- upload.locators.join(' ') +
+ locators.join(' ') +
' 0:' + upload.file.size.toString() + ':' +
filename +
'\n';
}
}).
then(_deferredAppend.resolve,
- _deferredAppend.reject).
+ _deferredAppend.reject);
+ return _deferredAppend.promise().
always(function() {
_deferredAppend = null;
});
- return _deferredAppend.promise();
}
}
}