[Clients] WebDAV Implementation Notes
Most of the time different clients can be automatically recognized by some type of User-Agent string in their requests.
When a request is received the user's agent (application) is matched to a user agent description (defined in coils.core.useragents) using the lookup_user_agent method.
from coils.core.useragents import lookup_user_agent
spec = lookup_user_agent('CardDAV-Sync (Android) (like iOS/5.0.1 (9A405) dataaccessd/1.0) gzip')
Each specification is a dictionary that describes the capacities, and most importantly the known bugs, of a specific client. Specifications all start with the default client description and then that description is then patched with the description of the specific client - this eliminates a lot of duplicate and boiler-plate content from the user agent descriptions.
The default description
'148c9d0d669648ed8b8ed0292df478fd':
{ 'name': 'default',
'patterns': [],
'webdav': { 'filenameAsDisplayName': False, # Use the filename as the display name, for clients that confuse the two
'showProjectContactsFolder': True, # Enable/Disable showing the Contacts folder in a Project folder
'showProjectEnterprisesFolder': True, # Enable/Disable showing the Enterprise folder in a Project folder
'showProjectTasksFolder': True, # Enable/Disable showing the Tasks folder in a Project folder
'showProjectProjectsFolder': True, # Enable/Disable showing the Projects (sub-projects) folder in a Project folder
'showProjectDocumentsFolder': True, # Enable/Disable showing the Documents folder in a Project folder
'showProjectNotesFolder': True, # Enable/Disable showing the Notes folder in a Project folder
'showProjectVersionsFolder': False, # Enable/Disable showing the Versions folder in a Project folder
'folderContentType': 'unix/httpd-directory', # Mime-type for a collection/folder
'escapeGETs': False,
'supports301': True, # Does the client respond correctly to 301 responses
'supportsLocation': True, # Does the client respond correct to Location: headers
'supportsMEMOs': False, # Does the client properly handle Memo (VJOURNAL) objects
'absoluteHrefs': False, # Does the client require HREF values to be absolute
'portInAbsoluteHref': False, # Does the client recognize port numbers in absolute HREFs
'hideLockRoot': False,
'principalURL': None,
'defaultPropeties':
[ ( u'name', u'DAV:', u'webdav', 'D:name' ),
( u'href', u'DAV:', u'webdav', 'D:href' ),
( u'getcontenttype', u'DAV:', u'webdav', 'D:getcontenttype' ),
( u'contentclass', u'DAV:', u'webdav', 'D:contentclass' ),
( u'getlastmodified', u'DAV:', u'webdav', 'D:getlastmodified' ),
( u'getcontentlength', u'DAV:', u'webdav', 'D:getcontentlength' ),
( u'iscollection', u'DAV:', u'webdav', 'D:iscollection' ),
( u'displayname', u'DAV:', u'webdav', 'D:displayname' ),
( u'getctag', u'urn:ietf:params:xml:ns:caldav', u'caldav', 'C:getctag' ),
( u'resourcetype', u'DAV:', u'webdav', 'D:resourcetype' ) ],
'defaultNamespaces': { 'C': 'urn:ietf:params:xml:ns:caldav',
'D': 'DAV:',
'G': 'http://groupdav.org/' } },
'jsonrpc': { },
'xmlrpc': { 'allowNone': False, },
'vcard': { 'setVoiceAttrInTel': True,
'setCoilsTypeInTel': True,
'telTypeMap': { '10_fax': { 'types': ['fax','work'], 'voice': False },
'01_tel': { 'types': ['work', 'pref' ], 'voice': True },
'03_tel_funk': { 'types': ['cell'], 'voice': True },
'05_tel_private': { 'types': ['home'], 'voice': True, },
'30_pager': { 'types': [ 'pager' ], 'voice': False } },
'setCoilsTypeInAdr': True, # Encode the OGo address type in VCARD ADR properties
'adrTypeMap': { 'private': { 'types': [ 'home' ] },
'mailing': { 'types': [ 'work', 'pref' ] },
'bill': { 'types': [ 'work', 'pref' ] },
'shipto': { 'types': [ 'work' ] } },
'includeObjectPropertes': False, # Encode the OGo object properties in VCARDs
'includeCoilsXAttributes': False, # Encode the OGo company values in VCARDs
'includeCompanyValues': False, # Encode the OGo company values in VCARDs
},
'icalendar': { 'includeAttachments': False, # includeAttachments: False, inline, link
},
'omphalos': { 'associativeLists': False, # Use associate lists in Omphalos responses
}
},
The current user agent description is always available via the [Context] object's user_agent_description property.
self.context.user_agent_description['webdav']['escapeGETs']