• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/router/lighttpd-1.4.39/external_file/js/davclient.js/
1/*
2    davfs.js - High-level JavaScript WebDAV client implementation
3    Copyright (C) 2004-2007 Guido Wesdorp
4    email johnny@johnnydebris.net
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19
20    This is a high-level WebDAV interface, part of the 'davlib' JS package.
21
22    For more details, see davclient.js in the same package, or visit
23    http://johnnydebris.net.
24
25*/
26
27//-----------------------------------------------------------------------------
28// ResourceCache - simple cache to help with the FS
29//-----------------------------------------------------------------------------
30
31var global = this;
32if (!global.davlib) {
33    alert('Error: davclient.js needs to be loaded before davfs.js');
34    try {
35        var exc = new exception.MissingDependency('davclient.js', 'davfs.js');
36    } catch(e) {
37        var exc = 'Missing Dependency: davclient.js (from davfs.js)';
38    };
39    throw(exc);
40};
41
42davlib.ResourceCache = function() {
43};
44
45davlib.ResourceCache.prototype.initialize = function() {
46    this._cache = {};
47};
48
49davlib.ResourceCache.prototype.addResource = function(path, resource) {
50    this._cache[path] = resource;
51};
52
53davlib.ResourceCache.prototype.getResource = function(path) {
54    return this._cache[path];
55};
56
57davlib.ResourceCache.prototype.invalidate = function(path) {
58    delete this._cache[path];
59};
60
61//-----------------------------------------------------------------------------
62// DavFS - high-level DAV client library
63//-----------------------------------------------------------------------------
64
65davlib.DavFS = function() {
66    /* High level implementation of a WebDAV client */
67};
68
69davlib.DavFS.prototype.initialize = function(host, port, protocol) {
70    this._client = new davlib.DavClient();
71    this._client.initialize(host, port, protocol);
72    this._cache = new davlib.ResourceCache();
73    this._cache.initialize();
74};
75
76davlib.DavFS.prototype.read = function(path, handler, context) {
77    /* get the contents of a file
78
79        when done, handler is called with 2 arguments, the status code
80        and the content, optionally in context <context>
81    */
82    this._client.GET(path, this._wrapHandler(handler,
83                        this._prepareArgsRead, context), this);
84};
85
86davlib.DavFS.prototype.write = function(path, content, handler, context,
87                                        locktoken) {
88    /* write the new contents of an existing or new file
89
90        when done handler will be called with one argument,
91        the status code of the response, optionally in context
92        <context>
93    */
94    this._client.PUT(path, content, this._wrapHandler(handler,
95                        this._prepareArgsSimpleError, context), this,
96                        locktoken);
97};
98
99davlib.DavFS.prototype.remove = function(path, handler, context, locktoken) {
100    /* remove a file or directory recursively from the fs
101
102        when done handler will be called with one argument,
103        the status code of the response, optionally in context
104        <context>
105
106        when the status code is 'Multi-Status', the handler will
107        get a second argument passed in, which is a parsed tree of
108        the multi-status response body
109    */
110    this._client.DELETE(path, this._wrapHandler(handler,
111                        this._prepareArgsMultiError, context), this,
112                        locktoken);
113};
114
115davlib.DavFS.prototype.mkDir = function(path, handler, context, locktoken) {
116    /* create a dir (collection)
117
118        when done, handler is called with 2 arguments, the status code
119        and the content, optionally in context <context>
120    */
121    this._client.MKCOL(path, this._wrapHandler(handler,
122                        this._prepareArgsSimpleError, context), this,
123                        locktoken);
124};
125
126davlib.DavFS.prototype.copy = function(path, topath, handler, context,
127                                       overwrite, locktoken) {
128    /* copy an item (resource or collection) to another location
129
130        when done, handler is called with 1 argument, the status code,
131        optionally in context <context>
132    */
133    // XXX not really sure if we should send the lock token for the from or
134    // the to path...
135    this._client.COPY(path, topath, this._wrapHandler(handler,
136                        this._prepareArgsMultiError, context), this,
137                        overwrite, locktoken);
138};
139
140davlib.DavFS.prototype.move = function(path, topath, handler, context,
141                                       locktoken) {
142    /* move an item (resource or collection) to another location
143
144        when done, handler is called with 1 argument, the status code,
145        optionally in context <context>
146    */
147    this._client.MOVE(path, topath, this._wrapHandler(handler,
148                      this._prepareArgsMultiError, context), this,
149                      locktoken);
150};
151
152davlib.DavFS.prototype.listDir = function(path, handler, context, cached) {
153    /* list the contents of a collection
154
155        when done, handler is called with 2 arguments, the status code
156        and an array with filenames, optionally in context <context>
157    */
158    if (cached) {
159        var item = this._cache.getResource(path);
160        // XXX perhaps we should keep items set to null so we know
161        // the difference between an item that isn't scanned and one
162        // that just has no children
163        if (item && item.items.length > 0) {
164            var dir = [];
165            for (var i=0; i < item.items.length; i++) {
166                dir.push(item.items[i].href);
167            };
168            handler.apply('200', dir);
169            return;
170        };
171    };
172    this._client.PROPFIND(path, this._wrapHandler(handler,
173                          this._prepareArgsListDir, context), this, 1);
174};
175
176davlib.DavFS.prototype.getProps = function(path, handler, context, cached) {
177    /* get the value of one or more properties */
178    if (cached) {
179        var item = this._cache.getResource(path);
180        // XXX perhaps we should keep items set to null so we know
181        // the difference between an item that isn't scanned and one
182        // that just has no children
183        if (item) {
184            timer_instance.registerFunction(context, handler, 0,
185                                            null, item.properties);
186            return;
187        };
188    };
189    this._client.PROPFIND(path, this._wrapHandler(handler,
190                          this._prepareArgsGetProps, context), this, 0);
191};
192
193davlib.DavFS.prototype.setProps = function(path, setprops, delprops,
194                                           handler, context, locktoken) {
195    this._client.PROPPATCH(path,
196                           this._wrapHandler(handler,
197                                this._prepareArgsMultiError, context),
198                           this, setprops, delprops, locktoken);
199};
200
201davlib.DavFS.prototype.lock = function(path, owner, handler, context,
202                                       scope, type, depth, timeout,
203                                       locktoken) {
204    /* Lock an item
205
206        when done, handler is called with 2 arguments, the status code
207        and an array with filenames, optionally in context <context>
208
209        optional args:
210
211        <owner> is a URL that identifies the owner, <type> can currently
212        only be 'write' (according to the DAV specs), <depth> should be
213        either 1 or 'Infinity' (default), timeout is in seconds and
214        locktoken is the result of a previous lock (serves to refresh a
215        lock)
216    */
217    this._client.LOCK(path, owner,
218                      this._wrapHandlerLock(handler,
219                            this._prepareArgsMultiError, context),
220                      this, scope, depth, timeout, locktoken);
221};
222
223davlib.DavFS.prototype.unlock = function(path, locktoken, handler, context) {
224    /* Release a lock from an item
225
226        when done, handler is called with 1 argument, the status code,
227        optionally in context <context>
228
229        <locktoken> is a lock token returned by a previous DavFS.lock()
230        call
231    */
232    this._client.UNLOCK(path, locktoken,
233                        this._wrapHandler(handler,
234                            this._prepareArgsMultiError, context),
235                        this);
236};
237
238// TODO... :\
239/*
240davlib.DavFS.prototype.isReadable = function(path, handler, context) {};
241
242davlib.DavFS.prototype.isWritable = function(path, handler, context) {};
243
244davlib.DavFS.prototype.isLockable = function(path, handler, context) {};
245*/
246
247davlib.DavFS.prototype.isLocked = function(path, handler, context, cached) {
248    function sub(error, content) {
249        if (!error) {
250            var ns = content['DAV:'];
251            if (!ns || !ns['lockdiscovery'] ||
252                    !ns['lockdiscovery'].documentElement.getElementsByTagName(
253                        'activelock').length) {
254                content = false;
255            } else {
256                content = true;
257            };
258            handler(error, content);
259        };
260    };
261    this.getProps(path, sub, context, cached);
262};
263
264davlib.DavFS.prototype._prepareArgsRead = function(status, statusstring,
265                                                   content) {
266    var error;
267    if (status != '200' && status != '201' && status != '204') {
268        error = statusstring;
269    };
270    return new Array(error, content);
271};
272
273davlib.DavFS.prototype._prepareArgsSimpleError = function(status, statusstring,
274                                                          content) {
275    var error;
276    // ignore weird IE status code 1223...
277    if (status != '200' && status != '201' &&
278            status != '204' && status != '1223') {
279        error = statusstring;
280    };
281    return new Array(error);
282};
283
284davlib.DavFS.prototype._prepareArgsMultiError = function(status, statusstring,
285                                                         content) {
286    var error = null;
287    if (status == '207') {
288        error = this._getErrorsFromMultiStatusTree(content);
289        if (!error.length) {
290            error = null;
291        };
292    } else if (status != '200' && status != '201' && status != '204') {
293        error = statusstring;
294    };
295    return new Array(error);
296};
297
298davlib.DavFS.prototype._prepareArgsListDir = function(status, statusstring,
299                                                      content) {
300    var error;
301    if (status == '207') {
302        error = this._getErrorsFromMultiStatusTree(content);
303        if (error.length == 0) {
304            error = undefined;
305            // some caching tricks, store the current item and also
306            // all its children (can't be deeper in the current setup)
307            // in the cache, the children don't contain subchildren yet
308            // but they do contain properties
309            this._cache.addResource(content.href, content);
310            for (var i=0; i < content.items.length; i++) {
311                var child = content.items[i];
312                this._cache.addResource(child.href, child);
313            };
314            // the caller is interested only in the filenames
315            // (we assume ;)
316            content = this._getDirFromMultiStatusTree(content);
317        };
318    } else if (status != '200' && status != '201' && status != '204') {
319        error = statusstring;
320    };
321    return new Array(error, content);
322};
323
324davlib.DavFS.prototype._prepareArgsGetProps = function(status, statusstring,
325                                                       content) {
326    var error;
327    if (status == '207') {
328        error = this._getErrorsFromMultiStatusTree(content);
329        if (error.length == 0) {
330            error = undefined;
331            this._cache.addResource(content.href, content);
332            content = content.properties;
333        };
334    } else if (status != '200' && status != '201' && status != '204') {
335        error = statusstring;
336    };
337    return new Array(error, content);
338};
339
340davlib.DavFS.prototype._wrapHandler = function(handler, prepareargs, context) {
341    /* return the handler wrapped in some class that fixes the context
342        and arguments
343    */
344    function sub(status, statusstring, content) {
345        var args = prepareargs.call(this, status, statusstring,
346                                        content);
347        handler.apply(context, args);
348    };
349    return sub;
350};
351
352davlib.DavFS.prototype._wrapHandlerLock = function(handler, prepareargs,
353                                                   context) {
354    /* return the handler wrapped in some class that fixes the context
355        and arguments
356    */
357    function sub(status, statusstring, content) {
358        var error;
359        if (status == '207') {
360            error = this._getErrorsFromMultiStatusTree(content);
361            if (error.length == 0) {
362                error = undefined;
363                this._cache.addResource(content.href, content);
364                content = content.properties;
365            };
366        } else if (status != '200') {
367            error = statusstring;
368        } else {
369            content = content.locktoken;
370        };
371        handler.apply(context, (new Array(error, content)));
372    };
373    return sub;
374};
375
376davlib.DavFS.prototype._getErrorsFromMultiStatusTree = function(curritem) {
377    var errors = new Array();
378    var status = curritem.status;
379    if (status && status != '200' && status != '204') {
380        errors.push(STATUS_CODES[status]);
381    };
382    for (var i=0; i < curritem.items.length; i++) {
383        var itemerrors = this._getErrorsFromMultiStatusTree(
384                                    curritem.items[i]);
385        if (itemerrors) {
386            for (var j=0; j < itemerrors.length; j++) {
387                errors.push(itemerrors[j]);
388            };
389        };
390    };
391    return errors;
392};
393
394davlib.DavFS.prototype._getDirFromMultiStatusTree = function(root) {
395    var list = new Array();
396    this._cache.addResource(root.href, root);
397    for (var i=0; i < root.items.length; i++) {
398        var item = root.items[i];
399        list.push(item.href);
400    };
401    list.sort();
402    return list;
403};
404
405