Attention
You are looking at outdated documentation for version 2.x. A newer version is available.
WsgiDAV Documentation¶
A generic and extendable WebDAV server written in Python and based on WSGI.
Project: | https://github.com/mar10/wsgidav/ |
---|---|
Version: | 2.4, Date: May 19, 2019 |
Attention
You are looking at outdated documentation for version 2.x. A newer version is available.
Installation¶
This section describes, how a WsgiDAV server is installed.
See also
If you plan to contribute to the WsgiDAV project, check out Development for details on how to install in development mode.
Preconditions¶
WsgiDAV server was tested with these operating systems (among others):
- Linux (Ubuntu 13)
- Mac OS X 10.9
- Windows (Windows 10, 8, 7, Vista, XP)
WsgiDAV requires
Unix / Linux¶
Releases are hosted on PyPI and can be installed using pip:
$ pip install --upgrade wsgidav
Or install the latest (potentially unstable) development version directly from GitHub:
$ pip install git+https://github.com/mar10/wsgidav.git
In order to run the WsgiDAV server from the command line, we also need a WSGI server such as Cheroot:
$ pip install cheroot
The following examples were tested on Ubuntu 13.04. Install lxml (optional):
$ sudo apt-get install python-lxml
If everything is cool, this should work now:
$ wsgidav --version -v
WsgiDAV/2.4.0 Python/3.6.1 Darwin-17.5.0-x86_64-i386-64bit
$ wsgidav --help
Windows¶
Install the preconditions if neccessary. Basically the same as for Unix / Linux
Note
MS Windows users that only need the command line interface may prefer the MSI installer.
Attention
You are looking at outdated documentation for version 2.x. A newer version is available.
User Guide¶
This section describes how to use the WsgiDAV library.
(Read Development to learn how to contribute to this project.)
Attention
You are looking at outdated documentation for version 2.x. A newer version is available.
Command Line Interface¶
This section describes how to use WsgiDAV from the command line.
The WsgiDAV server was tested with these platforms
- Mac OS X 10.9 - 10.13
- Ubuntu 13 - 16
- Windows (Win 7 - 10, Vista, XP)
To serve the /tmp
folder as WebDAV /
share, simply run:
$ wsgidav --host=0.0.0.0 --port=80 --root=/tmp
WARNING: share '/' will allow anonymous access.
Running WsgiDAV/2.3.1 Cheroot/6.0.0 Python/3.6.1
Serving on http://127.0.0.1:8080 ...
Warning
By default, WsgiDAV will publish the folder for anonymous access. Read Configuration how to set up authentication.
CLI Options¶
Use the --help
or -h
argument to get help:
$ wsgidav --help
usage: wsgidav [-h] [-p PORT] [-H HOST] [-r ROOT_PATH]
[--server {cheroot,cherrypy-wsgiserver,ext-wsgiutils,flup-fcgi,flup-fcgi-fork,paste,wsgiref}]
[--ssl-adapter {builtin,pyopenssl}] [-v] [-q] [-c CONFIG_FILE]
[--no-config] [-V]
Run a WEBDAV server to share file system folders.
Examples:
Share filesystem folder '/temp':
wsgidav --port=80 --host=0.0.0.0 --root=/temp
Run using a specific configuration file:
wsgidav --port=80 --host=0.0.0.0 --config=~/wsgidav.conf
If no config file is specified, the application will look for a file named
'wsgidav.conf' in the current directory.
See
http://wsgidav.readthedocs.io/en/latest/run-configure.html
for some explanation of the configuration file format.
optional arguments:
-h, --help show this help message and exit
-p PORT, --port PORT port to serve on (default: 8080)
-H HOST, --host HOST host to serve from (default: localhost). 'localhost' is only accessible from the local computer. Use 0.0.0.0 to make your application public
-r ROOT_PATH, --root ROOT_PATH
path to a file system folder to publish as share '/'.
--server {cheroot,cherrypy-wsgiserver,ext-wsgiutils,flup-fcgi,flup-fcgi-fork,paste,wsgiref}
type of pre-installed WSGI server to use (default: cheroot).
--ssl-adapter {builtin,pyopenssl}
used by 'cheroot' server if SSL certificates are configured (default: builtin.
-v, --verbose increment verbosity by one (default: 1, range: 0..5)
-q, --quiet set verbosity 0: suppress any output except for errors
-c CONFIG_FILE, --config CONFIG_FILE
configuration file (default: wsgidav.conf in current directory)
--no-config do not try to load default wsgidav.conf
-V, --version show program's version number and exit
Licensed under the MIT license.
See https://github.com/mar10/wsgidav for additional information.
$
Use a Configuration File¶
Much more options are available when a configuration file is specified.
By default wsgidav.conf
and wsgidav.json
is searched in the local directory.
An alternative file name can be specified like so:
$ wsgidav --config=my_config.conf
To prevent the use of of a local default configuration file, use this option:
$ wsgidav --no-config
See also
Attention
You are looking at outdated documentation for version 2.x. A newer version is available.
Configuration¶
This document describes the configuration options of a WsgiDAV server.
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)
The options described below can be defined for the CLI either
Note
The three supported file formats are just different ways for the CLI to
generate a Python dict that is then passed to the
WsgiDAVApp
constructor.
See the annotated_wsgidav.conf
For a start, you should copy
Sample Configuration
or
Annotated Sample Configuration
and edit it to your needs.
You can also start with a
(YAML Sample Configuration
) or a
(JSON Sample Configuration
).
Verbosity Level¶
The verbosity level can have a value from 0 to 5 (default: 3):
Verbosity | Option | Log level | Remarks |
---|---|---|---|
0 | -qqq | CRITICAL | quiet |
1 | ERROR | no output (excepting application exceptions) | |
2 | -q | WARN | warnings and errors only |
3 | INFO | show single line request summaries (for HTTP logging) | |
4 | -v | DEBUG | show additional events |
5 | -vv | DEBUG | show full request/response header info (HTTP Logging) request body and GET response bodies not shown |
Sample wsgidav.yaml
¶
The YAML syntax is probably the most concise format to define configuration:
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 | # Sample WsgiDAV configuration file
#
# 1. Rename this file to `wsgidav.yaml`
# 2. Adjust settings as appropriate
# 3. Run `wsgidav` from the same directory or pass file name with `--config` option.
#
# See http://wsgidav.readthedocs.io/en/latest/user_guide_configure.html
host: 0.0.0.0
port: 8080
# Set verbosity to standard
verbose: 1
# Remove this block to prevent directory browsing
dir_browser:
enable: true
response_trailer:
davmount: false
ms_mount: false
ms_sharepoint_plugin: true
ms_sharepoint_urls: false
provider_mapping:
"/share1": "/path/to/share1"
"/share2": "/path/to/share2"
user_mapping:
"/share1":
"user1":
password: "abc123"
description: "User 1 for Share 1"
roles: []
"/share2":
"user1":
password: "def456"
description: "User 1 for Share 2"
roles: []
"user2":
password: "qwerty"
description: "User 2 for Share 2"
roles: []
acceptbasic: false
acceptdigest: true
defaultdigest: true
|
Sample wsgidav.json
¶
We can also use a JSON file for configuration if we don’t require the full power of Python code to set everything up.
Note that the parser ignores JavaScript-style comments:
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 | /* Sample WsgiDAV configuration file
*
* 1. Rename this file to `wsgidav.json`
* 2. Adjust settings as appropriate
* 3. Run `wsgidav` from the same directory or pass file name with `--config` option.
*
* JSON formatted, but JavaScript-style comments are allowed.
*
* See http://wsgidav.readthedocs.io/en/latest/user_guide_configure.html
*/
{
"host": "0.0.0.0",
"port": 8080,
// Verbosity 0..3
"verbose": 1,
// Remove this block to prevent directory browsing
"dir_browser": {
"enable": true,
"response_trailer": "",
"davmount": false,
"ms_mount": false,
"ms_sharepoint_plugin": true,
"ms_sharepoint_urls": false
},
"provider_mapping": {
"/share1": "/path/to/share1",
"/share2": "/path/to/share2"
},
"user_mapping": {
"/share1": {
"user1": {
"password": "abc123",
"description": "User 1 for Share 1",
"roles": []
}
},
"/share2": {
"user1": {
"password": "def456",
"description": "User 1 for Share 2",
"roles": []
},
"user2": {
"password": "qwerty",
"description": "User 2 for Share 2",
"roles": []
}
}
},
"acceptbasic": false,
"acceptdigest": true,
"defaultdigest": true
}
|
Sample wsgidav.conf
¶
This format uses plain Python syntax, which allows us to use Python data structures, and even write helpers function, etc.
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 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 |
# Note: This file is in Python syntax and format
################################################################################
# WsgiDAV configuration file
# See
# http://wsgidav.readthedocs.io/en/latest/run-configure.html
# for some explanation of the configuration file format.
################################################################################
# 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
#===============================================================================
# Run WsgiDAV inside this WSGI server.
# Supported servers: "cheroot", "cherrypy-wsgiserver", "ext_wsgiutils",
# "flup-fcgi", "flup-fcgi-fork", "paste", "wsgiref"
# 'wsgiref' and 'ext_wsgiutils' are simple builtin servers that should *not* be
# used in production.
# All other servers must have been installed before, e.g. `pip install cheroot`.
# (The binary distribution already includes 'cheroot'.)
# Default: "cheroot", use the --server option on command line to change this.
#server = "cheroot"
# Additional arguments passed to the server on initialization (depends on `server`)
# For example for cheroot:
#server_args = {
# "numthreads": 10,
# "max": -1,
# "request_queue_size": 5,
# "timeout": 10,
# "shutdown_timeout": 5,
# "verbose": 0,
#}
# Server port (default: 8080, use --port on command line)
port = 8080
# Server hostname (default: localhost, use --host on command line)
host = "localhost"
#===============================================================================
# Enable SSL support
# Note:
# A valid certificate must match the servers hostname, so the bogus certs will
# not work in all scenarios.
# Create your own certificates instead!
# ssl_certificate = "wsgidav/server/sample_bogo_server.crt"
# ssl_private_key = "wsgidav/server/sample_bogo_server.key"
# ssl_certificate_chain = None
# Cheroot server supports 'builtin' and 'pyopenssl' (default: 'builtin')
# ssl_adapter = "pyopenssl"
#================================================================================
# Misc. setings
#
# Add the MS-Author-Via Response Header to OPTIONS command to allow editing
# with Microsoft Office (default: False)
add_header_MS_Author_Via = True
# Block size in bytes
# block_size = 8192
# Set this to True, to force unquoting of PATH_INFO. This should already be done by the WSGI
# Framework, so this setting should only be used to fix unexpected problems there (see issue #8).
# unquote_path_info = False
# Re-encode PATH_INFO using UTF-8 (falling back to ISO-8859-1).
# This seems to be wrong, since per PEP 3333 PATH_INFO is always ISO-8859-1 encoded
# (see https://www.python.org/dev/peps/pep-3333/#unicode-issues).
# However it seems to resolve errors when accessing resources with Chinese characters, for
# example (see issue #73).
# Set to `None` (the default) to enable this for Python 3 only.
# re_encode_path_info = None
#===============================================================================
# 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 = 3 # 0 - quiet
# 1 - no output (excepting application exceptions)
# 2 - warnings and errors only
# 3 - show single line request summaries (HTTP logging)
# 4 - show additional events
# 5 - 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, # (DEPRECATED with 2.4.0) 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 2.x. A newer version is available.
WebDAV Clients¶
This section describes, how a WsgiDAV server can be accessed with different clients.

