Attention
You are looking at outdated documentation for version 1.x. A newer version is available.
WsgiDAV Documentation¶
Project: | WsgiDAV, https://github.com/mar10/wsgidav/ |
---|---|
Copyright: | Licensed under The MIT License |
Author: | Martin Wendt |
Release: | 1.3 |
Date: | May 19, 2019 |
WsgiDAV is a generic WebDAV server written in Python and based on WSGI.
(WsgiDAV is a refactored version of PyFileServer written by Ho Chun Wei.)
Main Features¶
- Comes bundled with a server and a file system provider, so we can share a directory right away from the command line.
- Designed to run behind any WSGI compliant server.
- Tested with different clients on different platforms (Windows, Unix, Mac).
- Supports online editing of MS Office documents.
- Contains a simple web browser interface.
- SSL support
- Support for authentication using Basic or Digest scheme.
- Passes litmus test suite.
- Open architecture allows to write custom providers (i.e. storage, locking, authentication, …).
Quickstart¶
Install
Releases are hosted on PyPI. Install like:
$ pip install -U wsgidav
Or install the latest (potentially unstable) development version:
$ pip install git+https://github.com/mar10/wsgidav.git
See also
Installing WsgiDAV for details and how to install with developer access.
Run Server
To serve the /tmp
folder as WebDAV /
share, simply run:
$ wsgidav --host=0.0.0.0 --port=80 --root=/tmp
Much more options are available when a configuration file is specified.
By default wsgidav.conf
is searched in the local directory. Otherwise a
file name can be specified:
$ wsgidav --config=my_config.conf
See also
Supported Clients¶
WsgiDAV comes with a web interface and was tested with different clients (Windows File Explorer and drive mapping, MS Office, Ubuntu, Mac OS X, …).

