Skip to content

Commit

Permalink
Now PROPFIND can filter properties depending on the request body (acc…
Browse files Browse the repository at this point in the history
…ording to the RFC) + Add a trailing '/' to the resource path of collections (folders) in the 'DAV:href' tag (response)
  • Loading branch information
AdrienCastex committed Jun 9, 2017
1 parent 63aa8a3 commit 7af0e36
Show file tree
Hide file tree
Showing 2 changed files with 408 additions and 159 deletions.
252 changes: 177 additions & 75 deletions lib/server/commands/Propfind.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
Object.defineProperty(exports, "__esModule", { value: true });
var WebDAVRequest_1 = require("../WebDAVRequest");
var IResource_1 = require("../../resource/IResource");
var FSPath_1 = require("../../manager/FSPath");
var XML_1 = require("../../helper/XML");
var FSPath_1 = require("../../manager/FSPath");
var http = require("http");
function lockDiscovery(lockDiscoveryCache, arg, path, resource, callback) {
var cached = lockDiscoveryCache[path.toString()];
Expand Down Expand Up @@ -42,6 +42,47 @@ function lockDiscovery(lockDiscoveryCache, arg, path, resource, callback) {
});
});
}
function parseRequestBody(arg) {
var xml = XML_1.XML.parse(arg.data);
var allTrue = {
leftElements: [],
mustDisplay: function () { return true; },
mustDisplayValue: function () { return true; }
};
var onlyName = {
leftElements: [],
mustDisplay: function () { return true; },
mustDisplayValue: function () { return false; }
};
if (arg.contentLength <= 0)
return allTrue;
try {
var propfind = xml.find('DAV:propfind');
if (propfind.findIndex('DAV:propname') !== -1)
return onlyName;
if (propfind.findIndex('DAV:allprop') !== -1)
return allTrue;
var prop_1 = propfind.find('DAV:prop');
var fn = function (name) {
var index = prop_1.findIndex(name);
if (index === -1)
return false;
delete prop_1.elements[index];
return true;
};
return {
leftElements: prop_1.elements,
mustDisplay: fn,
mustDisplayValue: function () { return true; }
};
}
catch (ex) {
return allTrue;
}
}
function propstatStatus(status) {
return 'HTTP/1.1 ' + status + ' ' + http.STATUS_CODES[status];
}
function default_1(arg, callback) {
arg.getResource(function (e, resource) {
if (e || !resource) {
Expand Down Expand Up @@ -82,6 +123,7 @@ function default_1(arg, callback) {
});
}); });
function addXMLInfo(resource, multistatus, callback) {
var reqBody = parseRequestBody(arg);
var response = multistatus.ele('D:response');
var propstat = response.ele('D:propstat');
var privileges = [
Expand All @@ -91,37 +133,77 @@ function default_1(arg, callback) {
privileges.push('canSource');
arg.requireErPrivilege(privileges, resource, function (e, can) {
if (e) {
propstat.ele('D:status').add('HTTP/1.1 ' + WebDAVRequest_1.HTTPCodes.InternalServerError + ' ' + http.STATUS_CODES[WebDAVRequest_1.HTTPCodes.InternalServerError]);
propstat.ele('D:status').add(propstatStatus(WebDAVRequest_1.HTTPCodes.InternalServerError));
callback();
return;
}
if (!can) {
propstat.ele('D:status').add('HTTP/1.1 ' + WebDAVRequest_1.HTTPCodes.Forbidden + ' ' + http.STATUS_CODES[WebDAVRequest_1.HTTPCodes.Forbidden]);
propstat.ele('D:status').add(propstatStatus(WebDAVRequest_1.HTTPCodes.Forbidden));
callback();
return;
}
propstat.ele('D:status').add('HTTP/1.1 200 OK');
var prop = propstat.ele('D:prop');
var nb = 7;
var nb = 1;
function nbOut(error) {
if (nb > 0 && error) {
nb = -1;
nb = -1000;
callback(error);
return;
}
--nb;
if (nb === 0)
if (nb === 0) {
if (reqBody.leftElements.length > 0) {
var propstatError = response.ele('D:propstat');
var prop_2 = propstatError.ele('D:prop');
propstatError.ele('D:status').add(propstatStatus(WebDAVRequest_1.HTTPCodes.NotFound));
for (var i = 0; i < reqBody.leftElements.length; ++i)
if (reqBody.leftElements[i])
prop_2.ele(reqBody.leftElements[i].name);
}
callback();
}
}
resource.creationDate(function (e, ticks) { return process.nextTick(function () {
if (!e)
prop.ele('D:creationdate').add(arg.dateISO8601(ticks));
nbOut(e);
}); });
var tags = {};
function mustDisplayTag(name) {
if (reqBody.mustDisplay('DAV:' + name))
tags[name] = {
el: prop.ele('D:' + name),
value: reqBody.mustDisplayValue('DAV:' + name)
};
else
tags[name] = {
value: false
};
}
mustDisplayTag('creationdate');
mustDisplayTag('lockdiscovery');
mustDisplayTag('getetag');
mustDisplayTag('getlastmodified');
mustDisplayTag('resourcetype');
mustDisplayTag('displayname');
mustDisplayTag('supportedlock');
function displayValue(values, fn) {
if (values.constructor === String ? tags[values].value : values.some(function (n) { return tags[n].value; })) {
++nb;
process.nextTick(fn);
}
}
displayValue('creationdate', function () {
resource.creationDate(function (e, ticks) { return process.nextTick(function () {
if (!e)
tags.creationdate.el.add(arg.dateISO8601(ticks));
nbOut(e);
}); });
});
++nb;
arg.getResourcePath(resource, function (e, path) {
if (!e) {
response.ele('D:href').add(arg.fullUri(path).replace(' ', '%20'));
var lockdiscovery_1 = prop.ele('D:lockdiscovery');
if (e) {
nbOut(e);
return;
}
if (tags.lockdiscovery.value) {
++nb;
lockDiscovery(lockDiscoveryCache, arg, new FSPath_1.FSPath(path), resource, function (e, l) {
if (e) {
nbOut(e);
Expand All @@ -131,7 +213,7 @@ function default_1(arg, callback) {
for (var _i = 0, _a = l[path_1]; _i < _a.length; _i++) {
var _lock = _a[_i];
var lock = _lock;
var activelock = lockdiscovery_1.ele('D:activelock');
var activelock = tags.lockdiscovery.el.ele('D:activelock');
activelock.ele('D:lockscope').ele('D:' + lock.lockKind.scope.value.toLowerCase());
activelock.ele('D:locktype').ele('D:' + lock.lockKind.type.value.toLowerCase());
activelock.ele('D:depth').add('Infinity');
Expand All @@ -145,70 +227,90 @@ function default_1(arg, callback) {
nbOut(null);
});
}
else
nbOut(e);
resource.type(function (e, type) { return process.nextTick(function () {
if (e) {
nbOut(e);
return;
}
var p = arg.fullUri(path).replace(' ', '%20');
response.ele('D:href').add(p.lastIndexOf('/') !== p.length - 1 && type.isDirectory ? p + '/' : p);
if (tags.resourcetype.value && type.isDirectory)
tags.resourcetype.el.ele('D:collection');
if (type.isFile) {
mustDisplayTag('getcontentlength');
mustDisplayTag('getcontenttype');
if (tags.getcontenttype.value) {
++nb;
resource.mimeType(targetSource, function (e, mimeType) { return process.nextTick(function () {
if (!e)
tags.getcontenttype.el.add(mimeType);
nbOut(e);
}); });
}
if (tags.getcontentlength.value) {
++nb;
resource.size(targetSource, function (e, size) { return process.nextTick(function () {
if (!e)
tags.getcontentlength.el.add(size === undefined || size === null || size.constructor !== Number ? 0 : size);
nbOut(e);
}); });
}
}
nbOut();
}); });
});
resource.webName(function (e, name) { return process.nextTick(function () {
if (!e)
prop.ele('D:displayname').add(name ? name : '');
nbOut(e);
}); });
var supportedlock = prop.ele('D:supportedlock');
resource.getAvailableLocks(function (e, lockKinds) { return process.nextTick(function () {
if (e) {
displayValue('displayname', function () {
resource.webName(function (e, name) { return process.nextTick(function () {
if (!e)
tags.displayname.el.add(name ? name : '');
nbOut(e);
return;
}
lockKinds.forEach(function (lockKind) {
var lockentry = supportedlock.ele('D:lockentry');
var lockscope = lockentry.ele('D:lockscope');
lockscope.ele('D:' + lockKind.scope.value.toLowerCase());
var locktype = lockentry.ele('D:locktype');
locktype.ele('D:' + lockKind.type.value.toLowerCase());
});
nbOut();
}); });
resource.getProperties(function (e, properties) { return process.nextTick(function () {
if (e) {
nbOut(e);
return;
}
for (var name_1 in properties) {
var value = properties[name_1];
prop.ele(name_1).add(value);
}
nbOut();
}); });
resource.type(function (e, type) { return process.nextTick(function () {
if (e) {
nbOut(e);
return;
}
var resourcetype = prop.ele('D:resourcetype');
if (type.isDirectory)
resourcetype.ele('D:collection');
if (type.isFile) {
nb += 2;
resource.mimeType(targetSource, function (e, mimeType) { return process.nextTick(function () {
if (!e)
prop.ele('D:getcontenttype').add(mimeType);
}); });
});
displayValue('supportedlock', function () {
resource.getAvailableLocks(function (e, lockKinds) { return process.nextTick(function () {
if (e) {
nbOut(e);
}); });
resource.size(targetSource, function (e, size) { return process.nextTick(function () {
if (!e)
prop.ele('D:getcontentlength').add(size === undefined || size === null || size.constructor !== Number ? 0 : size);
return;
}
lockKinds.forEach(function (lockKind) {
var lockentry = tags.supportedlock.el.ele('D:lockentry');
var lockscope = lockentry.ele('D:lockscope');
lockscope.ele('D:' + lockKind.scope.value.toLowerCase());
var locktype = lockentry.ele('D:locktype');
locktype.ele('D:' + lockKind.type.value.toLowerCase());
});
nbOut();
}); });
});
++nb;
process.nextTick(function () {
resource.getProperties(function (e, properties) { return process.nextTick(function () {
if (e) {
nbOut(e);
}); });
}
nbOut();
}); });
resource.lastModifiedDate(function (e, lastModifiedDate) { return process.nextTick(function () {
if (!e) {
prop.ele('D:getetag').add(IResource_1.ETag.createETag(lastModifiedDate));
prop.ele('D:getlastmodified').add(new Date(lastModifiedDate).toUTCString());
}
nbOut(e);
}); });
return;
}
for (var name_1 in properties) {
if (reqBody.mustDisplay(name_1)) {
var tag = prop.ele(name_1);
if (reqBody.mustDisplayValue(name_1))
tag.add(properties[name_1]);
}
}
nbOut();
}); });
});
displayValue(['getetag', 'getlastmodified'], function () {
resource.lastModifiedDate(function (e, lastModifiedDate) { return process.nextTick(function () {
if (!e) {
if (tags.getetag.value)
tags.getetag.el.add(IResource_1.ETag.createETag(lastModifiedDate));
if (tags.getlastmodified.value)
tags.getlastmodified.el.add(new Date(lastModifiedDate).toUTCString());
}
nbOut(e);
}); });
});
nbOut();
});
}
function done(multistatus) {
Expand Down
Loading

0 comments on commit 7af0e36

Please sign in to comment.