def getProperties(self, properties): """ Same as _getProperties, but with a cache lookup step in between. @return a davxml.PropertyContainer @see _getProperties """ # check if one of the requested properties is not in the cache allCached = True for pp in properties: if pp.qname() not in self.propertyCache.keys(): allCached = False break if not allCached: # since we need to make a request anyway, we # might as well request frequently needed elements -- but avoid duplicates rp = self.cachedProperties + [ pp for pp in properties if pp not in self.cachedProperties ] returned = self._getProperties(rp) else: props = [self.propertyCache[p.qname()] for p in properties] returned = davxml.PropertyContainer(*props) return returned
def add(self, what, property): """ Add a response. @param what: a status code or a L{Failure} for the given path. @param property: the property whose status is being reported. """ if type(what) is int: code = what error = None message = responsecode.RESPONSES[code] elif isinstance(what, Failure): code = statusForFailure(what) error = errorForFailure(what) message = messageForFailure(what) else: raise AssertionError("Unknown data type: %r" % (what, )) if len(property.children) > 0: # Re-instantiate as empty element. property = property.__class__() if code > 400: # Error codes only log.err("Error during %s for %s: %s" % (self.method, property, message)) children = [] children.append(davxml.PropertyContainer(property)) children.append(davxml.Status.fromResponseCode(code)) if error is not None: children.append(error) if message is not None: children.append(davxml.ResponseDescription(message)) self.propstats.append(davxml.PropertyStatus(*children))
def test_PROPPATCH_liveprop(self): """ PROPPATCH on a live property """ prop = davxml.GETETag.fromString("some-etag-string") patch = davxml.PropertyUpdate( davxml.Set(davxml.PropertyContainer(prop))) return self._simple_PROPPATCH(patch, prop, responsecode.FORBIDDEN, "edit of live property")
def test_PROPPATCH_exists_not(self): """ PROPPATCH remove a non-existant property """ prop = davxml.Timeout( ) # Timeout isn't a valid property, so it won't exist. patch = davxml.PropertyUpdate( davxml.Remove(davxml.PropertyContainer(prop))) return self._simple_PROPPATCH(patch, prop, responsecode.OK, "remove of non-existant property")
def processLockRequest(resource, request): """ Respond to a LOCK request. (RFC 2518, section 8.10) Relevant notes: """ requestStream = request.stream depth = getDepth(request.headers) #log.error(request.headers.getRawHeaders("X-Litmus")[0]) # generate DAVDocument from request body lockInfo = waitForDeferred( deferredGenerator(parseLockRequest)(requestStream)) yield lockInfo lockInfo = lockInfo.getResult() assertExclusiveLock(lockInfo) assertWriteLock(lockInfo) # we currently only allow lock depths of "0" assertZeroLockDepth(depth) # build the corresponding activelock element # e.g. http://www.webdav.org/specs/rfc2518.html#rfc.section.8.10.8 activeLock = buildActiveLock(lockInfo, depth) # extract the lock token lt = activeLock.childOfType(davxml.LockToken).childOfType(davxml.HRef) # make headers with lock token header lth = http_headers.Headers(rawHeaders={"Lock-Token": [lt]}) ld = davxml.LockDiscovery(activeLock) ignored = waitForDeferred( deferredGenerator(resource._setLock)(ld, request)) yield ignored ignored = ignored.getResult() # debug ignored = waitForDeferred(deferredGenerator(resource._getLock)()) yield ignored ignored = ignored.getResult() pp = davxml.PropertyContainer(ld) yield Response(code=responsecode.OK, headers=lth, stream=stream.MemoryStream(pp.toxml()))
def test_PROPFIND_basic(self): """ PROPFIND request """ def check_result(response): response = IResponse(response) if response.code != responsecode.MULTI_STATUS: self.fail("Incorrect response code for PROPFIND (%s != %s)" % (response.code, responsecode.MULTI_STATUS)) content_type = response.headers.getHeader("content-type") if content_type not in (http_headers.MimeType("text", "xml"), http_headers.MimeType( "application", "xml")): self.fail( "Incorrect content-type for PROPFIND response (%r not in %r)" % (content_type, (http_headers.MimeType("text", "xml"), http_headers.MimeType("application", "xml")))) return davXMLFromStream(response.stream).addCallback(check_xml) def check_xml(doc): multistatus = doc.root_element if not isinstance(multistatus, davxml.MultiStatus): self.fail( "PROPFIND response XML root element is not multistatus: %r" % (multistatus, )) for response in multistatus.childrenOfType( davxml.PropertyStatusResponse): if response.childOfType(davxml.HRef) == "/": for propstat in response.childrenOfType( davxml.PropertyStatus): status = propstat.childOfType(davxml.Status) properties = propstat.childOfType( davxml.PropertyContainer).children if status.code != responsecode.OK: self.fail( "PROPFIND failed (status %s) to locate live properties: %s" % (status.code, properties)) properties_to_find = [ p.qname() for p in live_properties ] for property in properties: qname = property.qname() if qname in properties_to_find: properties_to_find.remove(qname) else: self.fail( "PROPFIND found property we didn't ask for: %r" % (property, )) if properties_to_find: self.fail( "PROPFIND failed to find properties: %r" % (properties_to_find, )) break else: self.fail("No response for URI /") query = davxml.PropertyFind(davxml.PropertyContainer(*live_properties)) request = SimpleRequest(self.site, "PROPFIND", "/") depth = random.choice(("0", "1", "infinity", None)) if depth is not None: request.headers.setHeader("depth", depth) request.stream = MemoryStream(query.toxml()) return self.send(request, check_result)
def test_PROPPATCH_basic(self): """ PROPPATCH """ # FIXME: # Do PROPFIND to make sure it's still there # Test nonexistant resource # Test None namespace in property def check_patch_response(response): response = IResponse(response) if response.code != responsecode.MULTI_STATUS: self.fail("Incorrect response code for PROPFIND (%s != %s)" % (response.code, responsecode.MULTI_STATUS)) content_type = response.headers.getHeader("content-type") if content_type not in (http_headers.MimeType("text", "xml"), http_headers.MimeType( "application", "xml")): self.fail( "Incorrect content-type for PROPPATCH response (%r not in %r)" % (content_type, (http_headers.MimeType("text", "xml"), http_headers.MimeType("application", "xml")))) return davXMLFromStream( response.stream).addCallback(check_patch_xml) def check_patch_xml(doc): multistatus = doc.root_element if not isinstance(multistatus, davxml.MultiStatus): self.fail( "PROPFIND response XML root element is not multistatus: %r" % (multistatus, )) # Requested a property change one resource, so there should be exactly one response response = multistatus.childOfType(davxml.Response) # Should have a response description (its contents are arbitrary) response.childOfType(davxml.ResponseDescription) # Requested property change was on / self.failUnless( response.childOfType(davxml.HRef) == "/", "Incorrect response URI: %s != /" % (response.childOfType(davxml.HRef), )) # Requested one property change, so there should be exactly one property status propstat = response.childOfType(davxml.PropertyStatus) # And the contained property should be a SpiffyProperty self.failIf( propstat.childOfType( davxml.PropertyContainer).childOfType(SpiffyProperty) is None, "Not a SpiffyProperty in PROPPATCH property status: %s" % (propstat.toxml())) if not have_dead_properties: raise SkipTest( "No dead property store available for DAVFile. " "Install xattr (http://undefined.org/python/#xattr) to enable use of dead properties." ) # And the status should be 200 self.failUnless( propstat.childOfType(davxml.Status).code == responsecode.OK, "Incorrect status code for PROPPATCH of property %s: %s != %s" % (propstat.childOfType(davxml.PropertyContainer).toxml(), propstat.childOfType(davxml.Status).code, responsecode.OK)) patch = davxml.PropertyUpdate( davxml.Set( davxml.PropertyContainer( SpiffyProperty.fromString("This is a spiffy resource.")))) request = SimpleRequest(self.site, "PROPPATCH", "/") request.stream = MemoryStream(patch.toxml()) return self.send(request, check_patch_response)
properties_by_status[status] = [] properties_by_status[status].append(propertyName(property)) else: properties_by_status[responsecode.OK].append(resource_property) else: log.err("Can't find property %r for resource %s" % (property, uri)) properties_by_status[responsecode.NOT_FOUND].append(propertyName(property)) propstats = [] for status in properties_by_status: properties = properties_by_status[status] if not properties: continue xml_status = davxml.Status.fromResponseCode(status) xml_container = davxml.PropertyContainer(*properties) xml_propstat = davxml.PropertyStatus(xml_container, xml_status) propstats.append(xml_propstat) xml_resource = davxml.HRef(uri) xml_response = davxml.PropertyStatusResponse(xml_resource, *propstats) xml_responses.append(xml_response) # # Return response # yield MultiStatusResponse(xml_responses) http_PROPFIND = deferredGenerator(http_PROPFIND)