~certify-web-dev/twisted/certify-trunk

« back to all changes in this revision

Viewing changes to twisted/web2/dav/method/propfind.py

  • Committer: Bazaar Package Importer
  • Author(s): Matthias Klose
  • Date: 2007-01-17 14:52:35 UTC
  • mfrom: (1.1.5 upstream) (2.1.2 etch)
  • Revision ID: james.westby@ubuntu.com-20070117145235-btmig6qfmqfen0om
Tags: 2.5.0-0ubuntu1
New upstream version, compatible with python2.5.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# -*- test-case-name: twisted.web2.dav.test.test_prop.PROP.test_PROPFIND -*-
 
2
##
 
3
# Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
 
4
#
 
5
# Permission is hereby granted, free of charge, to any person obtaining a copy
 
6
# of this software and associated documentation files (the "Software"), to deal
 
7
# in the Software without restriction, including without limitation the rights
 
8
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 
9
# copies of the Software, and to permit persons to whom the Software is
 
10
# furnished to do so, subject to the following conditions:
 
11
 
12
# The above copyright notice and this permission notice shall be included in all
 
13
# copies or substantial portions of the Software.
 
14
 
15
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 
16
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 
17
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 
18
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 
19
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 
20
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 
21
# SOFTWARE.
 
22
#
 
23
# DRI: Wilfredo Sanchez, wsanchez@apple.com
 
24
##
 
25
 
 
26
"""
 
27
WebDAV PROPFIND method
 
28
"""
 
29
 
 
30
__all__ = ["http_PROPFIND"]
 
31
 
 
32
from twisted.python import log
 
33
from twisted.python.failure import Failure
 
34
from twisted.internet.defer import deferredGenerator, waitForDeferred
 
35
from twisted.web2.http import HTTPError
 
36
from twisted.web2 import responsecode
 
37
from twisted.web2.http import StatusResponse
 
38
from twisted.web2.dav import davxml
 
39
from twisted.web2.dav.http import MultiStatusResponse, statusForFailure
 
40
from twisted.web2.dav.util import normalizeURL, joinURL, davXMLFromStream
 
41
 
 
42
def http_PROPFIND(self, request):
 
43
    """
 
44
    Respond to a PROPFIND request. (RFC 2518, section 8.1)
 
45
    """
 
46
    if not self.exists():
 
47
        log.err("File not found: %s" % (self.fp.path,))
 
48
        raise HTTPError(responsecode.NOT_FOUND)
 
49
 
 
50
    #
 
51
    # Read request body
 
52
    #
 
53
    try:
 
54
        doc = waitForDeferred(davXMLFromStream(request.stream))
 
55
        yield doc
 
56
        doc = doc.getResult()
 
57
    except ValueError, e:
 
58
        log.err("Error while handling PROPFIND body: %s" % (e,))
 
59
        raise HTTPError(StatusResponse(responsecode.BAD_REQUEST, str(e)))
 
60
 
 
61
    if doc is None:
 
62
        # No request body means get all properties.
 
63
        search_properties = "all"
 
64
    else:
 
65
        #
 
66
        # Parse request
 
67
        #
 
68
        find = doc.root_element
 
69
        if not isinstance(find, davxml.PropertyFind):
 
70
            error = ("Non-%s element in PROPFIND request body: %s"
 
71
                     % (davxml.PropertyFind.sname(), find))
 
72
            log.err(error)
 
73
            raise HTTPError(StatusResponse(responsecode.BAD_REQUEST, error))
 
74
 
 
75
        container = find.children[0]
 
76
 
 
77
        if isinstance(container, davxml.AllProperties):
 
78
            # Get all properties
 
79
            search_properties = "all"
 
80
        elif isinstance(container, davxml.PropertyName):
 
81
            # Get names only
 
82
            search_properties = "names"
 
83
        elif isinstance(container, davxml.PropertyContainer):
 
84
            properties = container.children
 
85
            search_properties = [(p.namespace, p.name) for p in properties]
 
