Skip to content

Commit 7af0e36

Browse files
committed
Now PROPFIND can filter properties depending on the request body (according to the RFC) + Add a trailing '/' to the resource path of collections (folders) in the 'DAV:href' tag (response)
1 parent 63aa8a3 commit 7af0e36

File tree

2 files changed

+408
-159
lines changed

2 files changed

+408
-159
lines changed

lib/server/commands/Propfind.js

Lines changed: 177 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
Object.defineProperty(exports, "__esModule", { value: true });
33
var WebDAVRequest_1 = require("../WebDAVRequest");
44
var IResource_1 = require("../../resource/IResource");
5-
var FSPath_1 = require("../../manager/FSPath");
65
var XML_1 = require("../../helper/XML");
6+
var FSPath_1 = require("../../manager/FSPath");
77
var http = require("http");
88
function lockDiscovery(lockDiscoveryCache, arg, path, resource, callback) {
99
var cached = lockDiscoveryCache[path.toString()];
@@ -42,6 +42,47 @@ function lockDiscovery(lockDiscoveryCache, arg, path, resource, callback) {
4242
});
4343
});
4444
}
45+
function parseRequestBody(arg) {
46+
var xml = XML_1.XML.parse(arg.data);
47+
var allTrue = {
48+
leftElements: [],
49+
mustDisplay: function () { return true; },
50+
mustDisplayValue: function () { return true; }
51+
};
52+
var onlyName = {
53+
leftElements: [],
54+
mustDisplay: function () { return true; },
55+
mustDisplayValue: function () { return false; }
56+
};
57+
if (arg.contentLength <= 0)
58+
return allTrue;
59+
try {
60+
var propfind = xml.find('DAV:propfind');
61+
if (propfind.findIndex('DAV:propname') !== -1)
62+
return onlyName;
63+
if (propfind.findIndex('DAV:allprop') !== -1)
64+
return allTrue;
65+
var prop_1 = propfind.find('DAV:prop');
66+
var fn = function (name) {
67+
var index = prop_1.findIndex(name);
68+
if (index === -1)
69+
return false;
70+
delete prop_1.elements[index];
71+
return true;
72+
};
73+
return {
74+
leftElements: prop_1.elements,
75+
mustDisplay: fn,
76+
mustDisplayValue: function () { return true; }
77+
};
78+
}
79+
catch (ex) {
80+
return allTrue;
81+
}
82+
}
83+
function propstatStatus(status) {
84+
return 'HTTP/1.1 ' + status + ' ' + http.STATUS_CODES[status];
85+
}
4586
function default_1(arg, callback) {
4687
arg.getResource(function (e, resource) {
4788
if (e || !resource) {
@@ -82,6 +123,7 @@ function default_1(arg, callback) {
82123
});
83124
}); });
84125
function addXMLInfo(resource, multistatus, callback) {
126+
var reqBody = parseRequestBody(arg);
85127
var response = multistatus.ele('D:response');
86128
var propstat = response.ele('D:propstat');
87129
var privileges = [
@@ -91,37 +133,77 @@ function default_1(arg, callback) {
91133
privileges.push('canSource');
92134
arg.requireErPrivilege(privileges, resource, function (e, can) {
93135
if (e) {
94-
propstat.ele('D:status').add('HTTP/1.1 ' + WebDAVRequest_1.HTTPCodes.InternalServerError + ' ' + http.STATUS_CODES[WebDAVRequest_1.HTTPCodes.InternalServerError]);
136+
propstat.ele('D:status').add(propstatStatus(WebDAVRequest_1.HTTPCodes.InternalServerError));
95137
callback();
96138
return;
97139
}
98140
if (!can) {
99-
propstat.ele('D:status').add('HTTP/1.1 ' + WebDAVRequest_1.HTTPCodes.Forbidden + ' ' + http.STATUS_CODES[WebDAVRequest_1.HTTPCodes.Forbidden]);
141+
propstat.ele('D:status').add(propstatStatus(WebDAVRequest_1.HTTPCodes.Forbidden));
100142
callback();
101143
return;
102144
}
103145
propstat.ele('D:status').add('HTTP/1.1 200 OK');
104146
var prop = propstat.ele('D:prop');
105-
var nb = 7;
147+
var nb = 1;
106148
function nbOut(error) {
107149
if (nb > 0 && error) {
108-
nb = -1;
150+
nb = -1000;
109151
callback(error);
110152
return;
111153
}
112154
--nb;
113-
if (nb === 0)
155+
if (nb === 0) {
156+
if (reqBody.leftElements.length > 0) {
157+
var propstatError = response.ele('D:propstat');
158+
var prop_2 = propstatError.ele('D:prop');
159+
propstatError.ele('D:status').add(propstatStatus(WebDAVRequest_1.HTTPCodes.NotFound));
160+
for (var i = 0; i < reqBody.leftElements.length; ++i)
161+
if (reqBody.leftElements[i])
162+
prop_2.ele(reqBody.leftElements[i].name);
163+
}
114164
callback();
165+
}
115166
}
116-
resource.creationDate(function (e, ticks) { return process.nextTick(function () {
117-
if (!e)
118-
prop.ele('D:creationdate').add(arg.dateISO8601(ticks));
119-
nbOut(e);
120-
}); });
167+
var tags = {};
168+
function mustDisplayTag(name) {
169+
if (reqBody.mustDisplay('DAV:' + name))
170+
tags[name] = {
171+
el: prop.ele('D:' + name),
172+
value: reqBody.mustDisplayValue('DAV:' + name)
173+
};
174+
else
175+
tags[name] = {
176+
value: false
177+
};
178+
}
179+
mustDisplayTag('creationdate');
180+
mustDisplayTag('lockdiscovery');
181+
mustDisplayTag('getetag');
182+
mustDisplayTag('getlastmodified');
183+
mustDisplayTag('resourcetype');
184+
mustDisplayTag('displayname');
185+
mustDisplayTag('supportedlock');
186+
function displayValue(values, fn) {
187+
if (values.constructor === String ? tags[values].value : values.some(function (n) { return tags[n].value; })) {
188+
++nb;
189+
process.nextTick(fn);
190+
}
191+
}
192+
displayValue('creationdate', function () {
193+
resource.creationDate(function (e, ticks) { return process.nextTick(function () {
194+
if (!e)
195+
tags.creationdate.el.add(arg.dateISO8601(ticks));
196+
nbOut(e);
197+
}); });
198+
});
199+
++nb;
121200
arg.getResourcePath(resource, function (e, path) {
122-
if (!e) {
123-
response.ele('D:href').add(arg.fullUri(path).replace(' ', '%20'));
124-
var lockdiscovery_1 = prop.ele('D:lockdiscovery');
201+
if (e) {
202+
nbOut(e);
203+
return;
204+
}
205+
if (tags.lockdiscovery.value) {
206+
++nb;
125207
lockDiscovery(lockDiscoveryCache, arg, new FSPath_1.FSPath(path), resource, function (e, l) {
126208
if (e) {
127209
nbOut(e);
@@ -131,7 +213,7 @@ function default_1(arg, callback) {
131213
for (var _i = 0, _a = l[path_1]; _i < _a.length; _i++) {
132214
var _lock = _a[_i];
133215
var lock = _lock;
134-
var activelock = lockdiscovery_1.ele('D:activelock');
216+
var activelock = tags.lockdiscovery.el.ele('D:activelock');
135217
activelock.ele('D:lockscope').ele('D:' + lock.lockKind.scope.value.toLowerCase());
136218
activelock.ele('D:locktype').ele('D:' + lock.lockKind.type.value.toLowerCase());
137219
activelock.ele('D:depth').add('Infinity');
@@ -145,70 +227,90 @@ function default_1(arg, callback) {
145227
nbOut(null);
146228
});
147229
}
148-
else
149-
nbOut(e);
230+
resource.type(function (e, type) { return process.nextTick(function () {
231+
if (e) {
232+
nbOut(e);
233+
return;
234+
}
235+
var p = arg.fullUri(path).replace(' ', '%20');
236+
response.ele('D:href').add(p.lastIndexOf('/') !== p.length - 1 && type.isDirectory ? p + '/' : p);
237+
if (tags.resourcetype.value && type.isDirectory)
238+
tags.resourcetype.el.ele('D:collection');
239+
if (type.isFile) {
240+
mustDisplayTag('getcontentlength');
241+
mustDisplayTag('getcontenttype');
242+
if (tags.getcontenttype.value) {
243+
++nb;
244+
resource.mimeType(targetSource, function (e, mimeType) { return process.nextTick(function () {
245+
if (!e)
246+
tags.getcontenttype.el.add(mimeType);
247+
nbOut(e);
248+
}); });
249+
}
250+
if (tags.getcontentlength.value) {
251+
++nb;
252+
resource.size(targetSource, function (e, size) { return process.nextTick(function () {
253+
if (!e)
254+
tags.getcontentlength.el.add(size === undefined || size === null || size.constructor !== Number ? 0 : size);
255+
nbOut(e);
256+
}); });
257+
}
258+
}
259+
nbOut();
260+
}); });
150261
});
151-
resource.webName(function (e, name) { return process.nextTick(function () {
152-
if (!e)
153-
prop.ele('D:displayname').add(name ? name : '');
154-
nbOut(e);
155-
}); });
156-
var supportedlock = prop.ele('D:supportedlock');
157-
resource.getAvailableLocks(function (e, lockKinds) { return process.nextTick(function () {
158-
if (e) {
262+
displayValue('displayname', function () {
263+
resource.webName(function (e, name) { return process.nextTick(function () {
264+
if (!e)
265+
tags.displayname.el.add(name ? name : '');
159266
nbOut(e);
160-
return;
161-
}
162-
lockKinds.forEach(function (lockKind) {
163-
var lockentry = supportedlock.ele('D:lockentry');
164-
var lockscope = lockentry.ele('D:lockscope');
165-
lockscope.ele('D:' + lockKind.scope.value.toLowerCase());
166-
var locktype = lockentry.ele('D:locktype');
167-
locktype.ele('D:' + lockKind.type.value.toLowerCase());
168-
});
169-
nbOut();
170-
}); });
171-
resource.getProperties(function (e, properties) { return process.nextTick(function () {
172-
if (e) {
173-
nbOut(e);
174-
return;
175-
}
176-
for (var name_1 in properties) {
177-
var value = properties[name_1];
178-
prop.ele(name_1).add(value);
179-
}
180-
nbOut();
181-
}); });
182-
resource.type(function (e, type) { return process.nextTick(function () {
183-
if (e) {
184-
nbOut(e);
185-
return;
186-
}
187-
var resourcetype = prop.ele('D:resourcetype');
188-
if (type.isDirectory)
189-
resourcetype.ele('D:collection');
190-
if (type.isFile) {
191-
nb += 2;
192-
resource.mimeType(targetSource, function (e, mimeType) { return process.nextTick(function () {
193-
if (!e)
194-
prop.ele('D:getcontenttype').add(mimeType);
267+
}); });
268+
});
269+
displayValue('supportedlock', function () {
270+
resource.getAvailableLocks(function (e, lockKinds) { return process.nextTick(function () {
271+
if (e) {
195272
nbOut(e);
196-
}); });
197-
resource.size(targetSource, function (e, size) { return process.nextTick(function () {
198-
if (!e)
199-
prop.ele('D:getcontentlength').add(size === undefined || size === null || size.constructor !== Number ? 0 : size);
273+
return;
274+
}
275+
lockKinds.forEach(function (lockKind) {
276+
var lockentry = tags.supportedlock.el.ele('D:lockentry');
277+
var lockscope = lockentry.ele('D:lockscope');
278+
lockscope.ele('D:' + lockKind.scope.value.toLowerCase());
279+
var locktype = lockentry.ele('D:locktype');
280+
locktype.ele('D:' + lockKind.type.value.toLowerCase());
281+
});
282+
nbOut();
283+
}); });
284+
});
285+
++nb;
286+
process.nextTick(function () {
287+
resource.getProperties(function (e, properties) { return process.nextTick(function () {
288+
if (e) {
200289
nbOut(e);
201-
}); });
202-
}
203-
nbOut();
204-
}); });
205-
resource.lastModifiedDate(function (e, lastModifiedDate) { return process.nextTick(function () {
206-
if (!e) {
207-
prop.ele('D:getetag').add(IResource_1.ETag.createETag(lastModifiedDate));
208-
prop.ele('D:getlastmodified').add(new Date(lastModifiedDate).toUTCString());
209-
}
210-
nbOut(e);
211-
}); });
290+
return;
291+
}
292+
for (var name_1 in properties) {
293+
if (reqBody.mustDisplay(name_1)) {
294+
var tag = prop.ele(name_1);
295+
if (reqBody.mustDisplayValue(name_1))
296+
tag.add(properties[name_1]);
297+
}
298+
}
299+
nbOut();
300+
}); });
301+
});
302+
displayValue(['getetag', 'getlastmodified'], function () {
303+
resource.lastModifiedDate(function (e, lastModifiedDate) { return process.nextTick(function () {
304+
if (!e) {
305+
if (tags.getetag.value)
306+
tags.getetag.el.add(IResource_1.ETag.createETag(lastModifiedDate));
307+
if (tags.getlastmodified.value)
308+
tags.getlastmodified.el.add(new Date(lastModifiedDate).toUTCString());
309+
}
310+
nbOut(e);
311+
}); });
312+
});
313+
nbOut();
212314
});
213315
}
214316
function done(multistatus) {

0 commit comments

Comments
 (0)