def test_encodeXMLName(self): # No namespace self.assertEquals(encodeXMLName(None, "name"), "name") self.assertEquals(encodeXMLName("" , "name"), "name") # Normal case self.assertEquals(encodeXMLName("namespace", "name"), "{namespace}name")
def test_encodeXMLName(self): # No namespace self.assertEquals(encodeXMLName(None, "name"), "name") self.assertEquals(encodeXMLName("", "name"), "name") # Normal case self.assertEquals(encodeXMLName("namespace", "name"), "{namespace}name")
def gotProperties(qnames): accessDeniedValue = object() def gotError(f, name): f.trap(HTTPError) code = f.value.response.code if code == responsecode.NOT_FOUND: log.error("Property %s was returned by listProperties() " "but does not exist for resource %s." % (name, self.resource)) return (name, None) if code == responsecode.UNAUTHORIZED: return (name, accessDeniedValue) return f whenAllProperties = gatherResults([ maybeDeferred(self.resource.readProperty, qn, request) .addCallback(lambda p, iqn=qn: (p.sname(), p.toxml()) if p is not None else (encodeXMLName(*iqn), None)) .addErrback(gotError, encodeXMLName(*qn)) for qn in sorted(qnames) ]) @whenAllProperties.addCallback def gotValues(items): for even, [name, value] in zip(cycle(["odd", "even"]), items): if value is None: value = tags.i("(no value)") elif value is accessDeniedValue: value = tags.i("(access forbidden)") yield tag.clone().fillSlots( even=even, name=name, value=value, ) return whenAllProperties
def get(self, qname, uid=None): """ Retrieve the value of a property stored as an extended attribute on the wrapped path. @param qname: The property to retrieve as a two-tuple of namespace URI and local name. @param uid: The per-user identifier for per user properties. @raise HTTPError: If there is no value associated with the given property. @return: A L{WebDAVDocument} representing the value associated with the given property. """ try: data = self.attrs.get(self._encode(qname, uid)) except KeyError: raise HTTPError(StatusResponse( responsecode.NOT_FOUND, "No such property: %s" % (encodeXMLName(*qname),) )) except IOError, e: if e.errno in _ATTR_MISSING or e.errno == errno.ENOENT: raise HTTPError(StatusResponse( responsecode.NOT_FOUND, "No such property: %s" % (encodeXMLName(*qname),) )) else: raise HTTPError(StatusResponse( statusForFailure(Failure()), "Unable to read property: %s" % (encodeXMLName(*qname),) ))
def __init__(self, qname): HTTPError.__init__(self, StatusResponse( responsecode.NOT_FOUND, "No such property: %s" % encodeXMLName(*qname) ) )
def __init__(self, qname): HTTPError.__init__( self, StatusResponse( responsecode.NOT_FOUND, "No such property: %s" % encodeXMLName(*qname) ) )
def setProperty(self, child, property, uid, delete=False): propertyCache, key, childCache, token = self.childCache(child) if delete: qname = property qnameuid = qname + (uid, ) if qnameuid in childCache: del childCache[qnameuid] else: qname = property.qname() qnameuid = qname + (uid, ) childCache[qnameuid] = property client = self.memcacheClient() if client is not None: retries = 10 while retries: try: if client.set(key, childCache, time=self.cacheTimeout, token=token): # Success break except TokenMismatchError: # The value in memcache has changed since we last # fetched it self.log.debug( "memcacheprops setProperty TokenMismatchError; retrying..." ) finally: # Re-fetch the properties for this child loaded = self._loadCache( childNames=(child.fp.basename(), )) propertyCache.update(loaded.iteritems()) retries -= 1 propertyCache, key, childCache, token = self.childCache(child) if delete: if qnameuid in childCache: del childCache[qnameuid] else: childCache[qnameuid] = property else: self.log.error( "memcacheprops setProperty had too many failures") delattr(self, "_propertyCache") raise MemcacheError( "Unable to %s property %s%s on %s" % ("delete" if delete else "set", uid if uid else "", encodeXMLName(*qname), child))
def setProperty(self, child, property, uid, delete=False): propertyCache, key, childCache, token = self.childCache(child) if delete: qname = property qnameuid = qname + (uid,) if qnameuid in childCache: del childCache[qnameuid] else: qname = property.qname() qnameuid = qname + (uid,) childCache[qnameuid] = property client = self.memcacheClient() if client is not None: retries = 10 while retries: try: if client.set( key, childCache, time=self.cacheTimeout, token=token ): # Success break except TokenMismatchError: # The value in memcache has changed since we last # fetched it self.log.debug("memcacheprops setProperty TokenMismatchError; retrying...") finally: # Re-fetch the properties for this child loaded = self._loadCache(childNames=(child.fp.basename(),)) propertyCache.update(loaded.iteritems()) retries -= 1 propertyCache, key, childCache, token = self.childCache(child) if delete: if qnameuid in childCache: del childCache[qnameuid] else: childCache[qnameuid] = property else: self.log.error("memcacheprops setProperty had too many failures") delattr(self, "_propertyCache") raise MemcacheError("Unable to %s property %s%s on %s" % ( "delete" if delete else "set", uid if uid else "", encodeXMLName(*qname), child ))
def get(self, qname): try: property = self._dict[qname] except KeyError: raise HTTPError( StatusResponse( responsecode.NOT_FOUND, "No such property: %s" % (encodeXMLName(*qname), ))) doc = element.WebDAVDocument.fromString(property) return doc.root_element
def get(self, qname): try: property = self._dict[qname] except KeyError: raise HTTPError(StatusResponse( responsecode.NOT_FOUND, "No such property: %s" % (encodeXMLName(*qname),) )) doc = element.WebDAVDocument.fromString(property) return doc.root_element
def gotProperties(qnames): accessDeniedValue = object() def gotError(f, name): f.trap(HTTPError) code = f.value.response.code if code == responsecode.NOT_FOUND: log.error( "Property {p} was returned by listProperties() " "but does not exist for resource {r}.", p=name, r=self.resource) return (name, None) if code == responsecode.UNAUTHORIZED: return (name, accessDeniedValue) return f whenAllProperties = gatherResults([ maybeDeferred( self.resource.readProperty, qn, request).addCallback( lambda p, iqn=qn: (p.sname(), p.toxml()) if p is not None else (encodeXMLName(*iqn), None)).addErrback( gotError, encodeXMLName(*qn)) for qn in sorted(qnames) ]) @whenAllProperties.addCallback def gotValues(items): for even, [name, value] in zip(cycle(["odd", "even"]), items): if value is None: value = tags.i("(no value)") elif value is accessDeniedValue: value = tags.i("(access forbidden)") yield tag.clone().fillSlots( even=even, name=name, value=value, ) return whenAllProperties
def _encodeKey(self, effective, compressNamespace=True): qname, uid = effective if compressNamespace: namespace = self._namespaceCompress.get(qname.namespace, qname.namespace) else: namespace = qname.namespace result = urllib.quote(encodeXMLName(namespace, qname.name), safe="{}:") if uid and uid != self._defaultUser: result = uid + result r = self.deadPropertyXattrPrefix + result return r
def get(self, qname, uid=None): """ Retrieve the value of a property stored as an extended attribute on the wrapped path. @param qname: The property to retrieve as a two-tuple of namespace URI and local name. @param uid: The per-user identifier for per user properties. @raise HTTPError: If there is no value associated with the given property. @return: A L{WebDAVDocument} representing the value associated with the given property. """ try: data = self.attrs.get(self._encode(qname, uid)) except KeyError: raise HTTPError( StatusResponse( responsecode.NOT_FOUND, "No such property: %s" % (encodeXMLName(*qname), ))) except IOError, e: if e.errno in _ATTR_MISSING or e.errno == errno.ENOENT: raise HTTPError( StatusResponse( responsecode.NOT_FOUND, "No such property: %s" % (encodeXMLName(*qname), ))) else: raise HTTPError( StatusResponse( statusForFailure(Failure()), "Unable to read property: %s" % (encodeXMLName(*qname), )))
def get(self, qname, uid=None, cache=True): if cache: propertyCache = self.propertyCache() qnameuid = qname + (uid, ) if qnameuid in propertyCache: return propertyCache[qnameuid] else: raise HTTPError( StatusResponse( responsecode.NOT_FOUND, "No such property: %s%s" % (uid if uid else "", encodeXMLName(*qname)))) self.log.debug("Read for %s%s on %s" % (("{%s}:" % (uid, )) if uid else "", qname, self.childPropertyStore.resource.fp.path)) return self.childPropertyStore.get(qname, uid=uid)
def get(self, qname, uid=None, cache=True): if cache: propertyCache = self.propertyCache() qnameuid = qname + (uid,) if qnameuid in propertyCache: return propertyCache[qnameuid] else: raise HTTPError(StatusResponse( responsecode.NOT_FOUND, "No such property: %s%s" % (uid if uid else "", encodeXMLName(*qname)) )) self.log_debug("Read for %s%s on %s" % ( ("{%s}:" % (uid,)) if uid else "", qname, self.childPropertyStore.resource.fp.path )) return self.childPropertyStore.get(qname, uid=uid)
def get(self, qname, uid=None): raise HTTPError( StatusResponse(responsecode.NOT_FOUND, "No such property: %s" % (encodeXMLName(*qname), )))
def _encode(clazz, name, uid=None): result = urllib.quote(encodeXMLName(*name), safe='{}:') if uid: result = uid + result r = clazz.deadPropertyXattrPrefix + result return r
class xattrPropertyStore(object): """ This implementation uses Bob Ippolito's xattr package, available from:: http://undefined.org/python/#xattr Note that the Bob's xattr package is specific to Linux and Darwin, at least presently. """ # # Dead properties are stored as extended attributes on disk. In order to # avoid conflicts with other attributes, prefix dead property names. # deadPropertyXattrPrefix = "WebDAV:" # Linux seems to require that attribute names use a "user." prefix. # FIXME: Is is a system-wide thing, or a per-filesystem thing? # If the latter, how to we detect the file system? if sys.platform == "linux2": deadPropertyXattrPrefix = "user." def _encode(clazz, name, uid=None): result = urllib.quote(encodeXMLName(*name), safe='{}:') if uid: result = uid + result r = clazz.deadPropertyXattrPrefix + result return r def _decode(clazz, name): name = urllib.unquote(name[len(clazz.deadPropertyXattrPrefix):]) index1 = name.find("{") index2 = name.find("}") if (index1 is -1 or index2 is -1 or not len(name) > index2): raise ValueError("Invalid encoded name: %r" % (name, )) if index1 == 0: uid = None else: uid = name[:index1] propnamespace = name[index1 + 1:index2] propname = name[index2 + 1:] return (propnamespace, propname, uid) _encode = classmethod(_encode) _decode = classmethod(_decode) def __init__(self, resource): self.resource = resource self.attrs = xattr.xattr(self.resource.fp.path) def get(self, qname, uid=None): """ Retrieve the value of a property stored as an extended attribute on the wrapped path. @param qname: The property to retrieve as a two-tuple of namespace URI and local name. @param uid: The per-user identifier for per user properties. @raise HTTPError: If there is no value associated with the given property. @return: A L{WebDAVDocument} representing the value associated with the given property. """ try: data = self.attrs.get(self._encode(qname, uid)) except KeyError: raise HTTPError( StatusResponse( responsecode.NOT_FOUND, "No such property: %s" % (encodeXMLName(*qname), ))) except IOError, e: if e.errno in _ATTR_MISSING or e.errno == errno.ENOENT: raise HTTPError( StatusResponse( responsecode.NOT_FOUND, "No such property: %s" % (encodeXMLName(*qname), ))) else: raise HTTPError( StatusResponse( statusForFailure(Failure()), "Unable to read property: %s" % (encodeXMLName(*qname), ))) # # Unserialize XML data from an xattr. The storage format has changed # over time: # # 1- Started with XML # 2- Started compressing the XML due to limits on xattr size # 3- Switched to pickle which is faster, still compressing # 4- Back to compressed XML for interoperability, size # # We only write the current format, but we also read the old # ones for compatibility. # legacy = False try: data = decompress(data) except zlib.error: legacy = True try: doc = WebDAVDocument.fromString(data) except ValueError: try: doc = unpickle(data) except UnpicklingError: format = "Invalid property value stored on server: %s %s" msg = format % (encodeXMLName(*qname), data) err(None, msg) raise HTTPError( StatusResponse(responsecode.INTERNAL_SERVER_ERROR, msg)) else: legacy = True if legacy: self.set(doc.root_element) return doc.root_element
StatusResponse(responsecode.BAD_REQUEST, "REPORT request body may not be empty")) # # Parse request # namespace = doc.root_element.namespace name = doc.root_element.name if namespace: if namespace == davxml.dav_namespace: request.submethod = "DAV:" + name elif namespace == caldavxml.caldav_namespace: request.submethod = "CalDAV:" + name else: request.submethod = encodeXMLName(namespace, name) else: request.submethod = name def to_method(namespace, name): if namespace: s = "_".join((namespace, name)) else: s = name ok = string.ascii_letters + string.digits + "_" out = [] for c in s: if c in ok: out.append(c) else:
def toString(self): return encodeXMLName(self.namespace, self.name)
"REPORT request body may not be empty" )) # # Parse request # namespace = doc.root_element.namespace name = doc.root_element.name if namespace: if namespace == davxml.dav_namespace: request.submethod = "DAV:" + name elif namespace == caldavxml.caldav_namespace: request.submethod = "CalDAV:" + name else: request.submethod = encodeXMLName(namespace, name) else: request.submethod = name def to_method(namespace, name): if namespace: s = "_".join((namespace, name)) else: s = name ok = string.ascii_letters + string.digits + "_" out = [] for c in s: if c in ok: out.append(c)
if doc is None: raise HTTPError(StatusResponse(responsecode.BAD_REQUEST, "REPORT request body may not be empty")) # # Parse request # namespace = doc.root_element.namespace name = doc.root_element.name if namespace: if namespace == davxml.dav_namespace: request.submethod = "DAV:" + name elif namespace == caldavxml.caldav_namespace: request.submethod = "CalDAV:" + name else: request.submethod = encodeXMLName(namespace, name) else: request.submethod = name def to_method(namespace, name): if namespace: s = "_".join((namespace, name)) else: s = name ok = string.ascii_letters + string.digits + "_" out = [] for c in s: if c in ok: out.append(c) else:
def __repr__(self): return "%s = %s" % (encodeXMLName(self.ns, self.name), self.value)
def get(self, qname, uid=None): raise HTTPError(StatusResponse( responsecode.NOT_FOUND, "No such property: %s" % (encodeXMLName(*qname),) ))
def to_method(s): out = [] for c in s: if c in ok: out.append(c) else: out.append("_") return "report_" + "".join(out) if namespace: method_name = to_method("_".join((namespace, name))) if namespace == davxml.dav_namespace: request.submethod = "DAV:" + name else: request.submethod = encodeXMLName(namespace, name) else: method_name = to_method(name) request.submethod = name try: method = getattr(self, method_name) # Also double-check via supported-reports property reports = self.supportedReports() test = lookupElement((namespace, name)) if not test: raise AttributeError() test = davxml.Report(test()) if test not in reports:
def action_readProperty(rootResource, directory, store, resource, qname): property = (yield resource.readProperty(qname, None)) print("%r on %s:" % (encodeXMLName(*qname), resource)) print("") print(property.toxml())
def action_readProperty(resource, qname): property = (yield resource.readProperty(qname, None)) print "%r on %s:" % (encodeXMLName(*qname), resource) print "" print property.toxml()