86
        else:
 
87
            raise AssertionError("Unexpected element type in %s: %s"
 
88
                                 % (davxml.PropertyFind.sname(), container))
 
89
 
 
90
    #
 
91
    # Generate XML output stream
 
92
    #
 
93
    request_uri = request.uri
 
94
    depth = request.headers.getHeader("depth", "infinity")
 
95
 
 
96
    xml_responses = []
 
97
 
 
98
    resources = [(self, None)]
 
99
    resources.extend(self.findChildren(depth))
 
100
 
 
101
    for resource, uri in resources:
 
102
        if uri is None:
 
103
            uri = normalizeURL(request_uri)
 
104
            if self.isCollection() and not uri.endswith("/"): uri += "/"
 
105
        else:
 
106
            uri = joinURL(request_uri, uri)
 
107
 
 
108
        resource_properties = waitForDeferred(resource.listProperties(request))
 
109
        yield resource_properties
 
110
        resource_properties = resource_properties.getResult()
 
111
 
 
112
        if search_properties is "names":
 
113
            properties_by_status = {
 
114
                responsecode.OK: [propertyName(p) for p in resource_properties]
 
115
            }
 
116
        else:
 
117
            properties_by_status = {
 
118
                responsecode.OK        : [],
 
119
                responsecode.NOT_FOUND : [],
 
120
            }
 
121
 
 
122
            if search_properties is "all":
 
123
                properties_to_enumerate = waitForDeferred(resource.listAllprop(request))
 
124
                yield properties_to_enumerate
 
125
                properties_to_enumerate = properties_to_enumerate.getResult()
 
126
            else:
 
127
                properties_to_enumerate = search_properties
 
128
 
 
129
            for property in properties_to_enumerate:
 
130
                if property in resource_properties:
 
131
                    try:
 
132
                        resource_property = waitForDeferred(resource.readProperty(property, request))
 
133
                        yield resource_property
 
134
                        resource_property = resource_property.getResult()
 
135
                    except:
 
136
                        f = Failure()
 
137
 
 
138
                        log.err("Error reading property %r for resource %s: %s" % (property, uri, f.value))
 
139
 
 
140
                        status = statusForFailure(f, "getting property: %s" % (property,))
 
141
                        if status not in properties_by_status:
 
142
                            properties_by_status[status] = []
 
143
                        properties_by_status[status].append(propertyName(property))
 
144
                    else:
 
145
                        properties_by_status[responsecode.OK].append(resource_property)
 
146
                else:
 
147
                    log.err("Can't find property %r for resource %s" % (property, uri))
 
148
                    properties_by_status[responsecode.NOT_FOUND].append(propertyName(property))
 
149
 
 
150
        propstats = []
 
151
 
 
152
        for status in properties_by_status:
 
153
            properties = properties_by_status[status]
 
154
            if not properties: continue
 
155
 
 
156
            xml_status    = davxml.Status.fromResponseCode(status)
 
157
            xml_container = davxml.PropertyContainer(*properties)
 
158
            xml_propstat  = davxml.PropertyStatus(xml_container, xml_status)
 
159
 
 
160
            propstats.append(xml_propstat)
 
161
 
 
162
        xml_resource = davxml.HRef(uri)
 
163
        xml_response = davxml.PropertyStatusResponse(xml_resource, *propstats)
 
164
 
 
165
        xml_responses.append(xml_response)
 
166
 
 
167
    #
 
168
    # Return response
 
169
    #
 
170
    yield MultiStatusResponse(xml_responses)
 
171
 
 
172
http_PROPFIND = deferredGenerator(http_PROPFIND)
 
173
 
 
174
##
 
175
# Utilities
 
176
##
 
177
 
 
178
def propertyName(name):
 
179
    property_namespace, property_name = name
 
180
    class PropertyName (davxml.WebDAVEmptyElement):
 
181
        namespace = property_namespace
 
182
        name = property_name
 
183
    return PropertyName()