See also
More info¶
Attention
You are looking at outdated documentation for version 1.x. A newer version is available.
Installing WsgiDAV¶
This document describes, how a WsgiDAV server is installed.
- WsgiDAV server was tested with these operating systems:
- Linux (Ubuntu 13)
- Mac OS X 10.9
- Windows (Win7, Vista, XP)
Details¶
Unix / Linux¶
The following examples were tested on Ubuntu 13.04.
Install lxml (optional):
~$ sudo apt-get install python-lxml
Install the latest release:
~$ sudo pip install -U wsgidav
or install the latest (potentially unstable) development version:
~$ pip install git+https://github.com/mar10/wsgidav.git
If you want to participate, check it out from the repository
$ git clone https://github.com/mar10/wsgidav.git wsgidav
$ cd wsgidav
$ setup.py develop
$ setup.py test
$ wsgidav --help
Windows¶
Install the preconditions, if neccessary. Basically the same as for Unix / Linux
Attention
You are looking at outdated documentation for version 1.x. A newer version is available.
Configure and Run WsgiDAV Server¶
This document describes, how to configure and run a WsgiDAV server.
The WsgiDAV server was tested with these platforms
- Mac OS X 10.9
- Ubuntu 13
- Windows (Win7, Vista, XP)
and these WSGI servers
- cherrypy.wsgiserver
- paste.httpserver
- Pylons
- wsgidav.ext_wsgiutils_server (bundled with WsgiDAV)
- wsgiref.simple_server
Attention
You are looking at outdated documentation for version 1.x. A newer version is available.
Sample configuration file¶
- The configuration file uses Python syntax to specify these options:
- Server options (hostname, port, SSL cert, …)
- List of share-name / WebDAV provider mappings
- List of users for authentication
- Optional custom DAV providers (i.e. other than FilesystemProvider)
- Optional custom lock manager, property manager and domain controller
- Advanced debugging options
- (and more)
For a start, you should copy
Sample Configuration
or
Annotated Sample Configuration
and edit it to your needs.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 |
# Note: This file is in Python syntax and format
################################################################################
# WsgiDAV configuration file
#
################################################################################
# HELPERS - Do not modify this section
provider_mapping = {}
user_mapping = {}
def addShare(shareName, davProvider):
provider_mapping[shareName] = davProvider
def addUser(realmName, user, password, description, roles=[]):
realmName = "/" + realmName.strip(r"\/")
userDict = user_mapping.setdefault(realmName, {}).setdefault(user, {})
userDict["password"] = password
userDict["description"] = description
userDict["roles"] = roles
################################################################################
# SERVER OPTIONS
#===============================================================================
# 3rd party servers
# Try to run WsgiDAV inside these WSGI servers, in that order
ext_servers = (
# "paste",
# "cherrypy",
# "wsgiref",
"cherrypy-bundled",
"wsgidav",
)
# Server port (use --port on command line)
port = 8080
# Server hostname (use --host on command line)
host = "localhost"
#===============================================================================
# Enable SSL support
# (The certificate should match the servers hostname, so the bogus certs will not
# work in all scenarios.)
# ssl_certificate = "wsgidav/server/sample_bogo_server.crt"
# ssl_private_key = "wsgidav/server/sample_bogo_server.key"
# ssl_certificate_chain = None
# Add the MS-Author-Via Response Header to OPTIONS command to allow editing
# with Microsoft Office (default: False)
add_header_MS_Author_Via = True
#================================================================================
# Misc. setings
#
# Block size in bytes
#block_size = 8192
#===============================================================================
# Middlewares
#
# Use this section to modify the default middleware stack
#from wsgidav.dir_browser import WsgiDavDirBrowser
#from debug_filter import WsgiDavDebugFilter
#from http_authenticator import HTTPAuthenticator
#from error_printer import ErrorPrinter
#middleware_stack = [ WsgiDavDirBrowser, HTTPAuthenticator, ErrorPrinter, WsgiDavDebugFilter ]
#===============================================================================
# Debugging
verbose = 1 # 0 - no output (excepting application exceptions)
# 1 - show single line request summaries (HTTP logging)
# 2 - show additional events
# 3 - show full request/response header info (HTTP Logging)
# request body and GET response bodies not shown
# Enable specific module loggers
# E.g. ["lock_manager", "property_manager", "http_authenticator", ...]
enable_loggers = []
# Enable max. logging for certain http methods
# E.g. ["COPY", "DELETE", "GET", "HEAD", "LOCK", "MOVE", "OPTIONS", "PROPFIND", "PROPPATCH", "PUT", "UNLOCK"]
debug_methods = []
# Enable max. logging during litmus suite tests that contain certain strings
# E.g. ["lock_excl", "notowner_modify", "fail_cond_put_unlocked", ...]
debug_litmus = []
################################################################################
# WsgiDavDirBrowser
dir_browser = {
"enable": True, # Render HTML listing for GET requests on collections
"response_trailer": "", # Raw HTML code, appended as footer
"davmount": False, # Send <dm:mount> response if request URL contains '?davmount'
"ms_mount": False, # Add an 'open as webfolder' link (requires Windows)
"ms_sharepoint_plugin": True, # Invoke MS Offce documents for editing using WebDAV
"ms_sharepoint_urls": False, # Prepend 'ms-word:ofe|u|' to URL for MS Offce documents
# "app_class": MyBrowser, # Used instead of WsgiDavDirBrowser
}
################################################################################
# DAV Provider
#===============================================================================
# Property Manager
#
# Uncomment this lines to specify your own property manager.
# Default: no support for dead properties
# Also available: wsgidav.property_manager.PropertyManager
# wsgidav.property_manager.ShelvePropertyManager
#
# Check the documentation on how to develop custom property managers.
# Note that the default PropertyManager works in-memory, and thus is NOT
# persistent.
### Use in-memory property manager (NOT persistent)
# (this is the same as passing 'propsmanager = True')
#from wsgidav.property_manager import PropertyManager
#propsmanager = PropertyManager()
### Use persistent shelve based property manager
#from wsgidav.property_manager import ShelvePropertyManager
#propsmanager = ShelvePropertyManager("wsgidav-props.shelve")
### Use persistent MongoDB based property manager
#from wsgidav.addons.mongo_property_manager import MongoPropertyManager
#prop_man_opts = {}
#propsmanager = MongoPropertyManager(prop_man_opts)
### Use persistent CouchDB based property manager
#from wsgidav.addons.couch_property_manager import CouchPropertyManager
#prop_man_opts = {}
#propsmanager = CouchPropertyManager(prop_man_opts)
### Use in-memory property manager (NOT persistent)
propsmanager = True
### Optional additional live property modification
# Note: by default live properties like file size and last-modified time are
# read-only, but that can be overriden here if the underlying DAV provider
# supports it. For now only the FileSystemProvider supports it and only namely
# changes to the last-modified timestamp. Enable it with the mutable_live_props
# list as below to allow clients to use the utime system call or e.g. the
# touch or cp / rsync commands with the preserve-timestamp flags on a mounted
# DAV share.
# Please note that the timestamp is set on the actual file or directory, so it
# is persistent even for in-memory property managers. It should also be noted
# that mutable last-modified may not be compliant with the RFC 4918.
#mutable_live_props = ["{DAV:}getlastmodified"]
#===============================================================================
# Lock Manager
#
# Uncomment this lines to specify your own locks manager.
# Default: wsgidav.lock_storage.LockStorageDict
# Also available: wsgidav.lock_storage.LockStorageShelve
#
# Check the documentation on how to develop custom lock managers.
# Note that the default LockStorageDict works in-memory, and thus is NOT
# persistent.
# Example: Use in-memory lock storage
# (this is the same as passing 'locksmanager = True', which is default)
#from wsgidav.lock_storage import LockStorageDict
#locksmanager = LockStorageDict()
# Example: Use PERSISTENT shelve based lock manager
#from wsgidav.lock_storage import LockStorageShelve
#locksmanager = LockStorageShelve("wsgidav-locks.shelve")
################################################################################
# SHARES
#
# If you would like to publish files in the location '/v_root' through a
# WsgiDAV share 'files', so that it can be accessed by this URL:
# http://server:port/files
# insert the following line:
# addShare("files", "/v_root")
# or, on a Windows box:
# addShare("files", "c:\\v_root")
#
# To access the same directory using a root level share
# http://server:port/
# insert this line:
# addShare("", "/v_root")
#
# The above examples use wsgidav.fs_dav_provider.FilesystemProvider, which is
# the default provider implementation.
#
# If you wish to use a custom provider, an object must be passed as second
# parameter. See the examples below.
### Add a read-write file share:
addShare("dav", r"C:\temp")
### Add a read-only file share:
#from wsgidav.fs_dav_provider import FilesystemProvider
#addShare("tmp", FilesystemProvider("/tmp", readonly=True))
### Publish an MySQL 'world' database as share '/world-db'
#from wsgidav.addons.mysql_dav_provider import MySQLBrowserProvider
#addShare("world-db", MySQLBrowserProvider("localhost", "root", "test", "world"))
### Publish a virtual structure
#from wsgidav.samples.virtual_dav_provider import VirtualResourceProvider
#addShare("virtres", VirtualResourceProvider())
### Publish a Mercurial repository
#from wsgidav.addons.hg_dav_provider import HgResourceProvider
#addShare("hg", HgResourceProvider("PATH_OR_URL"))
### Publish a MongoDB
#from wsgidav.samples.mongo_dav_provider import MongoResourceProvider
#mongo_dav_opts = {}
#addShare("mongo", MongoResourceProvider(mongo_dav_opts))
################################################################################
# AUTHENTICATION
#===============================================================================
# HTTP Authentication Options
acceptbasic = True # Allow basic authentication, True or False
acceptdigest = True # Allow digest authentication, True or False
defaultdigest = True # True (default digest) or False (default basic)
# Enter the name of a header field that will be accepted as authorized user.
# Including quotes, for example: trusted_auth_header = "REMOTE_USER"
trusted_auth_header = None
#===============================================================================
# Domain Controller
# Uncomment this line to specify your own domain controller
# Default: wsgidav.domain_controller, which uses the USERS section below
#
# Example:
# use a domain controller that allows users to authenticate against a
# Windows NT domain or a local computer.
# Note: NTDomainController requires basic authentication:
# Set acceptbasic=True, acceptdigest=False, defaultdigest=False
#from wsgidav.addons.nt_domain_controller import NTDomainController
#domaincontroller = NTDomainController(presetdomain=None, presetserver=None)
#acceptbasic = True
#acceptdigest = False
#defaultdigest = False
#===============================================================================
# USERS
#
# This section is ONLY used by the DEFAULT Domain Controller.
#
# Users are defined per realm:
# addUser(<realm>, <user>, <password>, <description>)
#
# Note that the default Domain Controller uses the share name as realm name.
#
# If no users are specified for a realm, no authentication is required.
# Thus granting read-write access to anonymous!
#
# Note: If you wish to use Windows WebDAV support (such as Windows XP's My
# Network Places), you need to include the domain of the user as part of the
# username (note the DOUBLE slash), such as:
# addUser("v_root", "domain\\user", "password", "description")
addUser("", "tester", "secret", "")
addUser("", "tester2", "secret2", "")
#addUser("dav", "tester", "secret", "")
#addUser("dav", "tester2", "secret2", "")
#addUser("virtres", "tester", "secret", "")
|
Attention
You are looking at outdated documentation for version 1.x. A newer version is available.
Running as Pylons controller¶
This example shows how configure a Pylons application, so that URLs starting with /dav/… are handled by WsgiDAV. (Tested with Pylons 0.9.7)
First, we create a URL mapping by adding these lines to
<pylons_project>/config/routing.py
:
# CUSTOM ROUTES HERE
# Add WsgiDAV server at /dav
map.connect('wdavroot', '/dav', path_info='/', controller='wdav')
map.connect('wdavres', '/dav/{path_info:.*}', controller='wdav')
Then add the controller by creating a new file
<pylons_project>/controllers/wdav.py
with this content:
# -*- coding: utf-8 -*-
from tempfile import gettempdir
from wsgidav.fs_dav_provider import FilesystemProvider
from wsgidav.wsgidav_app import DEFAULT_CONFIG, WsgiDAVApp
def _make_app():
rootpath = gettempdir()
provider = FilesystemProvider(rootpath)
config = DEFAULT_CONFIG.copy()
config.update({
"mount_path": "/dav",
"provider_mapping": {"/": provider},
"user_mapping": {},
"verbose": 1,
})
return WsgiDAVApp(config)
WdavController = _make_app()
Note that we have to use the mount_path option to tell WsgiDAV about the application root.
In the example above, we used a root share (‘/’), so WebDAV resources will be available as
http://192.168.0.2:5000/dav/resource.bin
If the provider is configured with a share name:
config.update({
"mount_path": "/dav",
"provider_mapping": {"/my_share": provider},
...
})
the WebDAV resources will be available as
http://192.168.0.2:5000/dav/my_share/resource.bin
Run as stand-alone server¶
WsgiDAV is a WSGI application, that can be run by any WSGI compliant server.
This package comes with a built-in WSGI server called wsgidav (See wsgidav.wsgidav_server.run_server.py for details).
In the most simple case, no configuration file is required. The following line starts publishing the local folder /tmp for anonymous WebDAV access:
~/wsgidav$ wsgidav --host=0.0.0.0 --port=80 --root=/tmp
To test it, you may start a browser on http://127.0.0.1/
.
However, most of the time we want to specify a configuration file with advanced settings:
~/wsgidav$ wsgidav --host=0.0.0.0 --port=80 --config=./wsgidav.conf
By default, WsgiDAV will search for a file called wsgidav.conf
in the current
working directory. Use the -h option for a list of additional commands:
~/wsgidav$ wsgidav -h
Configuration file¶
- The configuration file uses Python syntax to specify these options:
- Server options (hostname, port, SSL cert, …)
- List of share-name / WebDAV provider mappings
- List of users for authentication
- Optional custom DAV providers (i.e. other than FilesystemProvider)
- Optional custom lock manager, property manager and domain controller
- Advanced debugging options
- (and more)
For a start, you should copy
Sample Configuration
or
Annotated Sample Configuration
and edit it to your needs.
See also
Run inside a 3rd-party WSGI server¶
Setup up the configuration dictionary, create a WsgiDAVApp
object and
pass it to your favorite WSGI server:
Run inside Pylons¶
See Running as Pylons controller for an example how WsgiDAV can be configured as Pylons controller.
Attention
You are looking at outdated documentation for version 1.x. A newer version is available.
Access WsgiDAV with WebDAV Clients¶
This document describes, how a WsgiDAV server can be accessed with different clients.
WsgiDAV was tested with these clients
- Windows 7, 8
- Windows Vista (Microsoft-WebDAV-!MiniRedir/6.0.6002)
- Window XP (Microsoft-WebDAV-!MiniRedir/5.1.2600)
- DAVExplorer
- MS Office 2013
- OpenOffice 3.1
- Ubuntu Nautilus / gvfs
- Mac OS/X Finder
The following examples assume, that we have a running WsgiDAV server on a remote machine with this configuration:
- Server is running on a machine with IP address 192.168.0.2
- Server is listening on port 80
- A user called ‘tester’ with password ‘secret’ is configured to have access. (Or the share allows anonymous access.)
Windows clients¶
Redirector¶
The easiest way to access a WebDAV share from a Windows client is probably to map it as a network drive, and then use the File Explorer.
If the share allows anonymous access, type this at the command promt:
> net use W: http://192.168.0.2/
> dir W:
For access controlled shares, we must provide a user name:
> net use W: http://192.168.0.2/ /USER:tester
Windows will then prompt for a password. Alternatively we can pass password with the command line:
> net use W: http://192.168.0.2/ /USER:tester secret
To make this connection persistent between reboots:
> net use W: http://192.168.0.2/ /USER:tester secret /PERSISTENT:YES
To stop a connection:
> net use W: /DELETE
Note
Some known quirks of Windows redirector are listed below.
Known issues on all Windows versions
See als greenbytes WebDAV Mini-Redirector (MRXDAV.SYS) Versions and Issues List.
The WebDAV server must respond to PROPFIND and OPTIONS requests at the root share (‘/’). So when running behind another web server, WsgiDAV must be mounted at top level.
Digest authentication is supported by default. Basic authentication is disabled, when HTTP is used instead of SSL/HTTPS. (This can be changed by editing the registry: http://support.microsoft.com/kb/841215)
Basic authentication sends passwords unencrypted, so it is generally a good thing to do this only over an SSL encrypted channel.
Problems may arise, when we cannot provide Digest authentication (maybe because a custom WsgiDAV domain controller has no access to the users passwords). Or when our server does not provide HTTPS support.
Additional issues on Windows 7
By default Basic authentication is only allowed, when SSL (HTTPS) is used. (See previous notes.)
Reportedly on Windows 7, WebDAV requests receive a 3 second delay in the Windows explorer. To fix this, you may change IE’s proxy settings:
Open IE -> Go to Tools menu -> Internet Options -> Connections -> LAN settings -> Un-check Automatically detect settings -> Click Ok -> Click Ok
Additional issues on Windows Vista:
- By default Basic authentication is only allowed, when SSL (HTTPS) is used. (See previous notes.)
Additional issues on Windows XP:
Windows XP cannot map ‘/’ shares, so we have to connect to an existing sub folder (for example /dav):
> net use W: http://192.168.0.2/dav
No custom port is accepted in the URL, like http://192.168.0.2:8001/dav. So WsgiDAV must run on port 80. This also means, that SSL won’t work (This may help: http://www.stunnel.org/).
The URL must start with http://. HTTPS is not supported.
This in turn means that we have to enable Digest authentication, because Basic authentication is not allowed over HTTP (see common Windows issues above).
However at least on SP3 the redirector seems to follow 302 Redirect responses to a https location. And then Basic authentication worked.
There have been problems reported, when the
NET USE
command prompts you for a name/password. (Servicepack 3 seems to work fine.) In this case, try to pass username and password on the command line with the/USER
option:> net use W: http://192.168.0.2/dav /USER:tester secret
WebFolders¶
Microsoft’s “WebFolder” client predates Windows XP’s WebDAV Redirector.
- TODO
Note
Some known quirks of Microsoft’s “WebFolder” client are listed below.
See als greenbytes Web Folder Client (MSDAIPP.DLL) Versions and Issues List.
- If you experience problems, you might try Microsoft’s Software Update for Web Folders
Linux clients¶
Nautilus / gvfs¶
From the Nautilus File menu choose ‘Connect to server…’. In the dialog box enter
- Service type: ‘WebDAV (HTTP)’
- Server: ‘192.168.0.2’
- Folder: ‘ro_docs’ or whatever the share name is (leave empty for root share).
- Port: the port number (leave empty for default port 80)
- User Name: leave this empty: do not enter anything here.
Then click ‘Connect’ and enter username and password.
Known issues:
- When copying directories, only an HTML file is created at the target. See http://bugzilla.gnome.org/show_bug.cgi?id=605619
davfs2¶
On Ubuntu we can mount a WebDAV file system. First make sure, that davfs2 is installed:
$ sudo apt-get install davfs2
Then create the mount point:
$ sudo mkdir /mnt/wsgidav_temp
$ sudo chmod 0766 /mnt/wsgidav_temp
$ sudo mount -t davfs http://192.168.0.2/dav /mnt/wsgidav -o rw
Please enter the username to authenticate with server
http://192.168.0.2/dav or hit enter for none.
Username: tester
Please enter the password to authenticate user tester with server
http://192.168.0.2/dav or hit enter for none.
Password:
To unmount:
sudo unmount /mnt/wsgidav
Browser clients¶
WsgiDAV enables HTTP browsing by default, so it is always possible to enter:
http://192.168.0.2/dav
in the address bar of your favorite web browser.
Attention
You are looking at outdated documentation for version 1.x. A newer version is available.
Samples and addons for WsgiDAV¶
Attention
You are looking at outdated documentation for version 1.x. A newer version is available.
Mercurial WebDAV provider¶
Examples¶
This screenshot shows how a Mercurial repository appears in Microsoft Windows File Explorer:

Some new live properties are available:

Usage¶
Note
This is not production code.
To publish a Mercurial repository by the share name ‘hg’, simply add thes lines to the configuration file:
# Publish a Mercurial repository
from wsgidav.addons.hg_dav_provider import HgResourceProvider
addShare("hg", HgResourceProvider("REPO_PATH_OR_URL"))
Details¶
DAV provider that publishes a Mercurial repository.
Note: This is not production code!
The repository is rendered as three top level collections.
- edit:
- Contains the working directory, i.e. all files. This includes uncommitted changes and untracked new files. This folder is writable.
- released:
- Contains the latest committed files, also known as ‘tip’. This folder is read-only.
- archive:
- Contains the last 10 revisions as sub-folders. This folder is read-only.
Sample layout:
/<share>/
edit/
server/
ext_server.py
README.txt
released/
archive/
19/
18/
...
Supported features:
- Copying or moving files from
/edit/..
to the/edit/..
folder will result in ahg copy
orhg rename
. - Deleting resources from
/edit/..
will result in ahg remove
. - Copying or moving files from
/edit/..
to the/released
folder will result in ahg commit
. Note that the destination path is ignored, instead the source path is used. So a user can drag a file or folder from somewhere under theedit/..
directory and drop it directly on thereleased
directory to commit changes. - To commit all changes, simply drag’n’drop the
/edit
folder on the/released
folder. - Creating new collections results in creation of a file called
.directory
, which is thenhg add
ed since Mercurial doesn’t track directories. - Some attributes are published as live properties, such as
{hg:}date
.
Known limitations:
- This ‘commit by drag-and-drop’ only works, if the WebDAV clients produces MOVE or COPY requests. Alas, some clients will send PUT, MKCOL, … sequences instead.
- Adding and then removing a file without committing after the ‘add’ will leave this file on disk (untracked) This happens for example whit lock files that Open Office Write and other applications will create.
- Dragging the ‘edit’ folder onto ‘released’ with Windows File Explorer will remove the folder in the explorer view, although WsgiDAV did not delete it. This seems to be done by the client.
- See:
- http://mercurial.selenic.com/wiki/MercurialApi
- Requirements:
easy_install mercurial
or install the API as non-standalone version from here: http://mercurial.berkwood.com/ http://mercurial.berkwood.com/binaries/mercurial-1.4.win32-py2.6.exe
Attention
You are looking at outdated documentation for version 1.x. A newer version is available.
Attention
You are looking at outdated documentation for version 1.x. A newer version is available.
MySQL WebDAV provider¶
Examples¶
This screenshot shows how the country table of MySQL’s world-db sample database is published as a collection.
All table rows are rendered as non-collections (text files) that contain the CSV formatted columns.
An additional virtual text file _ENTIRE_CONTENTS is created, that contains th whole CSV formatted table content.

The table’s columns are mad accessible as live properties: .. image:: _static/img/DAVExplorer_MySQL.gif
Usage¶
To publish an MySQL database, simply add thes lines to the configuration file:
### Publish an MySQL 'world' database as share '/world-db'
from wsgidav.addons.mysql_dav_provider import MySQLBrowserProvider
addShare("world-db", MySQLBrowserProvider("localhost", "root", "test", "world"))
Module description¶
Attention
You are looking at outdated documentation for version 1.x. A newer version is available.
Attention
You are looking at outdated documentation for version 1.x. A newer version is available.
Virtual WebDAV provider¶
Examples¶
Given these 3 ‘resources’:
Title | Orga | Status | Tags | Attachments |
---|---|---|---|---|
My doc 1 | development | draft | cool, hot | MySpec.doc MySpec.pdf |
My doc 2 | development | published | cool, nice | MyURS.doc |
My doc (.) | marketing | published | nice | MyURS.doc |
this dynamic structure is published:

A resource is served as an collection, which is generated on-the-fly and contains some virtual files with additional information:

Usage¶
To publish the sample virtual resources, simply add thes lines to the configuration file:
# Publish a virtual structure
from wsgidav.samples.virtual_dav_provider import VirtualResourceProvider
addShare("virtres", VirtualResourceProvider())
Module description¶
Sample implementation of a DAV provider that provides a browsable, multi-categorized resource tree.
Note that this is simply an example with no concrete real world benefit. But it demonstrates some techniques to customize WsgiDAV.
Compared to a published file system, we have these main differences:
- A resource like
My doc 1
has several attributes likekey
,orga
,tags
,status
,description
. Also there may be a list of attached files. - These attributes are used to dynamically create a virtual hierarchy.
For example, if
status
isdraft
, a collection<share>/by_status/draft/
is created and the resource is mapped to<share>/by_status/draft/My doc 1
. - The resource
My doc 1
is rendered as a collection, that contains some virtual descriptive files and the attached files. - The same resource may be referenced using different paths
For example
<share>/by_tag/cool/My doc 1
,<share>/by_tag/hot/My doc 1
, and<share>/by_key/1
map to the same resource. Only the latter is considered the real-path, all others are virtual-paths. - The attributes are exposed as live properties, like “{virtres:}key”,
“{virtres:}tags”, and “{virtres:}description”.
Some of them are even writable. Note that modifying an attribute may also
change the dynamically created tree structure.
For example changing “{virtres:}status” from ‘draft’ to ‘published’ will
make the resource appear as
<share>/by_status/published/My doc 1
. - This provider implements native delete/move/copy methods, to change the
semantics of these operations for the virtual ‘/by_tag/’ collection.
For example issuing a DELETE on
<share>/by_tag/cool/My doc 1
will simply remove the ‘cool’ tag from that resource. - Virtual collections and artifacts cannot be locked.
However a resource can be locked.
For example locking
<share>/by_tag/cool/My doc 1
will also lock<share>/by_key/1
. - Some paths may be hidden, i.e. by_key is not browsable (but can be referenced) TODO: is this WebDAV compliant?
The database is a simple hard coded variable _resourceData
, that contains
a list of resource description dictionaries.
A resource is served as an collection, which is generated on-the-fly and contains some virtual files (artifacts).
In general, a URL is interpreted like this:
<share>/<category-type>/<category-key>/<resource-name>/<artifact-name>
An example layout:
<share>/
by_tag/
cool/
My doc 1/
.Info.html
.Info.txt
.Description.txt
MySpec.pdf
MySpec.doc
My doc 2/
hot/
My doc 1/
My doc 2/
nice/
My doc 2/
My doc 3
by_orga/
development/
My doc 3/
marketing/
My doc 1/
My doc 2/
by_status/
draft/
My doc 2
published/
My doc 1
My doc 3
by_key/
1/
2/
3/
When accessed using WebDAV, the following URLs both return the same resource ‘My doc 1’:
<share>/by_tag/cool/My doc 1
<share>/by_tag/hot/My doc 1
<share>/by_key/1
Attention
You are looking at outdated documentation for version 1.x. A newer version is available.
Attention
You are looking at outdated documentation for version 1.x. A newer version is available.
Attention
You are looking at outdated documentation for version 1.x. A newer version is available.
- Mercurial WebDAV provider
- WebDAV provider that publishes a Mercurial repository.
- MongoDB WebDAV provider
- WebDAV provider that publishes a mongoDB database.
- MySQL WebDAV provider
- Implementation of a WebDAV provider that provides a very basic, read-only resource layer emulation of a MySQL database.
- Google App Engine provider
- Implementation of a WebDAV provider that implements a virtual file system built on Google App Engine’s data store (‘Bigtable’). This project also implements a lock storage provider that uses memcache.
- Virtual WebDAV provider
- Sample implementation of a DAV provider that provides a browsable, multi-categorized resource tree.
- NT Domain Controller
- Implementation of a domain controller that allows users to authenticate against a Windows NT domain or a local computer (used by HTTPAuthenticator).
- MongoDB property manager
- Implementation of a property manager, that stores dead properties in mongoDB (used by WebDAV providers).
- CouchDB property manager
- Implementation of a property manager, that stores dead properties in CouchDB (used by WebDAV providers).
Attention
You are looking at outdated documentation for version 1.x. A newer version is available.
WsgiDAV Developers Guide¶
This section gives a brief introduction to the WsgiDAV application package (targeted to developers).
Attention
You are looking at outdated documentation for version 1.x. A newer version is available.
WsgiDAV Architecture¶
This document gives a brief introduction to the WsgiDAV application package (targeted to developers).
See also
WSGI application stack¶
WsgiDAV is a WSGI application.
WSGI <http://www.python.org/peps/pep-0333.html> stands for Web Server Gateway Interface, a proposed standard interface between web servers and Python web applications or frameworks, to promote web application portability across a variety of web servers. If you are unfamiliar with WSGI, do take a moment to read the PEP.
As most WSGI applications, WsgiDAV consists of middleware which serve as pre-filters and post-processors, and the actual application.
WSGI application stack:
<Request>
|
<Server> -> wsgidav_app.WsgiDavApp (container)
|
+-> debug_filter.WsgiDavDebugFilter (middleware, optional)
|
error_printer.ErrorPrinter (middleware)
|
http_authenticator.HTTPAuthenticator (middleware)
| \- Uses a domain controller object
|
dir_browser.WsgiDavDirBrowser (middleware, optional)
|
request_resolver.RequestResolver (middleware)
|
*-> request_server.RequestServer (application)
\- Uses a DAVProvider object
\- Uses a lock manager object
and a property manager object
This is default stack. Middleware order can be configured using
middleware_stack
option. You can write your own or extend existing
middleware and place it on middleware stack.
See the following sections for details.
WsgiDavApp¶
WSGI container, that handles the HTTP requests. This object is passed to the WSGI server and represents our WsgiDAV application to the outside.
On init:
Use the configuration dictionary to initialize lock manager, property manager, domain controller.
Create a dictionary of share-to-provider mappings.
Initialize middleware objects and RequestResolver and setup the WSGI application stack.
For every request:
Find the registered DAV provider for the current request.
Add or modify info in the WSGI
environ
:
- environ[“SCRIPT_NAME”]
- Mount-point of the current share.
- environ[“PATH_INFO”]
- Resource path, relative to the mount path.
- environ[“wsgidav.provider”]
- DAVProvider object that is registered for handling the current request.
- environ[“wsgidav.config”]
- Configuration dictionary.
- environ[“wsgidav.verbose”]
- Debug level [0-3].
Log the HTTP request, then pass the request to the first middleware.
Note: The OPTIONS method for the ‘*’ path is handled directly.
See Developers info for more information about the WsgiDAV architecture.
WsgiDavDebugFilter¶
WSGI middleware used for debugging (optional).
This module dumps request and response information to the console, depending on current debug configuration.
- On init:
- Define HTTP methods and litmus tests, that should turn on the verbose mode (currently hard coded).
- For every request:
Increase value of
environ['verbose']
, if the request should be debugged. Also dump request and response headers and body.Then pass the request to the next middleware.
These configuration settings are evaluated:
- verbose
This is also used by other modules. This filter adds additional information depending on the value.
verbose Effect 0 No additional output. 1 No additional output (only standard request logging). 2 Dump headers of all requests and responses. 3 Dump headers and bodies of all requests and responses. - debug_methods
Boost verbosity to 3 while processing certain request methods. This option is ignored, when
verbose < 2
.Configured like:
debug_methods = ["PROPPATCH", "PROPFIND", "GET", "HEAD","DELETE", "PUT", "COPY", "MOVE", "LOCK", "UNLOCK", ]
- debug_litmus
Boost verbosity to 3 while processing litmus tests that contain certain substrings. This option is ignored, when
verbose < 2
.Configured like:
debug_litmus = ["notowner_modify", "props: 16", ]
See Developers info for more information about the WsgiDAV architecture.
ErrorPrinter¶
Middleware error_printer.ErrorPrinter
Handle DAV exceptions and internal errors.
- On init:
- Store error handling preferences.
- For every request:
- Pass the request to the next middleware. If a DAV exception occurs, log info, then pass it on. Internal exceptions are converted to HTTP_INTERNAL_ERRORs.
HTTPAuthenticator¶
Middleware http_authenticator.HTTPAuthenticator
Uses a domain controller to establish HTTP authentication.
- On init:
- Store the domain controller object that is used for authentication.
- For every request:
if authentication is required and user is not logged in: return authentication response.
Else set these values:
``environ['httpauthentication.realm']`` ``environ['httpauthentication.username']``
WsgiDavDirBrowser¶
Middleware dir_browser.WsgiDavDirBrowser
Handles GET requests on collections to display a HTML directory listing.
On init:
For every request:
- If path maps to a collection:
- Render collection members as directory (HTML table).
RequestResolver¶
Middleware request_resolver.RequestResolver
Find the mapped DAV-Provider, create a new RequestServer instance, and dispatch
the request.
On init:
Store URL-to-DAV-Provider mapping.
For every request:
Setup
environ["SCRIPT_NAME"]
to request realm and andenviron["PATH_INFO"]
to resource path.Then find the registered DAV-Provider for this realm, create a new
RequestServer
instance, and pass the request to it.Note: The OPTIONS method for ‘*’ is handled directly.
RequestServer¶
Application request_server.RequestServer
Handles one single WebDAV request.
On init:
Store a reference to the DAV-Provider object.
For every request:
Handle one single WebDAV method (PROPFIND, PROPPATCH, LOCK, …) using a DAV-Provider instance. Then return the response body or raise an DAVError.
Note: this object only handles one single request.
Attention
You are looking at outdated documentation for version 1.x. A newer version is available.
WsgiDAV Modules¶
This document gives a brief introduction to the WsgiDAV application package (targeted to developers).
See also
DAV providers¶
DAV providers are abstractions layers that are used by the RequestServer
to
access and manipulate DAV resources.
All DAV providers must implement a common interface. This is usually done by
deriving from the abstract base class dav_provider.DAVProvider
.
WsgiDAV comes with a DAV provider for file systems, called
fs_dav_provider.FilesystemProvider
. That is why WsgiDAV is a WebDAV file
server out-of-the-box.
There are also a few other modules that may serve as examples on how to plug-in your own custom DAV providers: Samples and addons for WsgiDAV. See also Writing custom providers.
FilesystemProvider¶
Implementation of a DAV provider that serves resource from a file system.
ReadOnlyFilesystemProvider implements a DAV resource provider that publishes a file system for read-only access. Write attempts will raise HTTP_FORBIDDEN.
FilesystemProvider inherits from ReadOnlyFilesystemProvider and implements the missing write access functionality.
See Developers info for more information about the WsgiDAV architecture.
Property Managers¶
DAV providers may use a property manager to support persistence for dead properties.
WsgiDAV comes with two default implementations, one based on a in-memory dictionary, and a persistent one based in shelve:
property_manager.PropertyManager
property_manager.ShelvePropertyManager
PropertyManager
is used by default, but ShelvePropertyManager
can be
enabled by uncommenting two lines in the configuration file.
In addition, this may be replaced by a custom version, as long as the required interface is implemented.
Implements two property managers: one in-memory (dict-based), and one persistent low performance variant using shelve.
The properties dictionaray is built like:
{ ref-url1: {propname1: value1,
propname2: value2,
},
ref-url2: {propname1: value1,
propname2: value2,
},
}
See Developers info for more information about the WsgiDAV architecture.
Lock Managers¶
DAV providers may use a lock manager to support exclusive and shared write locking.
WsgiDAV comes with two default implementations, one based on a in-memory dictionary, and a persistent one based in shelve:
lock_manager.LockManager
lock_manager.ShelveLockManager
LockManager
is used by default, but ShelveLockManager
can be
enabled by uncommenting two lines in the configuration file.
In addition, this may be replaced by a custom version, as long as the required interface is implemented.
Implements the LockManager object that provides the locking functionality.
The LockManager requires a LockStorage object to implement persistence. Two alternative lock storage classes are defined in the lock_storage module:
- wsgidav.lock_storage.LockStorageDict
- wsgidav.lock_storage.LockStorageShelve
The lock data model is a dictionary with these fields:
- root:
- Resource URL.
- principal:
- Name of the authenticated user that created the lock.
- type:
- Must be ‘write’.
- scope:
- Must be ‘shared’ or ‘exclusive’.
- depth:
- Must be ‘0’ or ‘infinity’.
- owner:
- String identifying the owner.
- timeout:
- Seconds remaining until lock expiration. This value is passed to create() and refresh()
- expire:
- Converted timeout for persistence: expire = time() + timeout.
- token:
- Automatically generated unique token.
See Developers info for more information about the WsgiDAV architecture.
Domain controllers¶
A domain controller provides user/password checking for a realm to the HTTPAuthenticator.
WsgiDAV comes with a default implementation that reads a user/password list from the config file.
However, this may be replaced by a custom version, as long as the required interface is implemented.
wsgidav.addons.nt_domain_controller
is an example for such an extension.
Other objects¶
wsgidav.domain_controller.WsgiDAVDomainController
- Default implementation of a domain controller as used by
HTTPAuthenticator
.
Attention
You are looking at outdated documentation for version 1.x. A newer version is available.
WsgiDAV Glossary¶
This document defines some terms gives a brief introduction to the WsgiDAV application package (targeted to developers).
See also
You can find more information about WebDAV terms and naming convention in official WebDAV specification documentation.
You will find this terms / naming conventions in the source:
- URL:
In general URLs follow these rules:
- Byte strings, using ISO-8859-1 encoding
- Case sensitive
- Quoted, i.e. special characters are escaped
- Collections have a trailing ‘/’ (but we also accept request URLs, that omit them.)
- When we use the term URL in WsgiDAV variables, we typically mean absolute URLs:
/<mount>/<path>
- When we use the term full URL, we typically mean complete URLs:
http://<server>:<port>/<mount>/<path>
- Constructed like
- fullUrl = util.makeCompleteURL(environ)
- Example
- “http://example.com:8080/dav/public/my%20nice%20doc.txt”
- Path (in general):
When we use the term Path in WsgiDAV variables, we typically mean unquoted URLs, relative to the mount point.
- Example
- “/public/my nice doc.txt”
- mount point (also ‘mount path’, ‘approot’):
Unquoted, ISO-8859-1 encoded byte string.
The application’s mount point. Starts with a ‘/’ (if not empty).
This is the virtual directory, where the web server mounted the WsgiDAV application. So it is the environ[SCRIPT_NAME] that the server had set, before calling WsgiDAVApp.
- Example
- “”
- share path (also ‘share’, ‘domain’):
Unquoted, ISO-8859-1 encoded byte string.
The application’s share path, relative to the mount point. Starts with a ‘/’ (if not empty).
For every request, WsgiDAVApp tries to find the registered provider for the URL (after the mount path was popped). The share path is the common URL prefix of this URL.
TODO: do we need to ditinguish between server mount points (‘mount path’) and WsgiDAV mount points (‘share path’)?
- Constructed like
- mountPath = environ[SCRIPT_NAME]
- Example
- “/dav”
- realm:
Unquoted, ISO-8859-1 encoded byte string.
The domain name, that a resource belongs to.
This string is used for HTTP authentication.
Each realm would have a set of username and password pairs that would allow access to the resources.
- Examples
- “Marketing Department” “Windows Domain Authentication”
The
domain_controller.WsgiDAVDomainController
implementation uses the mount path as realm name.- path
Unquoted, ISO-8859-1 encoded byte string.
The resource URL, relative to the application’s mount point. Starts with a ‘/’. Collections also should have a trailing ‘/’.
- Constructed like:
- path = environ[PATH_INFO]
- Examples:
- “/public/my nice doc.txt” “/public/”
- preferred path:
Unquoted, ISO-8859-1 encoded byte string.
The preferred or normalized path.
Depending on case sensitivity of the OS file system, all these paths may map to the same collection resource:
/public/my folder/ /public/my folder (missing '/') /public/MY FOLDER/ (on a Windows server, which is not case sensitive)
provider.getPreferredPath(path) will return:
/public/my folder/
for all of these variants.
- reference URL:
Quoted, UTF-8 encoded byte string.
This is basically the same as an URL, that was build from the preferred path. But this deals with ‘virtual locations’ as well.
Since it is always unique for one resource, <refUrl> is used as key for the lock- and property storage.
A resource has always one ‘real location’ and may have 0..n ‘virtual locations’.
For example:
/dav/public/my%20folder/file1.txt /dav/by_key/1234 /dav/by_status/approved/file1.txt
may map to the same resource, but only:
/dav/by_key/1234
is the refUrl.
- Constructed like:
- realUrl = quote(mountPath + reference path)
- Examples:
- “/dav/by_key/1234”
- href:
Quoted, UTF-8 encoded byte string.
Used in XML responses. We are using the path-absolute option. i.e. starting with ‘/’. (See http://www.webdav.org/specs/rfc4918.html#rfc.section.8.3)
- Constructed like:
- href = quote(mountPath + preferredPath)
- Example:
- “/dav/public/my%20nice%20doc.txt”
- filePath:
Unicode
Used by fs_dav_provider when serving files from the file system. (At least on Vista) os.path.exists(filePath) returns False, if a file name contains special characters, even if it is correctly UTF-8 encoded. So we convert to unicode.
Attention
You are looking at outdated documentation for version 1.x. A newer version is available.
Attention
You are looking at outdated documentation for version 1.x. A newer version is available.
WsgiDAV API Doc¶
This section gives a brief introduction to the WsgiDAV application package (targeted to developers).
Overview¶
wsgidav package:
Classes¶

Packages¶
wsgidav¶
wsgidav.dav_error |
Implements a DAVError class that is used to signal WebDAV and HTTP errors. |
wsgidav.dav_provider |
Abstract base class for DAV resource providers. |
wsgidav.debug_filter |
WSGI middleware used for debugging (optional). |
wsgidav.dir_browser |
WSGI middleware that handles GET requests on collections to display directories. |
wsgidav.domain_controller |
Implementation of a domain controller that uses realm/username/password mappings from the configuration file and uses the share path as realm name. |
wsgidav.error_printer |
WSGI middleware to catch application thrown DAVErrors and return proper responses. |
wsgidav.fs_dav_provider |
Implementation of a DAV provider that serves resource from a file system. |
wsgidav.http_authenticator |
WSGI middleware for HTTP basic and digest authentication. |
wsgidav.lock_manager |
Implements the LockManager object that provides the locking functionality. |
wsgidav.lock_storage |
Implements two storage providers for LockManager. |
wsgidav.middleware |
Abstract base middleware class |
wsgidav.property_manager |
Implements two property managers: one in-memory (dict-based), and one persistent low performance variant using shelve. |
wsgidav.request_resolver |
WSGI middleware that finds the registered mapped DAV-Provider, creates a new RequestServer instance, and dispatches the request. |
wsgidav.request_server |
WSGI application that handles one single WebDAV request. |
wsgidav.rw_lock |
ReadWriteLock |
wsgidav.util |
Miscellaneous support functions for WsgiDAV. |
wsgidav.version |
Current WsgiDAV version number. |
wsgidav.wsgidav_app |
WSGI container, that handles the HTTP requests. |
wsgidav.xml_tools |
Small wrapper for different etree packages. |
wsgidav.samples¶
wsgidav.samples.dav_provider_tools |
|
wsgidav.samples.mongo_dav_provider |
|
wsgidav.samples.virtual_dav_provider |
Sample implementation of a DAV provider that provides a browsable, multi-categorized resource tree. |
wsgidav.addons¶
wsgidav.addons.couch_property_manager |
|
wsgidav.addons.hg_dav_provider |
|
wsgidav.addons.mongo_property_manager |
|
wsgidav.addons.mysql_dav_provider |
|
wsgidav.addons.nt_domain_controller |
wsgidav.server¶
wsgidav.server.ext_wsgiutils_server |
ext_wsgiutils_server.py is an extension of the wsgiutils server in Paste. |
wsgidav.server.run_reloading_server |
Wrapper for run_server , that restarts the server when source code is modified. |
wsgidav.server.run_server |
run_server |
wsgidav.server.server_sample |
Attention
You are looking at outdated documentation for version 1.x. A newer version is available.
FAQ¶
- What do I need to run WsgiDAV?
- See Installing WsgiDAV for details.
- Which web servers are supported?
WsgiDAV comes with a standalone server, to run out of the box. There is also built-in support for CherryPy, Paste, and wsgiref servers, as long as these packages are installed. (Fast)CGI should be possible using flup.
Basically, it runs with all WSGI servers. Currently we tested with Pylons, CherryPy, Paste server.
See Configure and Run WsgiDAV Server for details.
- Which configuration do you recommend?
Currently CherryPy seems to be very robust. Also installing lxml is recommended.
But since WsgiDAV is pretty new, please provide feedback on your experience.
- Which WebDAV clients are supported?
Basically all WebDAV clients on all platforms, though some of them show odd behaviors.
See Access WsgiDAV with WebDAV Clients for details.
- I found a bug, what should I do?
First, check the issue list, if this is a known bug. If not, open a new issue and provide detailed information how to reproduce it.
Then fix it and send me the patch ;-)
- How do you pronounce WsgiDAV?
- Don’t care really, but I would say ‘Whiskey Dove’. (Still looking for a cool logo ;) Edit: thanks to Markus Majer for providing one!
contents