Architecture#
This document gives a brief introduction to the WsgiDAV application package (targeted to developers).
WSGI Application Stack#
WsgiDAV is a WSGI application.
WSGI 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#
digraph inheritance87af19f810 { bgcolor=transparent; rankdir=LR; size="8.0, 12.0"; "abc.ABC" [fillcolor=white,fontname="Vera Sans, DejaVu Sans, Liberation Sans, Arial, Helvetica, sans",fontsize=10,height=0.25,shape=box,style="setlinewidth(0.5),filled",tooltip="Helper class that provides a standard way to create an ABC using"]; "dav_provider.DAVCollection" [URL="_autosummary/wsgidav.dav_provider.DAVCollection.html#wsgidav.dav_provider.DAVCollection",fillcolor=white,fontname="Vera Sans, DejaVu Sans, Liberation Sans, Arial, Helvetica, sans",fontsize=10,height=0.25,shape=box,style="setlinewidth(0.5),filled",target="_top",tooltip="A DAVCollection is a _DAVResource, that has members (like a 'folder' on"]; "dav_provider._DAVResource" -> "dav_provider.DAVCollection" [arrowsize=0.5,style="setlinewidth(0.5)"]; "dav_provider.DAVNonCollection" [URL="_autosummary/wsgidav.dav_provider.DAVNonCollection.html#wsgidav.dav_provider.DAVNonCollection",fillcolor=white,fontname="Vera Sans, DejaVu Sans, Liberation Sans, Arial, Helvetica, sans",fontsize=10,height=0.25,shape=box,style="setlinewidth(0.5),filled",target="_top",tooltip="A DAVNonCollection is a _DAVResource, that has content (like a 'file' on"]; "dav_provider._DAVResource" -> "dav_provider.DAVNonCollection" [arrowsize=0.5,style="setlinewidth(0.5)"]; "dav_provider.DAVProvider" [URL="_autosummary/wsgidav.dav_provider.DAVProvider.html#wsgidav.dav_provider.DAVProvider",fillcolor=white,fontname="Vera Sans, DejaVu Sans, Liberation Sans, Arial, Helvetica, sans",fontsize=10,height=0.25,shape=box,style="setlinewidth(0.5),filled",target="_top",tooltip="Abstract base class for DAV resource providers."]; "abc.ABC" -> "dav_provider.DAVProvider" [arrowsize=0.5,style="setlinewidth(0.5)"]; "dav_provider._DAVResource" [fillcolor=white,fontname="Vera Sans, DejaVu Sans, Liberation Sans, Arial, Helvetica, sans",fontsize=10,height=0.25,shape=box,style="setlinewidth(0.5),filled",tooltip="Represents a single existing DAV resource instance."]; "abc.ABC" -> "dav_provider._DAVResource" [arrowsize=0.5,style="setlinewidth(0.5)"]; "fs_dav_provider.FileResource" [URL="_autosummary/wsgidav.fs_dav_provider.FileResource.html#wsgidav.fs_dav_provider.FileResource",fillcolor=white,fontname="Vera Sans, DejaVu Sans, Liberation Sans, Arial, Helvetica, sans",fontsize=10,height=0.25,shape=box,style="setlinewidth(0.5),filled",target="_top",tooltip="Represents a single existing DAV resource instance."]; "dav_provider.DAVNonCollection" -> "fs_dav_provider.FileResource" [arrowsize=0.5,style="setlinewidth(0.5)"]; "fs_dav_provider.FilesystemProvider" [URL="_autosummary/wsgidav.fs_dav_provider.FilesystemProvider.html#wsgidav.fs_dav_provider.FilesystemProvider",fillcolor=white,fontname="Vera Sans, DejaVu Sans, Liberation Sans, Arial, Helvetica, sans",fontsize=10,height=0.25,shape=box,style="setlinewidth(0.5),filled",target="_top",tooltip="Default implementation of a filessystem DAVProvider."]; "dav_provider.DAVProvider" -> "fs_dav_provider.FilesystemProvider" [arrowsize=0.5,style="setlinewidth(0.5)"]; "fs_dav_provider.FolderResource" [URL="_autosummary/wsgidav.fs_dav_provider.FolderResource.html#wsgidav.fs_dav_provider.FolderResource",fillcolor=white,fontname="Vera Sans, DejaVu Sans, Liberation Sans, Arial, Helvetica, sans",fontsize=10,height=0.25,shape=box,style="setlinewidth(0.5),filled",target="_top",tooltip="Represents a single existing file system folder DAV resource."]; "dav_provider.DAVCollection" -> "fs_dav_provider.FolderResource" [arrowsize=0.5,style="setlinewidth(0.5)"]; }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#
digraph inheritance38c29c3354 { bgcolor=transparent; rankdir=LR; size="8.0, 12.0"; "property_manager.PropertyManager" [URL="_autosummary/wsgidav.prop_man.property_manager.PropertyManager.html#wsgidav.prop_man.property_manager.PropertyManager",fillcolor=white,fontname="Vera Sans, DejaVu Sans, Liberation Sans, Arial, Helvetica, sans",fontsize=10,height=0.25,shape=box,style="setlinewidth(0.5),filled",target="_top",tooltip="An in-memory property manager implementation using a dictionary."]; "property_manager.ShelvePropertyManager" [URL="_autosummary/wsgidav.prop_man.property_manager.ShelvePropertyManager.html#wsgidav.prop_man.property_manager.ShelvePropertyManager",fillcolor=white,fontname="Vera Sans, DejaVu Sans, Liberation Sans, Arial, Helvetica, sans",fontsize=10,height=0.25,shape=box,style="setlinewidth(0.5),filled",target="_top",tooltip="A low performance property manager implementation using shelve"]; "property_manager.PropertyManager" -> "property_manager.ShelvePropertyManager" [arrowsize=0.5,style="setlinewidth(0.5)"]; }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:
prop_man.property_manager.PropertyManager
prop_man.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#
digraph inheritance863a6677c5 { bgcolor=transparent; rankdir=LR; size="8.0, 12.0"; "lock_manager.LockManager" [URL="_autosummary/wsgidav.lock_man.lock_manager.LockManager.html#wsgidav.lock_man.lock_manager.LockManager",fillcolor=white,fontname="Vera Sans, DejaVu Sans, Liberation Sans, Arial, Helvetica, sans",fontsize=10,height=0.25,shape=box,style="setlinewidth(0.5),filled",target="_top",tooltip="Implements locking functionality using a custom storage layer."]; "lock_storage.LockStorageDict" [URL="_autosummary/wsgidav.lock_man.lock_storage.LockStorageDict.html#wsgidav.lock_man.lock_storage.LockStorageDict",fillcolor=white,fontname="Vera Sans, DejaVu Sans, Liberation Sans, Arial, Helvetica, sans",fontsize=10,height=0.25,shape=box,style="setlinewidth(0.5),filled",target="_top",tooltip="An in-memory lock manager storage implementation using a dictionary."]; "lock_storage.LockStorageShelve" [URL="_autosummary/wsgidav.lock_man.lock_storage.LockStorageShelve.html#wsgidav.lock_man.lock_storage.LockStorageShelve",fillcolor=white,fontname="Vera Sans, DejaVu Sans, Liberation Sans, Arial, Helvetica, sans",fontsize=10,height=0.25,shape=box,style="setlinewidth(0.5),filled",target="_top",tooltip="A low performance lock manager implementation using shelve."]; "lock_storage.LockStorageDict" -> "lock_storage.LockStorageShelve" [arrowsize=0.5,style="setlinewidth(0.5)"]; }DAV providers have a LockManager
to support
exclusive and shared write locking.
The lock manager uses a lock storage implementation for persistence.
WsgiDAV comes with two default implementations, one based on a in-memory dictionary, and a persistent one based on shelve:
lock_storage.LockStorageDict
lock_storage.LockStorageShelve
LockStorageDict
is used by default, but
LockStorageShelve
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#
digraph inheritance36a820faa2 { bgcolor=transparent; rankdir=LR; size="8.0, 12.0"; "abc.ABC" [fillcolor=white,fontname="Vera Sans, DejaVu Sans, Liberation Sans, Arial, Helvetica, sans",fontsize=10,height=0.25,shape=box,style="setlinewidth(0.5),filled",tooltip="Helper class that provides a standard way to create an ABC using"]; "base_dc.BaseDomainController" [fillcolor=white,fontname="Vera Sans, DejaVu Sans, Liberation Sans, Arial, Helvetica, sans",fontsize=10,height=0.25,shape=box,style="setlinewidth(0.5),filled"]; "abc.ABC" -> "base_dc.BaseDomainController" [arrowsize=0.5,style="setlinewidth(0.5)"]; "base_mw.BaseMiddleware" [URL="_autosummary/wsgidav.mw.base_mw.BaseMiddleware.html#wsgidav.mw.base_mw.BaseMiddleware",fillcolor=white,fontname="Vera Sans, DejaVu Sans, Liberation Sans, Arial, Helvetica, sans",fontsize=10,height=0.25,shape=box,style="setlinewidth(0.5),filled",target="_top",tooltip="Abstract base middleware class (optional)."]; "abc.ABC" -> "base_mw.BaseMiddleware" [arrowsize=0.5,style="setlinewidth(0.5)"]; "http_authenticator.HTTPAuthenticator" [URL="_autosummary/wsgidav.http_authenticator.HTTPAuthenticator.html#wsgidav.http_authenticator.HTTPAuthenticator",fillcolor=white,fontname="Vera Sans, DejaVu Sans, Liberation Sans, Arial, Helvetica, sans",fontsize=10,height=0.25,shape=box,style="setlinewidth(0.5),filled",target="_top",tooltip="WSGI Middleware for basic and digest authentication."]; "base_mw.BaseMiddleware" -> "http_authenticator.HTTPAuthenticator" [arrowsize=0.5,style="setlinewidth(0.5)"]; "nt_dc.NTDomainController" [URL="_autosummary/wsgidav.dc.nt_dc.NTDomainController.html#wsgidav.dc.nt_dc.NTDomainController",fillcolor=white,fontname="Vera Sans, DejaVu Sans, Liberation Sans, Arial, Helvetica, sans",fontsize=10,height=0.25,shape=box,style="setlinewidth(0.5),filled",target="_top"]; "base_dc.BaseDomainController" -> "nt_dc.NTDomainController" [arrowsize=0.5,style="setlinewidth(0.5)"]; "pam_dc.PAMDomainController" [URL="_autosummary/wsgidav.dc.pam_dc.PAMDomainController.html#wsgidav.dc.pam_dc.PAMDomainController",fillcolor=white,fontname="Vera Sans, DejaVu Sans, Liberation Sans, Arial, Helvetica, sans",fontsize=10,height=0.25,shape=box,style="setlinewidth(0.5),filled",target="_top"]; "base_dc.BaseDomainController" -> "pam_dc.PAMDomainController" [arrowsize=0.5,style="setlinewidth(0.5)"]; "simple_dc.SimpleDomainController" [URL="_autosummary/wsgidav.dc.simple_dc.SimpleDomainController.html#wsgidav.dc.simple_dc.SimpleDomainController",fillcolor=white,fontname="Vera Sans, DejaVu Sans, Liberation Sans, Arial, Helvetica, sans",fontsize=10,height=0.25,shape=box,style="setlinewidth(0.5),filled",target="_top"]; "base_dc.BaseDomainController" -> "simple_dc.SimpleDomainController" [arrowsize=0.5,style="setlinewidth(0.5)"]; }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.dc.nt_dc
is an example for such an extension.
SimpleDomainController
Default implementation of a domain controller as used by
HTTPAuthenticator
.
Applications#
digraph inheritance72a5050eb2 { bgcolor=transparent; rankdir=LR; size="8.0, 12.0"; "abc.ABC" [fillcolor=white,fontname="Vera Sans, DejaVu Sans, Liberation Sans, Arial, Helvetica, sans",fontsize=10,height=0.25,shape=box,style="setlinewidth(0.5),filled",tooltip="Helper class that provides a standard way to create an ABC using"]; "base_mw.BaseMiddleware" [URL="_autosummary/wsgidav.mw.base_mw.BaseMiddleware.html#wsgidav.mw.base_mw.BaseMiddleware",fillcolor=white,fontname="Vera Sans, DejaVu Sans, Liberation Sans, Arial, Helvetica, sans",fontsize=10,height=0.25,shape=box,style="setlinewidth(0.5),filled",target="_top",tooltip="Abstract base middleware class (optional)."]; "abc.ABC" -> "base_mw.BaseMiddleware" [arrowsize=0.5,style="setlinewidth(0.5)"]; "cors.Cors" [URL="_autosummary/wsgidav.mw.cors.Cors.html#wsgidav.mw.cors.Cors",fillcolor=white,fontname="Vera Sans, DejaVu Sans, Liberation Sans, Arial, Helvetica, sans",fontsize=10,height=0.25,shape=box,style="setlinewidth(0.5),filled",target="_top"]; "base_mw.BaseMiddleware" -> "cors.Cors" [arrowsize=0.5,style="setlinewidth(0.5)"]; "dav_error.DAVError" [URL="_autosummary/wsgidav.dav_error.DAVError.html#wsgidav.dav_error.DAVError",fillcolor=white,fontname="Vera Sans, DejaVu Sans, Liberation Sans, Arial, Helvetica, sans",fontsize=10,height=0.25,shape=box,style="setlinewidth(0.5),filled",target="_top",tooltip="General error class that is used to signal HTTP and WEBDAV errors."]; "dav_error.DAVErrorCondition" [URL="_autosummary/wsgidav.dav_error.DAVErrorCondition.html#wsgidav.dav_error.DAVErrorCondition",fillcolor=white,fontname="Vera Sans, DejaVu Sans, Liberation Sans, Arial, Helvetica, sans",fontsize=10,height=0.25,shape=box,style="setlinewidth(0.5),filled",target="_top",tooltip="May be embedded in :class:`DAVError` instances to store additional data."]; "debug_filter.WsgiDavDebugFilter" [URL="_autosummary/wsgidav.mw.debug_filter.WsgiDavDebugFilter.html#wsgidav.mw.debug_filter.WsgiDavDebugFilter",fillcolor=white,fontname="Vera Sans, DejaVu Sans, Liberation Sans, Arial, Helvetica, sans",fontsize=10,height=0.25,shape=box,style="setlinewidth(0.5),filled",target="_top"]; "base_mw.BaseMiddleware" -> "debug_filter.WsgiDavDebugFilter" [arrowsize=0.5,style="setlinewidth(0.5)"]; "error_printer.ErrorPrinter" [URL="_autosummary/wsgidav.error_printer.ErrorPrinter.html#wsgidav.error_printer.ErrorPrinter",fillcolor=white,fontname="Vera Sans, DejaVu Sans, Liberation Sans, Arial, Helvetica, sans",fontsize=10,height=0.25,shape=box,style="setlinewidth(0.5),filled",target="_top"]; "base_mw.BaseMiddleware" -> "error_printer.ErrorPrinter" [arrowsize=0.5,style="setlinewidth(0.5)"]; "http_authenticator.HTTPAuthenticator" [URL="_autosummary/wsgidav.http_authenticator.HTTPAuthenticator.html#wsgidav.http_authenticator.HTTPAuthenticator",fillcolor=white,fontname="Vera Sans, DejaVu Sans, Liberation Sans, Arial, Helvetica, sans",fontsize=10,height=0.25,shape=box,style="setlinewidth(0.5),filled",target="_top",tooltip="WSGI Middleware for basic and digest authentication."]; "base_mw.BaseMiddleware" -> "http_authenticator.HTTPAuthenticator" [arrowsize=0.5,style="setlinewidth(0.5)"]; "request_resolver.RequestResolver" [URL="_autosummary/wsgidav.request_resolver.RequestResolver.html#wsgidav.request_resolver.RequestResolver",fillcolor=white,fontname="Vera Sans, DejaVu Sans, Liberation Sans, Arial, Helvetica, sans",fontsize=10,height=0.25,shape=box,style="setlinewidth(0.5),filled",target="_top"]; "base_mw.BaseMiddleware" -> "request_resolver.RequestResolver" [arrowsize=0.5,style="setlinewidth(0.5)"]; "request_server.RequestServer" [URL="_autosummary/wsgidav.request_server.RequestServer.html#wsgidav.request_server.RequestServer",fillcolor=white,fontname="Vera Sans, DejaVu Sans, Liberation Sans, Arial, Helvetica, sans",fontsize=10,height=0.25,shape=box,style="setlinewidth(0.5),filled",target="_top"]; "rw_lock.ReadWriteLock" [URL="_autosummary/wsgidav.rw_lock.ReadWriteLock.html#wsgidav.rw_lock.ReadWriteLock",fillcolor=white,fontname="Vera Sans, DejaVu Sans, Liberation Sans, Arial, Helvetica, sans",fontsize=10,height=0.25,shape=box,style="setlinewidth(0.5),filled",target="_top",tooltip="Read-Write lock class. A read-write lock differs from a standard"]; "wsgidav_app.WsgiDAVApp" [URL="_autosummary/wsgidav.wsgidav_app.WsgiDAVApp.html#wsgidav.wsgidav_app.WsgiDAVApp",fillcolor=white,fontname="Vera Sans, DejaVu Sans, Liberation Sans, Arial, Helvetica, sans",fontsize=10,height=0.25,shape=box,style="setlinewidth(0.5),filled",target="_top"]; }WsgiDavApp#
Cors#
Middleware wsgidav.mw.cors.Cors
.
Respond to CORS preflight OPTIONS request and inject CORS headers.
- On init:
Store CORS preferences and prepare header lists.
- For every request:
Add CORS headers to responses.
ErrorPrinter#
Middleware wsgidav.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 wsgidav.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 wsgidav.dir_browser._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 wsgidav.request_resolver.RequestResolver
.
Must be configured as last in middleware_stack config option.
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.
WsgiDavDebugFilter#
RequestServer#
Application wsgidav.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.