1
# -*- test-case-name: twisted.web2.dav.test.test_prop.PROP.test_PROPFIND -*-
3
# Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
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:
12
# The above copyright notice and this permission notice shall be included in all
13
# copies or substantial portions of the Software.
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
23
# DRI: Wilfredo Sanchez, wsanchez@apple.com
27
WebDAV PROPFIND method
30
__all__ = ["http_PROPFIND"]
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
42
def http_PROPFIND(self, request):
44
Respond to a PROPFIND request. (RFC 2518, section 8.1)
47
log.err("File not found: %s" % (self.fp.path,))
48
raise HTTPError(responsecode.NOT_FOUND)
54
doc = waitForDeferred(davXMLFromStream(request.stream))
58
log.err("Error while handling PROPFIND body: %s" % (e,))
59
raise HTTPError(StatusResponse(responsecode.BAD_REQUEST, str(e)))
62
# No request body means get all properties.
63
search_properties = "all"
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))
73
raise HTTPError(StatusResponse(responsecode.BAD_REQUEST, error))
75
container = find.children[0]
77
if isinstance(container, davxml.AllProperties):
79
search_properties = "all"
80
elif isinstance(container, davxml.PropertyName):
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]
87
raise AssertionError("Unexpected element type in %s: %s"
88
% (davxml.PropertyFind.sname(), container))
91
# Generate XML output stream
93
request_uri = request.uri
94
depth = request.headers.getHeader("depth", "infinity")
98
resources = [(self, None)]
99
resources.extend(self.findChildren(depth))
101
for resource, uri in resources:
103
uri = normalizeURL(request_uri)
104
if self.isCollection() and not uri.endswith("/"): uri += "/"
106
uri = joinURL(request_uri, uri)
108
resource_properties = waitForDeferred(resource.listProperties(request))
109
yield resource_properties
110
resource_properties = resource_properties.getResult()
112
if search_properties is "names":
113
properties_by_status = {
114
responsecode.OK: [propertyName(p) for p in resource_properties]
117
properties_by_status = {
118
responsecode.OK : [],
119
responsecode.NOT_FOUND : [],
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()
127
properties_to_enumerate = search_properties
129
for property in properties_to_enumerate:
130
if property in resource_properties:
132
resource_property = waitForDeferred(resource.readProperty(property, request))
133
yield resource_property
134
resource_property = resource_property.getResult()
138
log.err("Error reading property %r for resource %s: %s" % (property, uri, f.value))
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))
145
properties_by_status[responsecode.OK].append(resource_property)
147
log.err("Can't find property %r for resource %s" % (property, uri))
148
properties_by_status[responsecode.NOT_FOUND].append(propertyName(property))
152
for status in properties_by_status:
153
properties = properties_by_status[status]
154
if not properties: continue
156
xml_status = davxml.Status.fromResponseCode(status)
157
xml_container = davxml.PropertyContainer(*properties)
158
xml_propstat = davxml.PropertyStatus(xml_container, xml_status)
160
propstats.append(xml_propstat)
162
xml_resource = davxml.HRef(uri)
163
xml_response = davxml.PropertyStatusResponse(xml_resource, *propstats)
165
xml_responses.append(xml_response)
170
yield MultiStatusResponse(xml_responses)
172
http_PROPFIND = deferredGenerator(http_PROPFIND)
178
def propertyName(name):
179
property_namespace, property_name = name
180
class PropertyName (davxml.WebDAVEmptyElement):
181
namespace = property_namespace
183
return PropertyName()