Giter Club home page Giter Club logo

npm-webdav-client's Introduction

webdav-client npm Version Build Status

This is a WebDAV client.

It is not meant to be used on browsers yet.

Install

npm install webdav-client

Usage

import * as webdavClient from 'webdav-client'
// or
import { Connection } from 'webdav-client'
// or
const webdavClient = require('webdav-client');

// Create the client object
const connection = new webdavClient.Connection('http://my-webdav-server:1900');

connection.get('/path/of/my/file.txt', (e, content) => {
    if(e)
        throw e;
    
    console.log(content);
})

Methods

class Connection
{
    constructor(url : string)
    constructor(options : ConnectionOptions)

    request(options : RequestOptions, callback : ResponseCallback) // Custom request
    stream(options : RequestOptions) : Stream // Custom streaming request
    
    // Might be needed before using the streaming form of the methods (put and get)
    prepareForStreaming(path : string, callback : (error : Error) => void) : void
    prepareForStreaming(callback : (error : Error) => void) : void

    readdir(path : string, callback : (error : Error, files ?: string[]) => void) : void
    readdir(path : string, options : ConnectionReaddirOptions, callback : (error : Error, files : string[] | ConnectionReaddirComplexResult[]) => void) : void

    exists(path : string, callback : (error : Error, exists : boolean) => void) : void

    mkdir(path : string, callback : (error : Error) => void) : void
    delete(path : string, callback : (error : Error) => void) : void

    get(path : string, callback : (error : Error, body : ContentType) => void) : void
    get(path : string, callback : (error : Error, body : ContentType) => void) : Stream

    put(path : string, content : ContentType, callback : (error : Error) => void) : void
    put(path : string) : Stream
    
    move(pathSource : string, pathDestination : string, override : boolean, callback : (error : Error) => void) : void
    move(pathSource : string, pathDestination : string, callback : (error : Error) => void) : void

    copy(pathSource : string, pathDestination : string, override : boolean, callback : (error : Error) => void) : void
    copy(pathSource : string, pathDestination : string, callback : (error : Error) => void) : void
    
    lock(path : string, callback : (error ?: Error, lockUID ?: Lock) => void) : void
    refreshLock(path : string, lock : string | Lock, callback : (error : Error) => void) : void
    unlock(path : string, lock : string | Lock, callback : (error : Error) => void) : void

    setProperties(path : string, properties : Properties, callback : (error : Error) => void) : void
    removeProperties(path : string, properties : string[], callback : (error : Error) => void) : void
    getProperties(path : string, callback : (error : Error, properties : Properties) => void) : void
    getProperties(path : string, options : ConnectionReaddirOptions, callback : (error : Error, properties : Properties) => void) : void
}

The Connection options :

interface ConnectionOptions
{
    url : string
    authenticator ?: Authenticator
    username ?: string
    password ?: string
}

The ConnectionReaddirOptions interface :

interface ConnectionReaddirOptions
{
    // true = get a ConnectionReaddirComplexResult Array as callback result
    // false (default) = get a String Array as callback result
    properties ?: boolean
    // An array of properties which will be sent with the PROPFIND request
    extraProperties: ConnectionReaddirProperty[]
}

The ConnectionReaddirOptions interface :

interface ConnectionReaddirProperty
{
    namespace: string
    namespaceShort: string
    element: string
    // Default value. If undefined and the XML response doesn't have this element, it will not be returned
    default?: any
    // true = It will be cast to number | string | boolean
    // false (default) = it is returned as string
    nativeType?: boolean
}

The ConnectionReaddirComplexResult interface :

interface ConnectionReaddirComplexResult
{
    creationDate : Date
    lastModified : Date
    isDirectory : boolean
    isFile : boolean
    type : 'directory' | 'file'
    size : number
    href : string
    name : string
    extraProperties: {
        [name : string] : string | number | boolean
    }
}

Streaming

If you want to perform a get or put in streaming mode, you can call the methods without a callback (and without the content argument for the put).

const stream = connection.get('/my/file.txt');
stream.on('data', (chunk) => {
    console.log(chunk.toString());
})
stream.on('end', () => {
    console.log('Done.');
});
const stream = connection.put('/my/file.txt');
stream.on('finish', () => {
    console.log('Done.');
});
otherStream.pipe(stream);

Custom requests

To do custom requests, you can use the request(...) and stream(...) methods.

They take a RequestOptions argument.

interface RequestOptions
{
    url : string
    method : string
    headers ?: {
        [name : string] : string
    }
    body ?: ContentType
}

Web browser compatibility

This library can be used in a web browser.

You can produce the web browser library from your from with, for instance, browserify or you can use the "browserified" file itsef (located at lib/browserified.js).

Here is the usage of the browserified.js file :

