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
|
# Copyright (c) 2009-2010, Cloud Matrix Pty. Ltd.
# All rights reserved; available under the terms of the MIT License.
"""
fs.contrib.davfs.xmlobj: dexml model definitions for WebDAV
This module defines the various XML element structures for WebDAV as a set
of dexml.Model subclasses.
"""
from urlparse import urlparse, urlunparse
from httplib import responses as STATUS_CODE_TEXT
STATUS_CODE_TEXT[207] = "Multi-Status"
import dexml
from dexml import fields
Error = dexml.Error
class _davbase(dexml.Model):
"""Base class for all davfs XML models."""
class meta:
namespace = "DAV:"
namespace_prefix = "D"
order_sensitive = False
class HrefField(fields.String):
"""Field representing a <href> tag."""
def __init__(self,*args,**kwds):
kwds["tagname"] = "href"
super(HrefField,self).__init__(*args,**kwds)
def parse_value(self,value):
url = urlparse(value.encode("UTF-8"))
return urlunparse((url.scheme,url.netloc,url.path,url.params,url.query,url.fragment))
def render_value(self,value):
url = urlparse(value.encode("UTF-8"))
return urlunparse((url.scheme,url.netloc,url.path,url.params,url.query,url.fragment))
class TimeoutField(fields.Field):
"""Field representing a WebDAV timeout value."""
def __init__(self,*args,**kwds):
if "tagname" not in kwds:
kwds["tagname"] = "timeout"
super(TimeoutField,self).__init__(*args,**kwds)
@classmethod
def parse_value(cls,value):
if value == "Infinite":
return None
if value.startswith("Second-"):
return int(value[len("Second-"):])
raise ValueError("invalid timeout specifier: %s" % (value,))
def render_value(self,value):
if value is None:
return "Infinite"
else:
return "Second-" + str(value)
class StatusField(fields.Value):
"""Field representing a WebDAV status-line value.
The value may be set as either a string or an integer, and is converted
into a StatusString instance.
"""
def __init__(self,*args,**kwds):
kwds["tagname"] = "status"
super(StatusField,self).__init__(*args,**kwds)
def __get__(self,instance,owner):
val = super(StatusField,self).__get__(instance,owner)
if val is not None:
val = StatusString(val,instance,self)
return val
def __set__(self,instance,value):
if isinstance(value,basestring):
# sanity check it
bits = value.split(" ")
if len(bits) < 3 or bits[0] != "HTTP/1.1":
raise ValueError("Not a valid status: '%s'" % (value,))
int(bits[1])
elif isinstance(value,int):
# convert it to a message
value = StatusString._value_for_code(value)
super(StatusField,self).__set__(instance,value)
class StatusString(str):
"""Special string representing a HTTP status line.
It's a string, but it exposes the integer attribute "code" giving just
the actual response code.
"""
def __new__(cls,val,inst,owner):
return str.__new__(cls,val)
def __init__(self,val,inst,owner):
self._owner = owner
self._inst = inst
@staticmethod
def _value_for_code(code):
msg = STATUS_CODE_TEXT.get(code,"UNKNOWN STATUS CODE")
return "HTTP/1.1 %d %s" % (code,msg)
def _get_code(self):
return int(self.split(" ")[1])
def _set_code(self,code):
newval = self._value_for_code(code)
self._owner.__set__(self._inst,newval)
code = property(_get_code,_set_code)
class multistatus(_davbase):
"""XML model for a multi-status response message."""
responses = fields.List("response",minlength=1)
description = fields.String(tagname="responsedescription",required=False)
class response(_davbase):
"""XML model for an individual response in a multi-status message."""
href = HrefField()
# TODO: ensure only one of hrefs/propstats
hrefs = fields.List(HrefField(),required=False)
status = StatusField(required=False)
propstats = fields.List("propstat",required=False)
description = fields.String(tagname="responsedescription",required=False)
class propstat(_davbase):
"""XML model for a propstat response message."""
props = fields.XmlNode(tagname="prop",encoding="UTF-8")
status = StatusField()
description = fields.String(tagname="responsedescription",required=False)
class propfind(_davbase):
"""XML model for a propfind request message."""
allprop = fields.Boolean(tagname="allprop",required=False)
propname = fields.Boolean(tagname="propname",required=False)
prop = fields.XmlNode(tagname="prop",required=False,encoding="UTF-8")
class propertyupdate(_davbase):
"""XML model for a propertyupdate request message."""
commands = fields.List(fields.Choice("remove","set"))
class remove(_davbase):
"""XML model for a propertyupdate remove command."""
props = fields.XmlNode(tagname="prop",encoding="UTF-8")
class set(_davbase):
"""XML model for a propertyupdate set command."""
props = fields.XmlNode(tagname="prop",encoding="UTF-8")
class lockdiscovery(_davbase):
"""XML model for a lockdiscovery request message."""
locks = fields.List("activelock")
class activelock(_davbase):
"""XML model for an activelock response message."""
lockscope = fields.Model("lockscope")
locktype = fields.Model("locktype")
depth = fields.String(tagname="depth")
owner = fields.XmlNode(tagname="owner",encoding="UTF-8",required=False)
timeout = TimeoutField(required=False)
locktoken = fields.Model("locktoken",required=False)
class lockscope(_davbase):
"""XML model for a lockscope response message."""
shared = fields.Boolean(tagname="shared",empty_only=True)
exclusive = fields.Boolean(tagname="exclusive",empty_only=True)
class locktoken(_davbase):
"""XML model for a locktoken response message."""
tokens = fields.List(HrefField())
class lockentry(_davbase):
"""XML model for a lockentry response message."""
lockscope = fields.Model("lockscope")
locktype = fields.Model("locktype")
class lockinfo(_davbase):
"""XML model for a lockinfo response message."""
lockscope = fields.Model("lockscope")
locktype = fields.Model("locktype")
owner = fields.XmlNode(tagname="owner",encoding="UTF-8")
class locktype(_davbase):
"""XML model for a locktype response message."""
type = fields.XmlNode(encoding="UTF-8")
|