def error(self): """ Convert any 2xx codes in the propstat responses to 424 Failed Dependency. """ for index, propstat in enumerate(self.propstats): # Check the status changed_status = False newchildren = [] for child in propstat.children: if isinstance(child, element.Status) and (child.code / 100 == 2): # Change the code newchildren.append( element.Status.fromResponseCode( responsecode.FAILED_DEPENDENCY)) changed_status = True elif changed_status and isinstance( child, element.ResponseDescription): newchildren.append( element.ResponseDescription(responsecode.RESPONSES[ responsecode.FAILED_DEPENDENCY])) else: newchildren.append(child) self.propstats[index] = element.PropertyStatus(*newchildren)
def responseForHref(request, responses, href, resource, propertiesForResource, propertyreq): if propertiesForResource is not None: properties_by_status = waitForDeferred( propertiesForResource(request, propertyreq, resource)) yield properties_by_status properties_by_status = properties_by_status.getResult() propstats = [] for status in properties_by_status: properties = properties_by_status[status] if properties: xml_status = element.Status.fromResponseCode(status) xml_container = element.PropertyContainer(*properties) xml_propstat = element.PropertyStatus(xml_container, xml_status) propstats.append(xml_propstat) if propstats: responses.append(element.PropertyStatusResponse(href, *propstats)) else: responses.append( element.StatusResponse( href, element.Status.fromResponseCode(responsecode.OK), ))
def _defer(properties_by_status): propstats = [] for status in properties_by_status: properties = properties_by_status[status] if properties: xml_status = element.Status.fromResponseCode(status) xml_container = element.PropertyContainer(*properties) xml_propstat = element.PropertyStatus(xml_container, xml_status) propstats.append(xml_propstat) # Always need to have at least one propstat present (required by Prefer header behavior) if len(propstats) == 0: propstats.append(element.PropertyStatus( element.PropertyContainer(), element.Status.fromResponseCode(responsecode.OK) )) if propstats: responses.append(element.PropertyStatusResponse(href, *propstats))
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 = element.WebDAVUnknownElement.withName( property.namespace, property.name) if code > 400: # Error codes only log.error("Error during {method} for {property}: {msg}", method=self.method, property=property, msg=message) children = [] children.append(element.PropertyContainer(property)) children.append(element.Status.fromResponseCode(code)) if error is not None: children.append(error) if message is not None: children.append(element.ResponseDescription(message)) self.propstats.append(element.PropertyStatus(*children))
def report_DAV__expand_property(self, request, expand_property): """ Generate an expand-property REPORT. (RFC 3253, section 3.8) TODO: for simplicity we will only support one level of expansion. """ # Verify root element if not isinstance(expand_property, element.ExpandProperty): raise ValueError( "%s expected as root element, not %s." % (element.ExpandProperty.sname(), expand_property.sname())) # Only handle Depth: 0 depth = request.headers.getHeader("depth", "0") if depth != "0": log.error("Non-zero depth is not allowed: %s" % (depth, )) raise HTTPError( StatusResponse(responsecode.BAD_REQUEST, "Depth %s not allowed" % (depth, ))) # # Get top level properties to expand and make sure we only have one level # properties = {} for property in expand_property.children: namespace = property.attributes.get("namespace", dav_namespace) name = property.attributes.get("name", "") # Make sure children have no children props_to_find = [] for child in property.children: if child.children: log.error( "expand-property REPORT only supports single level expansion" ) raise HTTPError( StatusResponse( responsecode.NOT_IMPLEMENTED, "expand-property REPORT only supports single level expansion" )) child_namespace = child.attributes.get("namespace", dav_namespace) child_name = child.attributes.get("name", "") props_to_find.append((child_namespace, child_name)) properties[(namespace, name)] = props_to_find # # Generate the expanded responses status for each top-level property # properties_by_status = { responsecode.OK: [], responsecode.NOT_FOUND: [], } filteredaces = None lastParent = None for qname in properties.iterkeys(): try: prop = (yield self.readProperty(qname, request)) # Form the PROPFIND-style DAV:prop element we need later props_to_return = element.PropertyContainer(*properties[qname]) # Now dereference any HRefs responses = [] for href in prop.children: if isinstance(href, element.HRef): # Locate the Href resource and its parent resource_uri = str(href) child = (yield request.locateResource(resource_uri)) if not child or not child.exists(): responses.append( element.StatusResponse( href, element.Status.fromResponseCode( responsecode.NOT_FOUND))) continue parent = (yield request.locateResource( parentForURL(resource_uri))) # Check privileges on parent - must have at least DAV:read try: yield parent.checkPrivileges(request, (element.Read(), )) except AccessDeniedError: responses.append( element.StatusResponse( href, element.Status.fromResponseCode( responsecode.FORBIDDEN))) continue # Cache the last parent's inherited aces for checkPrivileges optimization if lastParent != parent: lastParent = parent # Do some optimisation of access control calculation by determining any inherited ACLs outside of # the child resource loop and supply those to the checkPrivileges on each child. filteredaces = ( yield parent.inheritedACEsforChildren(request)) # Check privileges - must have at least DAV:read try: yield child.checkPrivileges( request, (element.Read(), ), inherited_aces=filteredaces) except AccessDeniedError: responses.append( element.StatusResponse( href, element.Status.fromResponseCode( responsecode.FORBIDDEN))) continue # Now retrieve all the requested properties on the HRef resource yield prop_common.responseForHref( request, responses, href, child, prop_common.propertyListForResource, props_to_return, ) prop.children = responses properties_by_status[responsecode.OK].append(prop) except: f = Failure() log.error( "Error reading property {qname} for resource {req}: {failure}", qname=qname, req=request.uri, failure=f.value) status = statusForFailure(f, "getting property: %s" % (qname, )) if status not in properties_by_status: properties_by_status[status] = [] properties_by_status[status].append(propertyName(qname)) # Build the overall response propstats = [ element.PropertyStatus( element.PropertyContainer(*properties_by_status[pstatus]), element.Status.fromResponseCode(pstatus)) for pstatus in properties_by_status if properties_by_status[pstatus] ] returnValue( MultiStatusResponse( (element.PropertyStatusResponse(element.HRef(request.uri), *propstats), )))
responsecode.NOT_FOUND].append( propertyName(property)) elif not returnMinimal: 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) # Always need to have at least one propstat present (required by Prefer header behavior) if len(propstats) == 0: propstats.append( davxml.PropertyStatus( davxml.PropertyContainer(), davxml.Status.fromResponseCode(responsecode.OK))) xml_resource = davxml.HRef(uri) xml_response = davxml.PropertyStatusResponse(xml_resource, *propstats) xml_responses.append(xml_response)