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 { rankdir=LR; size="8.0, 12.0"; "dav_provider.DAVCollection" [URL="_autosummary/wsgidav.dav_provider.DAVCollection.html#wsgidav.dav_provider.DAVCollection",color="#465158",fontcolor=white,fontname="Vera Sans, DejaVu Sans, Liberation Sans, Arial, Helvetica, sans",fontsize=13,height=0.25,shape=box,style="rounded,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",color="#465158",fontcolor=white,fontname="Vera Sans, DejaVu Sans, Liberation Sans, Arial, Helvetica, sans",fontsize=13,height=0.25,shape=box,style="rounded,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",color="#465158",fontcolor=white,fontname="Vera Sans, DejaVu Sans, Liberation Sans, Arial, Helvetica, sans",fontsize=13,height=0.25,shape=box,style="rounded,filled",target="_top",tooltip="Abstract base class for DAV resource providers."]; "dav_provider._DAVResource" [color="#465158",fontcolor=white,fontname="Vera Sans, DejaVu Sans, Liberation Sans, Arial, Helvetica, sans",fontsize=13,height=0.25,shape=box,style="rounded,filled",tooltip="Represents a single existing DAV resource instance."]; "fs_dav_provider.FileResource" [URL="_autosummary/wsgidav.fs_dav_provider.FileResource.html#wsgidav.fs_dav_provider.FileResource",color="#465158",fontcolor=white,fontname="Vera Sans, DejaVu Sans, Liberation Sans, Arial, Helvetica, sans",fontsize=13,height=0.25,shape=box,style="rounded,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",color="#465158",fontcolor=white,fontname="Vera Sans, DejaVu Sans, Liberation Sans, Arial, Helvetica, sans",fontsize=13,height=0.25,shape=box,style="rounded,filled",target="_top"]; "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",color="#465158",fontcolor=white,fontname="Vera Sans, DejaVu Sans, Liberation Sans, Arial, Helvetica, sans",fontsize=13,height=0.25,shape=box,style="rounded,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 { 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",color="#465158",fontcolor=white,fontname="Vera Sans, DejaVu Sans, Liberation Sans, Arial, Helvetica, sans",fontsize=13,height=0.25,shape=box,style="rounded,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",color="#465158",fontcolor=white,fontname="Vera Sans, DejaVu Sans, Liberation Sans, Arial, Helvetica, sans",fontsize=13,height=0.25,shape=box,style="rounded,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 inheritance639b71bc3e { rankdir=LR; size="8.0, 12.0"; "lock_manager.LockManager" [URL="_autosummary/wsgidav.lock_manager.LockManager.html#wsgidav.lock_manager.LockManager",color="#465158",fontcolor=white,fontname="Vera Sans, DejaVu Sans, Liberation Sans, Arial, Helvetica, sans",fontsize=13,height=0.25,shape=box,style="rounded,filled",target="_top",tooltip="Implements locking functionality using a custom storage layer."]; "lock_storage.LockStorageDict" [URL="_autosummary/wsgidav.lock_storage.LockStorageDict.html#wsgidav.lock_storage.LockStorageDict",color="#465158",fontcolor=white,fontname="Vera Sans, DejaVu Sans, Liberation Sans, Arial, Helvetica, sans",fontsize=13,height=0.25,shape=box,style="rounded,filled",target="_top",tooltip="An in-memory lock manager storage implementation using a dictionary."]; "lock_storage.LockStorageShelve" [URL="_autosummary/wsgidav.lock_storage.LockStorageShelve.html#wsgidav.lock_storage.LockStorageShelve",color="#465158",fontcolor=white,fontname="Vera Sans, DejaVu Sans, Liberation Sans, Arial, Helvetica, sans",fontsize=13,height=0.25,shape=box,style="rounded,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 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.dc.nt_dc is an example for such an extension.
SimpleDomainController
- Default implementation of a domain controller as used by
HTTPAuthenticator
.
Applications¶
digraph inheritance0db89fc85f { rankdir=LR; size="8.0, 12.0"; "dav_error.DAVError" [URL="_autosummary/wsgidav.dav_error.DAVError.html#wsgidav.dav_error.DAVError",color="#465158",fontcolor=white,fontname="Vera Sans, DejaVu Sans, Liberation Sans, Arial, Helvetica, sans",fontsize=13,height=0.25,shape=box,style="rounded,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",color="#465158",fontcolor=white,fontname="Vera Sans, DejaVu Sans, Liberation Sans, Arial, Helvetica, sans",fontsize=13,height=0.25,shape=box,style="rounded,filled",target="_top",tooltip="May be embedded in :class:`DAVError` instances to store additional data."]; "debug_filter.WsgiDavDebugFilter" [URL="_autosummary/wsgidav.debug_filter.WsgiDavDebugFilter.html#wsgidav.debug_filter.WsgiDavDebugFilter",color="#465158",fontcolor=white,fontname="Vera Sans, DejaVu Sans, Liberation Sans, Arial, Helvetica, sans",fontsize=13,height=0.25,shape=box,style="rounded,filled",target="_top"]; "middleware.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",color="#465158",fontcolor=white,fontname="Vera Sans, DejaVu Sans, Liberation Sans, Arial, Helvetica, sans",fontsize=13,height=0.25,shape=box,style="rounded,filled",target="_top"]; "middleware.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",color="#465158",fontcolor=white,fontname="Vera Sans, DejaVu Sans, Liberation Sans, Arial, Helvetica, sans",fontsize=13,height=0.25,shape=box,style="rounded,filled",target="_top",tooltip="WSGI Middleware for basic and digest authentication."]; "middleware.BaseMiddleware" -> "http_authenticator.HTTPAuthenticator" [arrowsize=0.5,style="setlinewidth(0.5)"]; "middleware.BaseMiddleware" [URL="_autosummary/wsgidav.middleware.BaseMiddleware.html#wsgidav.middleware.BaseMiddleware",color="#465158",fontcolor=white,fontname="Vera Sans, DejaVu Sans, Liberation Sans, Arial, Helvetica, sans",fontsize=13,height=0.25,shape=box,style="rounded,filled",target="_top",tooltip="Abstract base middleware class (optional)."]; "request_resolver.RequestResolver" [URL="_autosummary/wsgidav.request_resolver.RequestResolver.html#wsgidav.request_resolver.RequestResolver",color="#465158",fontcolor=white,fontname="Vera Sans, DejaVu Sans, Liberation Sans, Arial, Helvetica, sans",fontsize=13,height=0.25,shape=box,style="rounded,filled",target="_top"]; "middleware.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",color="#465158",fontcolor=white,fontname="Vera Sans, DejaVu Sans, Liberation Sans, Arial, Helvetica, sans",fontsize=13,height=0.25,shape=box,style="rounded,filled",target="_top"]; "rw_lock.ReadWriteLock" [URL="_autosummary/wsgidav.rw_lock.ReadWriteLock.html#wsgidav.rw_lock.ReadWriteLock",color="#465158",fontcolor=white,fontname="Vera Sans, DejaVu Sans, Liberation Sans, Arial, Helvetica, sans",fontsize=13,height=0.25,shape=box,style="rounded,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",color="#465158",fontcolor=white,fontname="Vera Sans, DejaVu Sans, Liberation Sans, Arial, Helvetica, sans",fontsize=13,height=0.25,shape=box,style="rounded,filled",target="_top"]; }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
.
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.
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.