Exemplo n.º 1
0
 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)
Exemplo n.º 2
0
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),
            ))
Exemplo n.º 3
0
    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))
Exemplo n.º 4
0
    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))
Exemplo n.º 5
0
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), )))
Exemplo n.º 6
0
                                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)