2016-03-12 12:22:35 +01:00
|
|
|
'use strict';
|
|
|
|
|
|
|
|
var Logger = require('../util/logger');
|
|
|
|
|
|
|
|
var logger = new Logger('storage-webdav');
|
|
|
|
|
2016-03-13 15:33:03 +01:00
|
|
|
var StorageWebDav = {
|
2016-03-12 12:22:35 +01:00
|
|
|
name: 'webdav',
|
|
|
|
icon: 'server',
|
|
|
|
enabled: true,
|
2016-03-13 17:08:25 +01:00
|
|
|
uipos: 10,
|
2016-03-12 12:22:35 +01:00
|
|
|
|
2016-03-13 17:08:25 +01:00
|
|
|
needShowOpenConfig: function() {
|
|
|
|
return true;
|
|
|
|
},
|
|
|
|
|
2016-03-13 17:45:55 +01:00
|
|
|
getOpenConfig: function() {
|
|
|
|
return {
|
|
|
|
fields: [
|
|
|
|
{id: 'path', title: 'openUrl', desc: 'openUrlDesc', type: 'text', required: true},
|
|
|
|
{id: 'user', title: 'openUser', desc: 'openUserDesc', placeholder: 'openUserPlaceholder', type: 'text'},
|
|
|
|
{id: 'password', title: 'openPass', desc: 'openPassDesc', placeholder: 'openPassPlaceholder', type: 'password'}
|
|
|
|
]
|
|
|
|
};
|
2016-03-13 17:08:25 +01:00
|
|
|
},
|
2016-03-12 12:22:35 +01:00
|
|
|
|
2016-03-12 17:49:52 +01:00
|
|
|
load: function(path, opts, callback) {
|
|
|
|
this._request({
|
|
|
|
op: 'Load',
|
|
|
|
method: 'GET',
|
|
|
|
path: path,
|
|
|
|
user: opts ? opts.user : null,
|
|
|
|
password: opts ? opts.password : null
|
|
|
|
}, callback ? function(err, xhr, stat) {
|
|
|
|
callback(err, xhr.response, stat);
|
|
|
|
} : null);
|
2016-03-12 12:22:35 +01:00
|
|
|
},
|
|
|
|
|
2016-03-12 17:49:52 +01:00
|
|
|
stat: function(path, opts, callback) {
|
|
|
|
this._request({
|
|
|
|
op: 'Stat',
|
|
|
|
method: 'HEAD',
|
|
|
|
path: path,
|
|
|
|
user: opts ? opts.user : null,
|
|
|
|
password: opts ? opts.password : null
|
|
|
|
}, callback ? function(err, xhr, stat) {
|
|
|
|
callback(err, stat);
|
|
|
|
} : null);
|
2016-03-12 12:22:35 +01:00
|
|
|
},
|
|
|
|
|
2016-03-12 17:49:52 +01:00
|
|
|
save: function(path, opts, data, callback, rev) {
|
2016-03-13 09:34:36 +01:00
|
|
|
var cb = function(err, xhr, stat) {
|
|
|
|
if (callback) {
|
|
|
|
callback(err, stat);
|
|
|
|
callback = null;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
var tmpPath = path.replace(/[^\/]+$/, function(m) { return '.' + m; }) + '.' + Date.now();
|
2016-03-12 17:49:52 +01:00
|
|
|
var saveOpts = {
|
|
|
|
path: path,
|
|
|
|
user: opts ? opts.user : null,
|
2016-03-13 09:34:36 +01:00
|
|
|
password: opts ? opts.password : null
|
2016-03-12 17:49:52 +01:00
|
|
|
};
|
2016-03-13 09:34:36 +01:00
|
|
|
var that = this;
|
|
|
|
this._request(_.defaults({
|
|
|
|
op: 'Save:stat', method: 'HEAD'
|
|
|
|
}, saveOpts), function(err, xhr, stat) {
|
|
|
|
if (err) { return cb(err); }
|
|
|
|
if (stat.rev !== rev) {
|
|
|
|
logger.debug('Save error', path, 'rev conflict', stat.rev, rev);
|
|
|
|
return cb({ revConflict: true }, xhr, stat);
|
|
|
|
}
|
|
|
|
that._request(_.defaults({
|
|
|
|
op: 'Save:put', method: 'PUT', path: tmpPath, data: data, nostat: true
|
|
|
|
}, saveOpts), function(err) {
|
2016-03-12 17:49:52 +01:00
|
|
|
if (err) { return cb(err); }
|
2016-03-13 09:34:36 +01:00
|
|
|
that._request(_.defaults({
|
|
|
|
op: 'Save:stat', method: 'HEAD'
|
|
|
|
}, saveOpts), function(err, xhr, stat) {
|
|
|
|
if (err) {
|
|
|
|
that._request(_.defaults({ op: 'Save:delete', method: 'DELETE', path: tmpPath }, saveOpts));
|
|
|
|
return cb(err, xhr, stat);
|
|
|
|
}
|
|
|
|
if (stat.rev !== rev) {
|
|
|
|
logger.debug('Save error', path, 'rev conflict', stat.rev, rev);
|
|
|
|
that._request(_.defaults({ op: 'Save:delete', method: 'DELETE', path: tmpPath }, saveOpts));
|
|
|
|
return cb({ revConflict: true }, xhr, stat);
|
|
|
|
}
|
|
|
|
that._request(_.defaults({
|
|
|
|
op: 'Save:move', method: 'MOVE', path: tmpPath, nostat: true,
|
|
|
|
headers: { Destination: path, 'Overwrite': 'T' }
|
|
|
|
}, saveOpts), function(err) {
|
|
|
|
if (err) { return cb(err); }
|
|
|
|
that._request(_.defaults({
|
|
|
|
op: 'Save:stat', method: 'HEAD'
|
|
|
|
}, saveOpts), function(err, xhr, stat) {
|
|
|
|
cb(err, xhr, stat);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
2016-03-12 17:49:52 +01:00
|
|
|
});
|
2016-03-13 09:34:36 +01:00
|
|
|
});
|
2016-03-12 17:49:52 +01:00
|
|
|
},
|
|
|
|
|
|
|
|
_request: function(config, callback) {
|
2016-03-13 09:34:36 +01:00
|
|
|
if (config.rev) {
|
|
|
|
logger.debug(config.op, config.path, config.rev);
|
|
|
|
} else {
|
|
|
|
logger.debug(config.op, config.path);
|
|
|
|
}
|
2016-03-12 12:22:35 +01:00
|
|
|
var ts = logger.ts();
|
2016-03-12 17:49:52 +01:00
|
|
|
var xhr = new XMLHttpRequest();
|
|
|
|
xhr.addEventListener('load', function() {
|
2016-03-13 09:34:36 +01:00
|
|
|
if ([200, 201, 204].indexOf(xhr.status) < 0) {
|
2016-03-12 17:49:52 +01:00
|
|
|
logger.debug(config.op + ' error', config.path, xhr.status, logger.ts(ts));
|
|
|
|
var err;
|
|
|
|
switch (xhr.status) {
|
|
|
|
case 404:
|
|
|
|
err = { notFound: true };
|
|
|
|
break;
|
|
|
|
case 412:
|
|
|
|
err = { revConflict: true };
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
err = 'HTTP status ' + xhr.status;
|
|
|
|
break;
|
|
|
|
}
|
2016-03-13 09:34:36 +01:00
|
|
|
if (callback) { callback(err, xhr); callback = null; }
|
2016-03-12 17:49:52 +01:00
|
|
|
return;
|
|
|
|
}
|
2016-03-13 09:34:36 +01:00
|
|
|
var rev = xhr.getResponseHeader('Last-Modified');
|
|
|
|
if (!rev && !config.nostat) {
|
2016-03-12 17:49:52 +01:00
|
|
|
logger.debug(config.op + ' error', config.path, 'no headers', logger.ts(ts));
|
2016-03-13 09:34:36 +01:00
|
|
|
if (callback) { callback('No Last-Modified header', xhr); callback = null; }
|
2016-03-12 17:49:52 +01:00
|
|
|
return;
|
|
|
|
}
|
2016-03-13 09:34:36 +01:00
|
|
|
var completedOpName = config.op + (config.op.charAt(config.op.length - 1) === 'e' ? 'd' : 'ed');
|
|
|
|
logger.debug(completedOpName, config.path, rev, logger.ts(ts));
|
2016-03-12 17:49:52 +01:00
|
|
|
if (callback) { callback(null, xhr, rev ? { rev: rev } : null); callback = null; }
|
|
|
|
});
|
|
|
|
xhr.addEventListener('error', function() {
|
|
|
|
logger.debug(config.op + ' error', config.path, logger.ts(ts));
|
2016-03-13 09:34:36 +01:00
|
|
|
if (callback) { callback('network error', xhr); callback = null; }
|
2016-03-12 17:49:52 +01:00
|
|
|
});
|
|
|
|
xhr.addEventListener('abort', function() {
|
|
|
|
logger.debug(config.op + ' error', config.path, 'aborted', logger.ts(ts));
|
2016-03-13 09:34:36 +01:00
|
|
|
if (callback) { callback('aborted', xhr); callback = null; }
|
2016-03-12 17:49:52 +01:00
|
|
|
});
|
|
|
|
xhr.responseType = 'arraybuffer';
|
|
|
|
xhr.open(config.method, config.path);
|
|
|
|
if (config.user) {
|
|
|
|
xhr.setRequestHeader('Authorization', 'Basic ' + btoa(config.user + ':' + config.password));
|
|
|
|
}
|
2016-03-13 09:34:36 +01:00
|
|
|
if (config.headers) {
|
|
|
|
_.forEach(config.headers, function(value, header) {
|
|
|
|
xhr.setRequestHeader(header, value);
|
|
|
|
});
|
2016-03-12 17:49:52 +01:00
|
|
|
}
|
|
|
|
if (config.data) {
|
|
|
|
var blob = new Blob([config.data], {type: 'application/octet-stream'});
|
|
|
|
xhr.send(blob);
|
|
|
|
} else {
|
|
|
|
xhr.send();
|
|
|
|
}
|
2016-03-12 12:22:35 +01:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2016-03-13 15:33:03 +01:00
|
|
|
module.exports = StorageWebDav;
|