WsgiDAV was tested with these clients
- Windows 7, 8, 10
- Windows Vista (Microsoft-WebDAV-!MiniRedir/6.0.6002)
- Window XP (Microsoft-WebDAV-!MiniRedir/5.1.2600)
- DAVExplorer
- Microsoft® 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
Mac¶
OS/X Finder¶
In the Finder menu, choose Go and Connect to Server….
1. Enter the URI of the WsgiDAV server: http://192.168.0.2/dav 1. Click the [+] button behind it to keep the server URI. 1. Click the [Connect] button at the bottom. 1. Enter credentials and click [Connect] 1. Browse, search, and so on. The volume is on the desktop.
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 2.x. A newer version is available.
Using the Library¶
This section describes how to use the wsgidav
package to implement custom
WebDAV servers.
Todo
This documentation is still under construction.
The wsgidav
package can be used in Python code:
$ python
>>> from wsgidav import __version__
>>> __version__
'2.3.1'
Run Inside a WSGI Server¶
The WsgiDAV server was tested with these WSGI servers:
- Cheroot
- cherrypy.wsgiserver
- paste.httpserver
- Pylons
- wsgidav.ext_wsgiutils_server (bundled with WsgiDAV)
- wsgiref.simple_server
In order to run WsgiDAV, we need to create an instance of WsgiDAVApp
,
pass options, and mount it on a WSGI compliant web server.
Here we keep most of the default options and use the
cheroot WSGI server
from cheroot import wsgi
from wsgidav.wsgidav_app import WsgiDAVApp
config = {
"host": "0.0.0.0",
"port": 8080,
"mount_path": "/dav",
"root": "/User/joe/pub",
"verbose": 1,
}
app = WsgiDAVApp(config)
server_args = {
"bind_addr": (config["host"], config["port"]),
"wsgi_app": app,
}
server = wsgi.Server(**server_args)
server.start()
Options are passed as Python dict, see the Configuration for details.
By default, the FilesystemProvider
is used.
This provider creates instances of FileResource
and FolderResource
to represent files and
directories respectively.
This is why the example above will publish the directory /User/joe/pub
as
http://HOST:8080/dav
.
See the Sample WSGI Server for another example.
Run Inside Pylons¶
See Running as Pylons controller for an example how WsgiDAV can be configured as Pylons controller.
Custom Providers¶
If we want to implement custom behavior, we can define our own variant of a
(derived from DAVProvider
), which typically also
uses custom instances of DAVNonCollection
and
DAVCollection
.
from cheroot import wsgi
from wsgidav.wsgidav_app import WsgiDAVApp
from bar_package import FooProvider
config = {
"host": "0.0.0.0",
"port": 8080,
"provider_mapping": {
"/dav": FooProvider(),
},
"verbose": 1,
}
app = WsgiDAVApp(config)
Logging¶
By default, the library initializes and uses a python logger named ‘wsgidav’ and sub-loggers named like ‘wsgidav.wsgidav_app’, etc.
By default, the wsgidav logger only has a NullHandler
assigned and does not propagate
to the root logger, so it is silent.
This logger can be enabled like so:
import logging
logger = logging.getLogger("wsgidav")
logger.propagate = True
logger.setLevel(logging.DEBUG)
Note
The CLI calls util.initLogging()
on startup, so it logs to stdout as configured
by the verbose
and enable_loggers
options.
Attention
You are looking at outdated documentation for version 2.x. A newer version is available.
Writing Custom Providers¶
Note
This documentation is under construction.
Samples and Addons for WsgiDAV¶
Attention
You are looking at outdated documentation for version 2.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 2.x. A newer version is available.
MongoDB WebDAV provider¶
Module description¶
Implementation of a WebDAV provider that provides a very basic, read-only resource layer emulation of a MongoDB database.
Usage: add the following entries to wsgidav.conf:
from wsgidav.samples.mongo_dav_provider import MongoResourceProvider
mongo_dav_opts = {}
addShare("mongo", MongoResourceProvider(mongo_dav_opts))
Valid options are (sample shows defaults):
opts = {"host": "localhost", # MongoDB server
"port": 27017, # MongoDB port
# This options are used with `mongod --auth`
# The user must be created in the admin db with
# > use admin
# > db.addUser(username, password)
"user": None, # Authenticate with this user
"pwd": None, # ... and password
}
Attention
You are looking at outdated documentation for version 2.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¶
Implementation of a WebDAV provider that provides a very basic, read-only resource layer emulation of a MySQL database.
This module is specific to the WsgiDAV application. It provides a
classes MySQLBrowserProvider
.
Usage:
(see doc/annotated_wsgidav.conf)
MySQLBrowserProvider(host, user, passwd, db)
host - host of database server
user - username to access database
passwd - passwd to access database
db - name of database on database server
The MySQLBrowserProvider
provides a very basic, read-only
resource layer emulation of a MySQL database.
It provides the following interface:
- the root collection shared consists of collections that correspond to table names
- in each table collection, there is a resource called “_ENTIRE_CONTENTS”. This is a non-collection resource that returns a csv representation of the entire table
- if the table has a single primary key, each table record will also appear as a non-collection resource in the table collection using the primary key value as its name. This resource returns a csv representation of the record and will also include the record attributes as live properties with attribute name as property name and table name suffixed with colon as the property namespace
This is a very basic interface and below is a by no means thorough summary of its limitations:
- Really only supports having numbers or strings as primary keys. The code uses a numeric or string comparison that may not hold up if the primary key is a date or some other datatype.
- There is no handling for cases like BLOBs as primary keys or such. Well, there is no handling for BLOBs in general.
- When returning contents, it buffers the entire contents! A bad way to return large tables. Ideally you would have a FileMixin that reads the database even as the application reads the file object….
- It takes too many database queries to return information. Ideally there should be some sort of caching for metadata at least, to avoid unnecessary queries to the database.
Attention
You are looking at outdated documentation for version 2.x. A newer version is available.
Attention
You are looking at outdated documentation for version 2.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 2.x. A newer version is available.
NT Domain Controller¶
Examples¶
TODO
Usage¶
TODO
Module description¶
Implementation of a domain controller that allows users to authenticate against a Windows NT domain or a local computer (used by HTTPAuthenticator).
Usage:
from wsgidav.addons.nt_domain_controller import NTDomainController
domaincontroller = NTDomainController(presetdomain=None, presetserver=None)
where:
- domaincontroller object corresponds to that in
wsgidav.conf
or as input intowsgidav.http_authenticator.HTTPAuthenticator
. - presetdomain allows the admin to specify a domain to be used (instead of any domain that may come as part of the username in domainuser). This is useful only if there is one domain to be authenticated against and you want to spare users from typing the domain name
- presetserver allows the admin to specify the NETBIOS name of the domain controller to be used (complete with the preceding \). if absent, it will look for trusted domain controllers on the localhost.
This class allows the user to authenticate against a Windows NT domain or a local computer, requires NT or beyond (2000, XP, 2003, etc).
This class requires Mark Hammond’s Win32 extensions for Python at here or sourceforge
Information on Win32 network authentication was from the following resources:
- Digest Authentication
Digest authentication requires the password to be retrieve from the system to compute the correct digest for comparison. This is so far impossible (and indeed would be a big security loophole if it was allowed), so digest authentication WILL not work with this class.
Highly recommend basic authentication over SSL support.
- User Login
Authentication will count as a user login attempt, so any security in place for invalid password attempts may be triggered.
Also note that, even though the user is logged in, the application does not impersonate the user - the application will continue to run under the account and permissions it started with. The user has the read/write permissions to the share of the running account and not his own account.
- Using on a local computer
- This class has been tested on a local computer (Windows XP). Leave domain as None and do not specify domain when entering username in this case.
- Using for a network domain
- This class is being tested for a network domain (I’m setting one up to test).
ml
Attention
You are looking at outdated documentation for version 2.x. A newer version is available.
MongoDB property manager¶
Note
This is not production code.
Module description¶
Implements a property manager based on MongoDB.
Usage: add this lines to wsgidav.conf:
from wsgidav.addons.mongo_property_manager import MongoPropertyManager
prop_man_opts = {}
propsmanager = MongoPropertyManager(prop_man_opts)
Valid options are (sample shows defaults):
opts = {"host": "localhost", # MongoDB server
"port": 27017, # MongoDB port
"dbName": "wsgidav-props", # Name of DB to store the properties
# This options are used with `mongod --auth`
# The user must be created with db.addUser()
"user": None, # Authenticate with this user
"pwd": None, # ... and password
}
Attention
You are looking at outdated documentation for version 2.x. A newer version is available.
CouchDB property manager¶
Note
This is not production code.
Module Description¶
Implements a property manager based on CouchDB.
http://wiki.apache.org/couchdb/Reference http://packages.python.org/CouchDB/views.html
Usage: add this lines to wsgidav.conf:
from wsgidav.addons.couch_property_manager import CouchPropertyManager
prop_man_opts = {}
propsmanager = CouchPropertyManager(prop_man_opts)
Valid options are (sample shows defaults):
opts = {"url": "http://localhost:5984/", # CouchDB server
"dbName": "wsgidav-props", # Name of DB to store the properties
}
Note
Not all samples have yet been ported to WsgiDAV 2.x.
- 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 2.x. A newer version is available.
FAQ¶
- What do I need to run WsgiDAV?
- See run-install 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 run-configure 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 run-access 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’.
Attention
You are looking at outdated documentation for version 2.x. A newer version is available.
Reference Guide¶
This document gives a brief introduction to the WsgiDAV application package (targeted to developers).
Attention
You are looking at outdated documentation for version 2.x. A newer version is available.
Architecture¶
This document gives a brief introduction to the WsgiDAV application package (targeted to developers).
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.
WsgiDAV implements this 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
Note
This is the default stack. Middleware applications and 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.
Building Blocks¶
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 DAVProvider
.
WsgiDAV comes with a DAV provider for file systems, called
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 (see also Writing Custom Providers).
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 on 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.
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 on 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.
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.
WsgiDAVDomainController
- Default implementation of a domain controller as used by
HTTPAuthenticator
.
Applications¶

