webdav-handler 0.1.2

handler for the HTTP and Webdav protocols with filesystem backend
Documentation

webdav-handler

Apache-2.0 licensed crates.io Released API docs

Generic async HTTP/WEBDAV handler

Webdav (RFC4918) is HTTP (GET/HEAD/PUT/DELETE) plus a bunch of extra methods.

This crate implements a futures/stream based webdav handler for Rust, using the types from the http crate. It comes complete with an async filesystem backend, so it can be used as a WEBDAV filesystem server, or just as a feature-complete HTTP server.

NOTE: this crate uses futures 0.3 + async/await code internally, so it only works with Rust 1.39 and up. The external interface is still futures 0.1 + tokio 0.1 based though.

Interface.

It has an interface similar to the Go x/net/webdav package:

With some glue code, this handler can be used from HTTP server libraries/frameworks such as hyper or actix-web. (See examples/hyper.rs or examples/actix-web).

Implemented standards.

Currently passes the "basic", "copymove", "props", "locks" and "http" checks of the Webdav Litmus Test testsuite. That's all of the base RFC4918 webdav specification.

The litmus test suite also has tests for RFC3744 "acl" and "principal", RFC5842 "bind", and RFC3253 "versioning". Those we do not support right now.

The relevant parts of the HTTP RFCs are also implemented, such as the preconditions (If-Match, If-None-Match, If-Modified-Since, If-Unmodified-Since, If-Range), partial transfers (Range).

Also implemented is partial PUT, for which there are currently two non-standard ways to do it: PUT with the Content-Range header, which is what Apache's mod_dav implements, and PATCH with the X-Update-Range header from SabreDav.

Backends.

Included are two filesystems:

  • LocalFs: serves a directory on the local filesystem
  • MemFs: ephemeral in-memory filesystem. supports DAV properties.

Also included are two locksystems:

  • MemLs: ephemeral in-memory locksystem.
  • FakeLs: fake locksystem. just enough LOCK/UNLOCK support for OSX/Windows.

Example.

Example server that serves the /tmp directory in r/w mode. You should be able to mount this network share from Linux, OSX and Windows.

use hyper;
use bytes::Bytes;
use futures::{future::Future, stream::Stream};
use webdav_handler::{DavHandler, localfs::LocalFs, fakels::FakeLs};

fn main() {
    let dir = "/tmp";
    let addr = ([127, 0, 0, 1], 4918).into();

    let dav_server = DavHandler::new(None, LocalFs::new(dir, false, false, false), Some(FakeLs::new()));
    let make_service = move || {
        let dav_server = dav_server.clone();
        hyper::service::service_fn(move |req: hyper::Request<hyper::Body>| {
            /// Turn hyper request body stream into more general Bytes stream.
            let (parts, body) = req.into_parts();
            let body = body.map(|item| Bytes::from(item));
            let req = http::Request::from_parts(parts, body);
            let fut = dav_server.handle(req)
                .and_then(|resp| {
                    /// Transform the response Byte stream into a hyper response body.
                    let (parts, body) = resp.into_parts();
                    let body = hyper::Body::wrap_stream(body);
                    Ok(hyper::Response::from_parts(parts, body))
                });
            Box::new(fut)
        })
    };

    println!("Serving {} on {}", dir, addr);
    let server = hyper::Server::bind(&addr)
        .serve(make_service)
        .map_err(|e| eprintln!("server error: {}", e));

    hyper::rt::run(server);
}

Building.

You need at least Rust 1.39.

Testing.

RUST_LOG=webdav_handler=debug cargo run --example sample-litmus-server

This will start a server on port 4918, serving an in-memory filesystem. For other options, run cargo run --example sample-litmus-server -- --help

Copyright and License.