<html>
    <head>
        <!-- Load the library -->
        <script src="node_modules/webdav-client/lib/browserified.js"></script>

        <!-- Usage of the library -->
        <script>
            const connection = new webdavClient.Connection('http://my-webdav-server:1900');

            connection.get('/path/of/my/file.txt', (e, content) => {
                if(e)
                    throw e;
                
                console.log(content);
            });
        </script>
    </head>
    <body></body>
</html>

Keep in mind that the library uses the request package, which might not be the most optimized package for web browsers.

npm-webdav-client's People

Contributors

adriencastex avatar kwisatz avatar rvsteen avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

npm-webdav-client's Issues

Uncaught exception in method 'exists'

Hello,

Using connection.exists(path, callback) creates an uncaught exception when the request cannot reach the webdav server. My case happens when my nextcloud server is down or shuts down during this request, which makes res to be null in the following line:

callback(e, res.statusCode <= 400);

There should be a sanity test to check if res is null before accessing the statusCode.

URI.pathname not prepended to destination path in move() and copy().

If you are using the webdav client with a url such as...

const client = webdav.Connection({ url: 'http://myserver.com/webdav' ");

And you try to perform a move operation like...

client.move('/foobar', '/barfoo')

You receive a 404 error because on the server side:
https://github.com/OpenMarshal/npm-WebDAV-Server/blob/ca245a2208070fde0bfc8f2610bbcd375fad1eb4/src/server/v2/commands/Move.ts#L22

Source path is '/webdav/foobar' while destination is '/barfoo'. The leading path (root) is included in the source because it is relative to the URI ('http://myserver.com/webdav') while the destination is not.

I feel like this is a bug in the client and that it is inconsistent in how it handles paths. This situation requires the user to prepend the root path to the destination when using move() or copy(). All other operations use relative paths (as it should be).

This could be "fixed" fairly easily in the client...
https://github.com/OpenMarshal/npm-WebDAV-Client/blob/master/src/index.ts#L373

... by prepending this.root to pathDestination. Or by passing the destination as a full URI (relative to the connection base URI), in which case it would be parsed server-side and also be handled correctly.

Use Promises instead of Callbacks

readdir(path : string, callback : (error : Error, files ?: string[]) => void) : void

// vs.

readdir(path : string) : Promise<string[]>

What do you think?

Update to rfc8607 following the webdav specification.

Update to rfc8607 following the webdav specification.

https://www.ietf.org/rfc/rfc8607.html

So what functions does the current webdav-server
support, and which functions does it not support?

I searched webdav on ietf's datatracker and found rfc as follows.

from rfc 2291 to rfc 8607.

https://datatracker.ietf.org/doc/search?name=webdav&sort=&rfcs=on&activedrafts=on&by=group&group=

I found that webdav has updated many new extension methods and headers and others.

However, some webdav servers or client have incomplete support for these functions.

The release date of these rfc is from February 1998 to June 2019.

I want to know whether there is currently a server or client that implements all webdav functions?

parse attributes in readdir()

Your client is the most preferable to me

I understand that it is a suitable environment for testing your webdav server .

And I want to use this client in my project.
I would like to add the most productive readdir() to obtain the content together with the attributes per one HTTP request

like this:

Connection.prototype.readdir = function (path, callback) {
    this.request({
        url: path,
        method: 'PROPFIND',
        headers: {
            depth: '1'
        }
    }, function (e, res, body) {
        if (e)
            return callback(e);
        if (res.statusCode >= 400)
            return callback(new HTTPError(res));
        try {
            var r = {};
            var xmlEntries = xml_js_builder_1.XML.parse(body)
                .find('DAV:multistatus')
                .findMany('DAV:response');
            for (let elIndex in xmlEntries) {
                let el = xmlEntries[elIndex];
                let props = el.find('DAV:propstat').find('DAV:prop');

                var davEntry = {};

                davEntry.creationDate = new Date(props.find('DAV:creationdate').findText());
                davEntry.lastModified = new Date(props.find('DAV:getlastmodified').findText());
                davEntry.type = props.find('DAV:resourcetype').findIndex('DAV:collection') != -1 ? 'd' : 'f';
                davEntry.size = props.findIndex('DAV:getcontentlength') !== -1 ? parseInt(props.find('DAV:getcontentlength').findText()) : 0;

                var href = el.find('DAV:href').findText();
                if (href.length <= href.indexOf(path) + path.length + 1)
                    continue;

                href = href.lastIndexOf('/') === href.length - 1 ? href.slice(0, -1) : href;
                let name = decodeURI(href.substring(href.lastIndexOf('/') + 1));

                r[name] = davEntry;
            }
            callback(null, r);
        }
        catch (ex) {
            callback(ex);
        }
    });
};

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.