[CalendarServer-changes] [2310]
CalendarServer/branches/release/CalendarServer-1.3-dev
source_changes at macosforge.org
source_changes at macosforge.org
Mon Apr 14 12:09:54 PDT 2008
Revision: 2310
http://trac.macosforge.org/projects/calendarserver/changeset/2310
Author: cdaboo at apple.com
Date: 2008-04-14 12:09:53 -0700 (Mon, 14 Apr 2008)
Log Message:
-----------
Puller-up r2303.
Modified Paths:
--------------
CalendarServer/branches/release/CalendarServer-1.3-dev/lib-patches/Twisted/twisted.web2.dav.resource.patch
CalendarServer/branches/release/CalendarServer-1.3-dev/twistedcaldav/extensions.py
CalendarServer/branches/release/CalendarServer-1.3-dev/twistedcaldav/method/__init__.py
CalendarServer/branches/release/CalendarServer-1.3-dev/twistedcaldav/static.py
Added Paths:
-----------
CalendarServer/branches/release/CalendarServer-1.3-dev/twistedcaldav/method/propfind.py
Modified: CalendarServer/branches/release/CalendarServer-1.3-dev/lib-patches/Twisted/twisted.web2.dav.resource.patch
===================================================================
--- CalendarServer/branches/release/CalendarServer-1.3-dev/lib-patches/Twisted/twisted.web2.dav.resource.patch 2008-04-14 18:52:19 UTC (rev 2309)
+++ CalendarServer/branches/release/CalendarServer-1.3-dev/lib-patches/Twisted/twisted.web2.dav.resource.patch 2008-04-14 19:09:53 UTC (rev 2310)
@@ -382,17 +382,42 @@
aces.append(davxml.ACE(*children))
else:
aces.extend(inherited_aces)
-@@ -1128,7 +1200,7 @@
+@@ -1105,8 +1177,7 @@
+ the child resource loop and supply those to the checkPrivileges on each child.
+
+ @param request: the L{IRequest} for the request in progress.
+- @return: a C{list} of L{Ace}s that child resources of this one will
+- inherit and which will match the currently authenticated principal.
++ @return: a C{list} of L{Ace}s that child resources of this one will inherit.
+ """
+
+ # Get the parent ACLs with inheritance and preserve the <inheritable> element.
+@@ -1128,21 +1199,9 @@
# Adjust ACE for inherit on this resource
children = list(ace.children)
children.remove(TwistedACLInheritable())
- children.append(davxml.Inherited(davxml.HRef.fromString(request.urlForResource(self))))
+ children.append(davxml.Inherited(davxml.HRef(request.urlForResource(self))))
aces.append(davxml.ACE(*children))
-
- # Filter out those that do not have a principal match with the current principal
-@@ -1152,49 +1224,69 @@
+-
+- # Filter out those that do not have a principal match with the current principal
+- principal = self.currentPrincipal(request)
+- filteredaces = []
+- for ace in aces:
+- if self.matchPrincipal(principal, ace.principal, request):
+- if ace.invert:
+- continue
+- else:
+- if not ace.invert:
+- continue
+- filteredaces.append(ace)
+- yield filteredaces
++ yield aces
+ inheritedACEsforChildren = deferredGenerator(inheritedACEsforChildren)
+
+@@ -1152,49 +1211,69 @@
+
This implementation returns an empty set.
"""
-
@@ -489,7 +514,7 @@
def samePrincipal(self, principal1, principal2):
"""
Check whether the two prinicpals are exactly the same in terms of
-@@ -1219,7 +1311,6 @@
+@@ -1219,7 +1298,6 @@
return False
def matchPrincipal(self, principal1, principal2, request):
@@ -497,7 +522,7 @@
"""
Check whether the principal1 is a principal in the set defined by
principal2.
-@@ -1244,6 +1335,9 @@
+@@ -1244,6 +1322,9 @@
if isinstance(principal1, davxml.Unauthenticated):
yield False
return
@@ -507,7 +532,7 @@
else:
yield True
return
-@@ -1271,7 +1365,6 @@
+@@ -1271,7 +1352,6 @@
assert principal2 is not None, "principal2 is None"
@@ -515,7 +540,7 @@
# Compare two HRefs and do group membership test as well
if principal1 == principal2:
yield True
-@@ -1302,9 +1395,9 @@
+@@ -1302,9 +1382,9 @@
def testGroup(group):
# Get principal resource for principal2
if group and isinstance(group, DAVPrincipalResource):
@@ -528,7 +553,7 @@
return False
-@@ -1351,11 +1444,16 @@
+@@ -1351,11 +1431,16 @@
@return C{True} if C{href_principal} is valid, C{False} otherwise.
This implementation tests for a href element that corresponds to
@@ -548,7 +573,7 @@
return d
def resolvePrincipal(self, principal, request):
-@@ -1432,7 +1530,7 @@
+@@ -1432,7 +1517,7 @@
log.err("DAV:self ACE is set on non-principal resource %r" % (self,))
yield None
return
@@ -557,7 +582,7 @@
if isinstance(principal, davxml.HRef):
yield principal
-@@ -1517,6 +1615,270 @@
+@@ -1517,6 +1602,270 @@
return None
##
@@ -828,7 +853,7 @@
# HTTP
##
-@@ -1567,7 +1929,7 @@
+@@ -1567,7 +1916,7 @@
def findChildren(self, depth, request, callback, privileges=None, inherited_aces=None):
return succeed(None)
@@ -837,7 +862,7 @@
"""
Resource representing a WebDAV principal. (RFC 3744, section 2)
"""
-@@ -1577,7 +1939,7 @@
+@@ -1577,7 +1926,7 @@
# WebDAV
##
@@ -846,7 +871,7 @@
(dav_namespace, "alternate-URI-set"),
(dav_namespace, "principal-URL" ),
(dav_namespace, "group-member-set" ),
-@@ -1585,14 +1947,11 @@
+@@ -1585,14 +1934,11 @@
)
def davComplianceClasses(self):
@@ -862,7 +887,7 @@
def readProperty(self, property, request):
def defer():
if type(property) is tuple:
-@@ -1610,10 +1969,10 @@
+@@ -1610,10 +1956,10 @@
return davxml.PrincipalURL(davxml.HRef(self.principalURL()))
if name == "group-member-set":
@@ -875,7 +900,7 @@
if name == "resourcetype":
if self.isCollection():
-@@ -1677,8 +2036,27 @@
+@@ -1677,8 +2023,27 @@
if self.principalURL() == uri:
return True
else:
@@ -904,7 +929,7 @@
class AccessDeniedError(Exception):
def __init__(self, errors):
"""
-@@ -1718,6 +2096,37 @@
+@@ -1718,6 +2083,37 @@
davxml.registerElement(TwistedACLInheritable)
davxml.ACE.allowed_children[(twisted_dav_namespace, "inheritable")] = (0, 1)
Modified: CalendarServer/branches/release/CalendarServer-1.3-dev/twistedcaldav/extensions.py
===================================================================
--- CalendarServer/branches/release/CalendarServer-1.3-dev/twistedcaldav/extensions.py 2008-04-14 18:52:19 UTC (rev 2309)
+++ CalendarServer/branches/release/CalendarServer-1.3-dev/twistedcaldav/extensions.py 2008-04-14 19:09:53 UTC (rev 2310)
@@ -83,10 +83,10 @@
def authorizationPrincipal(self, request, authid, authnPrincipal):
"""
Determine the authorization principal for the given request and authentication principal.
- This implementation looks for an X-Authorize-As header value to use as the authoization principal.
+ This implementation looks for an X-Authorize-As header value to use as the authorization principal.
@param request: the L{IRequest} for the request in progress.
- @param authid: a string containing the uthentication/authorization identifier
+ @param authid: a string containing the authentication/authorization identifier
for the principal to lookup.
@param authnPrincipal: the L{IDAVPrincipal} for the authenticated principal
@return: a deferred result C{tuple} of (L{IDAVPrincipal}, C{str}) containing the authorization principal
@@ -176,6 +176,7 @@
if depth == "0" or not self.isCollection():
yield None
+ return
# First find all depth 1 children
#children = []
@@ -230,10 +231,13 @@
for resource, url in items[2]:
badcallback(resource, url)
- # TODO: Depth: inifinity support
+ # TODO: Depth: infinity support
if depth == "infinity":
for collection, url in allowed_collections:
- d = waitForDeferred(collection.findChildrenFaster(request, depth, okcallback, badcallback, names, privileges, inherited_aces=None))
+ collection_inherited_aces = waitForDeferred(collection.inheritedACEsforChildren(request))
+ yield collection_inherited_aces
+ collection_inherited_aces = collection_inherited_aces.getResult()
+ d = waitForDeferred(collection.findChildrenFaster(depth, request, okcallback, badcallback, names, privileges, inherited_aces=collection_inherited_aces))
yield d
d.getResult()
@@ -243,6 +247,10 @@
def checkACLPrivilege(self, request, acl, privyset, privileges, inherited_aces):
+ if acl is None:
+ yield False
+ return
+
principal = self.currentPrincipal(request)
# Other principal types don't make sense as actors.
@@ -318,7 +326,30 @@
return acl
+ @deferredGenerator
+ def matchPrincipal(self, principal1, principal2, request):
+ """
+ Implementation of DAVResource.matchPrincipal that caches the principal match
+ for the duration of a request. This avoids having to do repeated group membership
+ tests when privileges on multiple resources are determined.
+ """
+
+ if not hasattr(request, "matchPrincipalCache"):
+ request.matchPrincipalCache = {}
+ # The interesting part of a principal is it's one child
+ principals = (principal1, principal2)
+ cache_key = tuple([str(p.children[0]) for p in principals])
+
+ match = request.matchPrincipalCache.get(cache_key, None)
+ if match is None:
+ match = waitForDeferred(super(DAVResource, self).matchPrincipal(principal1, principal2, request))
+ yield match
+ match = match.getResult()
+ request.matchPrincipalCache[cache_key] = match
+
+ yield match
+
class DAVPrincipalResource (SuperDAVPrincipalResource):
"""
Extended L{twisted.web2.dav.static.DAVFile} implementation.
@@ -335,7 +366,7 @@
return super(DAVPrincipalResource, self).readProperty(property, request)
def resourceType(self):
- # Allow live property to be overriden by dead property
+ # Allow live property to be overridden by dead property
if self.deadProperties().contains((dav_namespace, "resourcetype")):
return self.deadProperties().get((dav_namespace, "resourcetype"))
if self.isCollection():
Modified: CalendarServer/branches/release/CalendarServer-1.3-dev/twistedcaldav/method/__init__.py
===================================================================
--- CalendarServer/branches/release/CalendarServer-1.3-dev/twistedcaldav/method/__init__.py 2008-04-14 18:52:19 UTC (rev 2309)
+++ CalendarServer/branches/release/CalendarServer-1.3-dev/twistedcaldav/method/__init__.py 2008-04-14 19:09:53 UTC (rev 2310)
@@ -29,6 +29,7 @@
"get",
"mkcalendar",
"mkcol",
+ "propfind",
"put",
"report",
"report_calquery",
Copied: CalendarServer/branches/release/CalendarServer-1.3-dev/twistedcaldav/method/propfind.py (from rev 2303, CalendarServer/trunk/twistedcaldav/method/propfind.py)
===================================================================
--- CalendarServer/branches/release/CalendarServer-1.3-dev/twistedcaldav/method/propfind.py (rev 0)
+++ CalendarServer/branches/release/CalendarServer-1.3-dev/twistedcaldav/method/propfind.py 2008-04-14 19:09:53 UTC (rev 2310)
@@ -0,0 +1,209 @@
+# -*- test-case-name: twisted.web2.dav.test.test_prop.PROP.test_PROPFIND -*-
+##
+# Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+##
+
+"""
+WebDAV PROPFIND method
+"""
+
+__all__ = ["http_PROPFIND"]
+
+from twisted.python import log
+from twisted.python.failure import Failure
+from twisted.internet.defer import deferredGenerator, waitForDeferred
+from twisted.web2.http import HTTPError
+from twisted.web2 import responsecode
+from twisted.web2.http import StatusResponse
+from twisted.web2.dav import davxml
+from twisted.web2.dav.http import MultiStatusResponse, statusForFailure
+from twisted.web2.dav.util import normalizeURL, davXMLFromStream
+
+"""
+This is a direct copy of the twisted implementation of PROPFIND except that it uses the
+findChildrenFaster method to optimize child privilege checking.
+"""
+
+def http_PROPFIND(self, request):
+ """
+ Respond to a PROPFIND request. (RFC 2518, section 8.1)
+ """
+ if not self.exists():
+ log.err("File not found: %s" % (self.fp.path,))
+ raise HTTPError(responsecode.NOT_FOUND)
+
+ #
+ # Check authentication and access controls
+ #
+ x = waitForDeferred(self.authorize(request, (davxml.Read(),)))
+ yield x
+ x.getResult()
+
+ #
+ # Read request body
+ #
+ try:
+ doc = waitForDeferred(davXMLFromStream(request.stream))
+ yield doc
+ doc = doc.getResult()
+ except ValueError, e:
+ log.err("Error while handling PROPFIND body: %s" % (e,))
+ raise HTTPError(StatusResponse(responsecode.BAD_REQUEST, str(e)))
+
+ if doc is None:
+ # No request body means get all properties.
+ search_properties = "all"
+ else:
+ #
+ # Parse request
+ #
+ find = doc.root_element
+ if not isinstance(find, davxml.PropertyFind):
+ error = ("Non-%s element in PROPFIND request body: %s"
+ % (davxml.PropertyFind.sname(), find))
+ log.err(error)
+ raise HTTPError(StatusResponse(responsecode.BAD_REQUEST, error))
+
+ container = find.children[0]
+
+ if isinstance(container, davxml.AllProperties):
+ # Get all properties
+ search_properties = "all"
+ elif isinstance(container, davxml.PropertyName):
+ # Get names only
+ search_properties = "names"
+ elif isinstance(container, davxml.PropertyContainer):
+ properties = container.children
+ search_properties = [(p.namespace, p.name) for p in properties]
+ else:
+ raise AssertionError("Unexpected element type in %s: %s"
+ % (davxml.PropertyFind.sname(), container))
+
+ #
+ # Generate XML output stream
+ #
+ request_uri = request.uri
+ depth = request.headers.getHeader("depth", "infinity")
+
+ xml_responses = []
+
+ # FIXME: take advantage of the new generative properties of findChildren
+
+ my_url = normalizeURL(request_uri)
+ if self.isCollection() and not my_url.endswith("/"):
+ my_url += "/"
+
+ # Do some optimization of access control calculation by determining any inherited ACLs outside of
+ # the child resource loop and supply those to the checkPrivileges on each child.
+ filtered_aces = waitForDeferred(self.inheritedACEsforChildren(request))
+ yield filtered_aces
+ filtered_aces = filtered_aces.getResult()
+
+ resources = [(self, my_url)]
+
+ d = self.findChildrenFaster(depth, request, lambda x, y: resources.append((x, y)), None, None, (davxml.Read(),), inherited_aces=filtered_aces)
+ x = waitForDeferred(d)
+ yield x
+ x.getResult()
+
+ for resource, uri in resources:
+ if search_properties is "names":
+ try:
+ resource_properties = waitForDeferred(resource.listProperties(request))
+ yield resource_properties
+ resource_properties = resource_properties.getResult()
+ except:
+ log.err("Unable to get properties for resource %r" % (resource,))
+ raise
+
+ properties_by_status = {
+ responsecode.OK: [propertyName(p) for p in resource_properties]
+ }
+ else:
+ properties_by_status = {
+ responsecode.OK : [],
+ responsecode.NOT_FOUND : [],
+ }
+
+ if search_properties is "all":
+ properties_to_enumerate = waitForDeferred(resource.listAllprop(request))
+ yield properties_to_enumerate
+ properties_to_enumerate = properties_to_enumerate.getResult()
+ else:
+ properties_to_enumerate = search_properties
+
+ for property in properties_to_enumerate:
+ has = waitForDeferred(resource.hasProperty(property, request))
+ yield has
+ has = has.getResult()
+ if has:
+ try:
+ resource_property = waitForDeferred(resource.readProperty(property, request))
+ yield resource_property
+ resource_property = resource_property.getResult()
+ except:
+ f = Failure()
+
+ log.err("Error reading property %r for resource %s: %s" % (property, uri, f.value))
+
+ status = statusForFailure(f, "getting property: %s" % (property,))
+ if status not in properties_by_status:
+ properties_by_status[status] = []
+ properties_by_status[status].append(propertyName(property))
+ else:
+ properties_by_status[responsecode.OK].append(resource_property)
+ else:
+ 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)
+
+##
+# Utilities
+##
+
+def propertyName(name):
+ property_namespace, property_name = name
+ pname = davxml.WebDAVUnknownElement()
+ pname.namespace = property_namespace
+ pname.name = property_name
+ return pname
Modified: CalendarServer/branches/release/CalendarServer-1.3-dev/twistedcaldav/static.py
===================================================================
--- CalendarServer/branches/release/CalendarServer-1.3-dev/twistedcaldav/static.py 2008-04-14 18:52:19 UTC (rev 2309)
+++ CalendarServer/branches/release/CalendarServer-1.3-dev/twistedcaldav/static.py 2008-04-14 19:09:53 UTC (rev 2310)
@@ -840,4 +840,5 @@
twistedcaldav.method.delete.CalDAVFile = CalDAVFile
twistedcaldav.method.get.CalDAVFile = CalDAVFile
twistedcaldav.method.mkcol.CalDAVFile = CalDAVFile
+twistedcaldav.method.propfind.CalDAVFile = CalDAVFile
twistedcaldav.method.put.CalDAVFile = CalDAVFile
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20080414/7e73a75e/attachment-0001.html
More information about the calendarserver-changes
mailing list