WsgiDavApp¶
WsgiDavDebugFilter¶
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 2.x. A newer version is available.
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 2.x. A newer version is available.
API Doc¶
Package wsgidav
¶
wsgidav._version |
Package version number. |
wsgidav.compat |
Tool functions to support Python 2 and 3. |
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.wsgidav_app |
WSGI container, that handles the HTTP requests. |
wsgidav.xml_tools |
Small wrapper for different etree packages. |
Package wsgidav.addons
¶
wsgidav.addons.couch_property_manager |
Implements a property manager based on CouchDB. |
wsgidav.addons.hg_dav_provider |
|
wsgidav.addons.mongo_property_manager |
Implements a property manager based on MongoDB. |
wsgidav.addons.mysql_dav_provider |
Implementation of a WebDAV provider that provides a very basic, read-only resource layer emulation of a MySQL database. |
wsgidav.addons.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). |
Package wsgidav.samples
¶
wsgidav.samples.dav_provider_tools |
Tools that make it easier to implement custom WsgiDAV providers. |
wsgidav.samples.mongo_dav_provider |
Implementation of a WebDAV provider that provides a very basic, read-only resource layer emulation of a MongoDB database. |
wsgidav.samples.virtual_dav_provider |
Sample implementation of a DAV provider that provides a browsable, multi-categorized resource tree. |
Package 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 server_cli , that restarts the server when source code is modified. |
wsgidav.server.server_cli |
server_cli |
wsgidav.server.server_sample |
Simple example how to a run WsgiDAV in a 3rd-party WSGI server. |
Attention
You are looking at outdated documentation for version 2.x. A newer version is available.
Index¶
Attention
You are looking at outdated documentation for version 2.x. A newer version is available.
Development¶
This section describes how developers can contribute to the WsgiDAV project.
First off, thanks for taking the time to contribute!
There are many ways you can help:
- Send feedback:
Know a cool project that uses it, created a custom provider or have an interesting use case? Let us know in the forum . - Create issues for bugs or feature requests (see Bug Reports and Feature Requests below).
- Help others, by answering questions in the forum or on Stackoverflow.
- Improve this documentation.
- Fix bugs or propose features.
This small guideline may help taking the first steps.
Happy hacking :)
Bug Reports and Feature Requests¶
If you have encountered a problem with WsgiDAV or have an idea for a new feature, please submit it to the issue tracker on GitHub.
Note
The issue tracker is for bugs and feature requests. Please use the Q&A forum or Stackoverflow to ask questions.
Use the search function to find existing issues if any. If you have additional information, add a comment there instead of creating a new issue.
If it’s a bug report:
- Carefully describe the required steps to reproduce the failure.
- Give additional information about the server: (OS version, WsgiDAV version, WSGI server setup)? Which settings are enabled (configuration file)?
- What client are you using (OS, client software and -version)?
- What output do you see on the console or log files?
- Maybe attach a patch file or describe a potential fix?
If it’s a feature request:
- What are you trying to accomplish?
- Why is this a cool feature? Give use cases.
- Can you propose a specification? Are there similar implementations in other projects? Add references or screenshots if you have some. Remember that the general API must stay generic, extensible, and consistent. How will this interfere with existing API and functionality? Does it play well with the other extensions?
Contributing Code¶
Note
Please open (or refer to) an issue, even if you provide a pull request. It will be useful to discuss different approaches or upcoming related problems.
The recommended way for new contributors to submit code to WsgiDAV is to fork the repository on GitHub and then submit a pull request after committing the changes. The pull request will then need to be approved before it is merged.
- Check for open issues or open a fresh issue to start a discussion around a feature idea or a bug.
- Fork the repository on GitHub.
- Clone the repo to your local computer
- Setup the project for development
- Create and activate your feature branch
- Hack, Hack, Hack
- Test, Test, Test
- Send a pull request and bug the maintainer until it gets merged and published.
Note
Don’t mix different topics in a single commit or issue. Instead submit a new pull request (and even create separate branches as apropriate).
Setup for Development¶
Fork the Repository¶
Create an account on GitHub.
Fork the main WsgiDAV repository (mar10/wsgidav) using the GitHub interface.
Clone your forked repository to your machine.
git clone https://github.com/YOUR_USERNAME/wsgidav cd wsgidav
Create and activate a new working branch. Choose any name you like.
git checkout -b feature-xyz
Create and Activate a Virtual Environment¶
Virtual environments allow us to develop and test in a sandbox, without affecting our
system othwerwise.
We need Python 2.7,
Python 3.4+,
and pip on our system.
If you want to run tests on all supported platforms, install Python 2.7, 3.4, 3.5, and 3.6.
On Linux/OS X, we recommend to use pipenv to activate a virtual environment:
$ cd /path/to/wsgidav
$ pipenv shell
bash-3.2$
Note: On Ubuntu you additionally may have to install apt-get install python3-venv
.
Alternatively (especially on Windows), use virtualenv
to create and activate the virtual environment.
For example using Python’s builtin venv
(instead of virtualenvwrapper
)
in a Windows PowerShell:
> cd /path/wsgidav
> py -3.6 -m venv c:\env\wsgidav_py36
> c:\env\wsgidav_py36\Scripts\Activate.ps1
(wsgidav_py36) $
Install Requirements¶
Now that the new environment exists and is activated, we can setup the requirements:
$ pip install -r requirements-dev.txt
and install wsgidav to run from source code:
$ pip install -e .
If everything is cool, this code should now run:
$ wsgidav --version
$ 2.3.1
The test suite should run as well:
$ tox
Hack, Hack, Hack¶
Test, Test, Test¶
Testing is best done through tox
, which provides a number of targets and
allows testing against multiple different Python environments:
To run all unit tests on all suppprted Python versions inclusive flake8 style checks and code coverage:
$ tox
To run unit tests for a specific Python version, such as 3.6:
$ tox -e py36
To run selective tests, ww can call
py.test
directly, e.g.:$ py.test -ra wsgidav tests/test_util.py
To list all possible targets (available commands):
$ tox -av
To build the Sphinx documentation:
$ tox -e docs
Gain additional Kudos by first adding a test that fails without your changes and passes
after they are applied.
New unit tests should be included in the tests
directory whenever possible.
Create a Pull Request¶
Make sure you have forked the original repository on GitHub and checked out the new fork to your computer as described above.
Create and activate your feature branch (
git checkout -b my-new-feature
).Commit your changes (git commit -am “Added some cool feature”).
Push to the branch (git push origin my-new-feature).
Create a new Pull Request on GitHub.
Please add a bullet point to
../../CHANGELOG.md
if the fix or feature is not trivial (small doc updates, typo fixes). Then commit:git commit -m '#42: Add useful new feature that does this.'
GitHub recognizes certain phrases that can be used to automatically update the issue tracker.
For example:
git commit -m 'Closes #42: Fix invalid markup in docstring of Foo.bar.'
would close issue #42.
Wait for a core developer to review your changes.
Attention
You are looking at outdated documentation for version 2.x. A newer version is available.
Release Info¶
# Changelog
## 2.4.2 / Unreleased
## 2.4.1 / 2018-06-16
- Fix some logging exceptions
- Fix exception in CLI config reader (Py2)
## 2.4.0 / 2018-05-30
- Improve configuration files: - YAML is now the preferred configuration file format. - Add support for JSON config files (JavaScript-style comments allowed) (#89) - Use wsgidav.yaml, wsgidav.json, or wsgidav.conf by default if they exist in the local folder
- Expand ‘~’ in –root and –config command line options
- #97: Fix assumption that QUERY_STRING is in environment (dir_browser)
- #99: Fix virtual_dav_provider for Py3: WSGI expects binary instead of str
- #100: Send ETags with PUT response
- #101: Fail cleanly if trying to PUT to unknown collection
- Refactor logging: - Re-define verbosity level range: 0..5 - Remove usage of print in favor of logging.getLogger().debug - Remove util.note(), .status(), … helpers
- Refactor code base: - Use .format() syntax instead of %s for string templating - Mandatory PEP 8 compliance (checked by flake8)
- Rework documentation on Read The Docs
- MSI setup uses Cheroot version 6.2+
## 2.3.0 / 2018-04-06
- #80: Drop support for Python 3.3 (end-of-life September 2017)
- #86: Give custom PropertyManager implementations access to the environ
- #87: Don’t assume sys.stdout.encoding is not None
- #90: Custom response headers
- #93: Add support for streaming large files on Mac
## 2.2.4 / 2017-08-11
- Fix #75: Return 401 when auth method is not supported
- Fix #77: removeProperty call to not lose dryRun, otherwise removeProperty is called twice for real
- Fix #79: Prevent error when missing environment variable
## 2.2.2 / 2017-06-23
- #69: Rectifying naming disparity for CherryPy server
- Fix #67: lock manager returns timeout negative seconds
- Fix #71: Attempts to unlock a nonexistent resource cause an internal server error
- Fix #73: Failed on processing non-iso-8859-1 characters on Python 3
- MSI setup uses Python 3.5
## 2.2.1 / 2017-02-25
- #65: Support for Cheroot server, which is the standalone WSGI server of CherryPy since version 9.0. –server=cheroot is the default now.
- New option –ssl-adapter, used by ‘cheroot’ server if SSL certificates are configured. Defaults to ‘builtin’.<br> Set to ‘pyopenssl’ to use an existing OpenSSL nstallation. (Note: Currently broken as of Cheroot 5.1, see cherrypy/cheroot#6)
- Deprecate cherrypy.wsgiserver.<br> –server=cherrypy was renamed to –cherrypy-wsgiserver
- #64: Fix LOCK without owner
- #65: Add lxml to MSI installer
- Release as Wheel
## 2.1.0 / 2016-11-13
- #42: Remove print usage in favor of logging (Sergi Almacellas Abellana)
- #43: PEP8 fixes (Sergi Almacellas Abellana, Tom Viner)
- #45 New method _DAVResource.finalizeHeaders(environ, responseHeaders) (Samuel Fekete)
- #55 Custom response handlers for PUT, GET etc.
- New helpers addons.stream_tools.FileLikeQueue and StreamingFile allow to pipe / proxy PUT requests to external consumers.
## 2.0.1 / 2016-10-07
- #46 Wrap xml libraries with the equivalent defusedxml packages (Tom Viner)
## 2.0.0 / 2016-10-02
- #4: Support Python 3
- Windows MSI Installer
- Drop support for Python 2.6
- cherrypy.wsgiserver is no longer included as source package. CherryPy is still the recommended standalone WSGI server, and deployed with the binary installation. It is also installed as dependency by setup.py test. However if a source installation is used, either install cherrypy using pip install cherrypy or choose another server using the –server option.
- Configuration: - New options server and server_args - Removed ext_servers option
- Standalone server: - New command line option –server (defaults to cherrypy) - New command line option –no-config - Removed command line option -d use -vv instead
- Use py.test & tox
## 1.3.0 / 2016-08-24
- #19: Add option mutable_live_props to support setting last modified file/directory timestamps (Jonas Bardino)
- #23: Fix Windows file manager and OSX Finder fails on file names with comma (Jonas Bardino)
- #27: Do not install tests (Erich Seifert)
- #28: New option trusted_auth_header allows reverse proxy authentication (Mageti)
- #30: API change to allow much easier per-user chrooting (Jonas Bardino)
- #32: Fix digest authentication rejected due to invalid header (Adrian Crețu)
## 1.2.0 / 2015-05-14
- #8: Unquote PATH_INFO is now optional ‘unquote_path_info’; defaults to false. (Brian Sipos)
- #9: Fixed status codes for apache mod_wsgi (Brian Sipos)
- #10: Hotfix for file copy on GVFS (Brian Sipos)
- #12: Configurable middleware stack (Pavel Shiryaev)
- #15: Fix Finder access (Jonas Bardino)
## 1.1.0 / 2014-01-01
- New dir_browser option ‘ms_sharepoint_plugin’ to start MS Office documents in edit-mode
- Moved project from Google Code to GitHub
- Moved documentation to ReadTheDocs
## 1.0.0 / 2013-12-27
- NOTE: no longer tested with Python 2.4.
- SSL sample with bogo-cert
- Renamed ‘msmount’ option to ‘ms_mount’.
- Files are always stored in binary mode.
- Port and hostname can now be specified in config file (before: command line only).
- New option for dir_browser: ‘msSharepointUrls’ will prepend ‘ms-word:ofe|u|’ to URL for MS Offce documents.
- New option ‘add_header_MS_Author_Via = True’ to support editing with Microsoft Office
- FilesystemProvider expands variables like ‘~’, ‘$Name’ and ‘%NAME%’ in folder paths (i.e. ‘~/foo’ -> ‘/Users/joe/foo’)
- Issue #55 Failure operating with litmus test suite, Mac OS X WebDAV Client, Windows 7 (thanks to Ben Allums)
- Fixed issue #48 Allow the dirbrowser to be configured from the config file (thanks to Herman Grecco)
- Fixed issue #43 Unicode error in Ubuntu
- Allow Ctrl-C / SIGINT to stop CherryPyWSGIServer
- Made mimetype guessing more robust
- Updated CherryPy standalone WSGI server to 3.2.4
- Support ‘setup.py test’ which uses nosetests and includes litmus
## 0.5.0 / 2011-01-16
- Bundled with CherryPy standalone WSGI server
- Added copyright notes for original PyFileServer
- Changed signature of DAVProvider (and derived classes): provider argument was removed
- New method DAVResource.getMemberList() replaces getMemberNames().
- New class DAVCollection allows for more efficient implementation of custom providers.
- Forcing ‘Connection: close’, when a required Content-Length is missing. So it’s possible now to return GET responses without knowing the size.
- New property manager based on CouchDB (addons.couch_property_manager)
- New property manager based on MongoDB (addons.mongo_property_manager)
- New sample DAV provider for MongoDBs (samples.mongo_dav_provider)
- Debug output goes to stdout (was stderr)
- Support davmount (rfc 4709).
- Added support for Microsoft FOLDER behavior.
- renamed displayType() -> getDirectoryInfo()
- Fixed RANGE response
## 0.4.0.b3
- Refactored LockManager. using separate LockStorage
- Bugfixes
## 0.4.0.b2 / 2010-02-15
- Bugfixes
## 0.4.0.b1
- Using HTTP/1.1 with keep-alive (St�phane KLEIN)
- Correctly return pre- and postconditions on lock conflicts.
- Added Sphinx docs
- Added Mercurial provider
- Changed configuration: no property manager used by default
## Until 0.4.0 alpha
See https://github.com/mar10/wsgidav/blob/master/doc/changelog04.md
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, Linux, 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 the litmus test suite.
- Open architecture allows to write custom providers (i.e. storage, locking, authentication, virtual file systems, …).
- WsgiDAV is a refactored version of PyFileServer written by Ho Chun Wei.
Quickstart¶
Releases are hosted on PyPI. Install WsgiDAV (and a server) like:
$ pip install cheroot wsgidav
To serve the /tmp
folder as WebDAV /
share, simply run:
$ wsgidav --host=0.0.0.0 --port=80 --root=/tmp
Note
MS Windows users that only need the command line interface may prefer the MSI installer.
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, …).
