[CalendarServer-changes] [9264] CalendarServer/trunk

source_changes at macosforge.org source_changes at macosforge.org
Tue May 22 12:23:23 PDT 2012


Revision: 9264
          http://trac.macosforge.org/projects/calendarserver/changeset/9264
Author:   cdaboo at apple.com
Date:     2012-05-22 12:23:22 -0700 (Tue, 22 May 2012)
Log Message:
-----------
Tests for Prefer header support.

Modified Paths:
--------------
    CalendarServer/trunk/twext/web2/dav/method/propfind.py
    CalendarServer/trunk/twext/web2/dav/method/proppatch.py
    CalendarServer/trunk/twext/web2/dav/resource.py
    CalendarServer/trunk/twext/web2/http_headers.py
    CalendarServer/trunk/twistedcaldav/method/mkcol.py
    CalendarServer/trunk/twistedcaldav/method/post.py
    CalendarServer/trunk/twistedcaldav/method/propfind.py
    CalendarServer/trunk/twistedcaldav/method/put.py
    CalendarServer/trunk/twistedcaldav/method/report_common.py

Modified: CalendarServer/trunk/twext/web2/dav/method/propfind.py
===================================================================
--- CalendarServer/trunk/twext/web2/dav/method/propfind.py	2012-05-22 19:19:49 UTC (rev 9263)
+++ CalendarServer/trunk/twext/web2/dav/method/propfind.py	2012-05-22 19:23:22 UTC (rev 9264)
@@ -112,7 +112,12 @@
     if depth == "infinity":
         raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, davxml.PropfindFiniteDepth()))
 
-    brief = request.headers.getHeader("brief", False)
+    # Look for Prefer header first, then try Brief
+    prefer = request.headers.getHeader("prefer", {})
+    returnMinimal = "return-minimal" in prefer
+    noRoot = "depth-noroot" in prefer
+    if not returnMinimal:
+        returnMinimal = request.headers.getHeader("brief", False)
 
     xml_responses = []
 
@@ -128,7 +133,10 @@
     yield filtered_aces
     filtered_aces = filtered_aces.getResult()
 
-    resources = [(self, my_url)]
+    if depth in ("1", "infinity") and noRoot:
+        resources = []
+    else:
+        resources = [(self, my_url)]
 
     d = self.findChildren(depth, request, lambda x, y: resources.append((x, y)), (davxml.Read(),), inherited_aces=filtered_aces)
     x = waitForDeferred(d)
@@ -136,6 +144,7 @@
     x.getResult()
 
     for resource, uri in resources:
+
         if search_properties is "names":
             try:
                 resource_properties = waitForDeferred(resource.listProperties(request))
@@ -175,14 +184,14 @@
                         status = statusForFailure(f, "getting property: %s" % (property,))
                         if status not in properties_by_status:
                             properties_by_status[status] = []
-                        if not brief or status != responsecode.NOT_FOUND:
+                        if not returnMinimal or status != responsecode.NOT_FOUND:
                             properties_by_status[status].append(propertyName(property))
                     else:
                         if resource_property is not None:
                             properties_by_status[responsecode.OK].append(resource_property)
-                        elif not brief:
+                        elif not returnMinimal:
                             properties_by_status[responsecode.NOT_FOUND].append(propertyName(property))
-                elif not brief:
+                elif not returnMinimal:
                     properties_by_status[responsecode.NOT_FOUND].append(propertyName(property))
 
         propstats = []

Modified: CalendarServer/trunk/twext/web2/dav/method/proppatch.py
===================================================================
--- CalendarServer/trunk/twext/web2/dav/method/proppatch.py	2012-05-22 19:19:49 UTC (rev 9263)
+++ CalendarServer/trunk/twext/web2/dav/method/proppatch.py	2012-05-22 19:23:22 UTC (rev 9264)
@@ -1,6 +1,6 @@
 # -*- test-case-name: twext.web2.dav.test.test_prop.PROP.test_PROPPATCH -*-
 ##
-# Copyright (c) 2005-2011 Apple Computer, Inc. All rights reserved.
+# Copyright (c) 2005-2012 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
@@ -84,6 +84,10 @@
     undoActions = []
     gotError = False
 
+    # Look for Prefer header
+    prefer = request.headers.getHeader("prefer", {})
+    returnMinimal = "return-minimal" in prefer
+
     try:
         #
         # Update properties
@@ -192,8 +196,11 @@
         responses.error()
 
     #
-    # Return response
+    # Return response - use 200 if Prefer:return-minimal set and no errors
     #
-    yield MultiStatusResponse([responses.response()])
+    if returnMinimal and not gotError:
+        yield responsecode.OK
+    else:
+        yield MultiStatusResponse([responses.response()])
 
 http_PROPPATCH = deferredGenerator(http_PROPPATCH)

Modified: CalendarServer/trunk/twext/web2/dav/resource.py
===================================================================
--- CalendarServer/trunk/twext/web2/dav/resource.py	2012-05-22 19:19:49 UTC (rev 9263)
+++ CalendarServer/trunk/twext/web2/dav/resource.py	2012-05-22 19:23:22 UTC (rev 9264)
@@ -2270,9 +2270,9 @@
             # we redirect such requests (as above) in the event that
             # this resource was created or modified by the request.
             #
-            if self.isCollection() and request.uri[-1:] != "/":
+            if self.isCollection() and request.path[-1:] != "/" and not response.headers.hasHeader("content-location"):
                 response.headers.setHeader(
-                    "content-location", request.uri + "/"
+                    "content-location", request.path + "/"
                 )
 
             return response

Modified: CalendarServer/trunk/twext/web2/http_headers.py
===================================================================
--- CalendarServer/trunk/twext/web2/http_headers.py	2012-05-22 19:19:49 UTC (rev 9263)
+++ CalendarServer/trunk/twext/web2/http_headers.py	2012-05-22 19:23:22 UTC (rev 9264)
@@ -1501,6 +1501,7 @@
     'If-Range':(parseIfRange,),
     'If-Unmodified-Since':(last,parseDateTime),
     'Max-Forwards':(last,int),
+    'Prefer':(tokenize, listParser(parseExpect), dict),     # Prefer like Expect
 #    'Proxy-Authorization':str, # what is "credentials"
     'Range':(tokenize, parseRange),
     'Referer':(last,str), # TODO: URI object?
@@ -1524,6 +1525,7 @@
     'If-Range':(generateIfRange, singleHeader),
     'If-Unmodified-Since':(generateDateTime,singleHeader),
     'Max-Forwards':(str, singleHeader),
+    'Prefer':(iteritems, listGenerator(generateExpect), singleHeader),      # Prefer like Expect
 #    'Proxy-Authorization':str, # what is "credentials"
     'Range':(generateRange,singleHeader),
     'Referer':(str,singleHeader),

Modified: CalendarServer/trunk/twistedcaldav/method/mkcol.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/method/mkcol.py	2012-05-22 19:19:49 UTC (rev 9263)
+++ CalendarServer/trunk/twistedcaldav/method/mkcol.py	2012-05-22 19:23:22 UTC (rev 9264)
@@ -111,6 +111,8 @@
 
     if doc is not None:
 
+        # Can ignore Prefer:return-minimal as we don't return a body for success by default
+
         # Parse response body
         mkcol = doc.root_element
         if not isinstance(mkcol, mkcolxml.MakeCollection):

Modified: CalendarServer/trunk/twistedcaldav/method/post.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/method/post.py	2012-05-22 19:19:49 UTC (rev 9263)
+++ CalendarServer/trunk/twistedcaldav/method/post.py	2012-05-22 19:23:22 UTC (rev 9264)
@@ -1,5 +1,5 @@
 ##
-# Copyright (c) 2005-2007 Apple Inc. All rights reserved.
+# Copyright (c) 2005-2012 Apple Inc. All rights reserved.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -117,6 +117,16 @@
             # May need to add a location header
             addLocation(request, request.unparseURL(path=newchildURL, params=""))
 
+            # Look for Prefer header
+            prefer = request.headers.getHeader("prefer", {})
+            returnRepresentation = "return-representation" in prefer
+
+            if returnRepresentation and result.code / 100 == 2:
+                result = (yield newchild.http_GET(request))
+                result.code = responsecode.CREATED
+                result.headers.removeHeader("content-location")
+                result.headers.setHeader("content-location", newchildURL)
+
             returnValue(result)
 
         except ValueError, e:
@@ -175,6 +185,16 @@
             # May need to add a location header
             addLocation(request, request.unparseURL(path=newchildURL, params=""))
 
+            # Look for Prefer header
+            prefer = request.headers.getHeader("prefer", {})
+            returnRepresentation = "return-representation" in prefer
+
+            if returnRepresentation and result.code / 100 == 2:
+                result = (yield newchild.http_GET(request))
+                result.code = responsecode.CREATED
+                result.headers.removeHeader("content-location")
+                result.headers.setHeader("content-location", newchildURL)
+
             returnValue(result)
 
         except ValueError, e:

Modified: CalendarServer/trunk/twistedcaldav/method/propfind.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/method/propfind.py	2012-05-22 19:19:49 UTC (rev 9263)
+++ CalendarServer/trunk/twistedcaldav/method/propfind.py	2012-05-22 19:23:22 UTC (rev 9264)
@@ -108,7 +108,12 @@
     if depth == "infinity":
         raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, davxml.PropfindFiniteDepth()))
 
-    brief = request.headers.getHeader("brief", False)
+    # Look for Prefer header first, then try Brief
+    prefer = request.headers.getHeader("prefer", {})
+    returnMinimal = "return-minimal" in prefer
+    noRoot = "depth-noroot" in prefer
+    if not returnMinimal:
+        returnMinimal = request.headers.getHeader("brief", False)
 
     xml_responses = []
 
@@ -122,7 +127,10 @@
     # the child resource loop and supply those to the checkPrivileges on each child.
     filtered_aces = (yield self.inheritedACEsforChildren(request))
 
-    resources = [(True, self, my_url)]
+    if depth in ("1", "infinity") and noRoot:
+        resources = []
+    else:
+        resources = [(True, self, my_url)]
 
     yield self.findChildrenFaster(
         depth,
@@ -171,14 +179,14 @@
                             status = statusForFailure(f, "getting property: %s" % (property,))
                             if status not in properties_by_status:
                                 properties_by_status[status] = []
-                            if not brief or status != responsecode.NOT_FOUND:
+                            if not returnMinimal or status != responsecode.NOT_FOUND:
                                 properties_by_status[status].append(propertyName(property))
                         else:
                             if resource_property is not None:
                                 properties_by_status[responsecode.OK].append(resource_property)
-                            elif not brief:
+                            elif not returnMinimal:
                                 properties_by_status[responsecode.NOT_FOUND].append(propertyName(property))
-                    elif not brief:
+                    elif not returnMinimal:
                         properties_by_status[responsecode.NOT_FOUND].append(propertyName(property))
 
             propstats = []

Modified: CalendarServer/trunk/twistedcaldav/method/put.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/method/put.py	2012-05-22 19:19:49 UTC (rev 9263)
+++ CalendarServer/trunk/twistedcaldav/method/put.py	2012-05-22 19:23:22 UTC (rev 9264)
@@ -1,5 +1,5 @@
 ##
-# Copyright (c) 2005-2009 Apple Inc. All rights reserved.
+# Copyright (c) 2005-2012 Apple Inc. All rights reserved.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -83,6 +83,18 @@
                 calendar = calendardata,
             )
             result = (yield storer.run())
+
+            # Look for Prefer header
+            prefer = request.headers.getHeader("prefer", {})
+            returnRepresentation = "return-representation" in prefer
+
+            if returnRepresentation and result.code / 100 == 2:
+                oldcode = result.code
+                result = (yield self.http_GET(request))
+                if oldcode == responsecode.CREATED:
+                    result.code =  responsecode.CREATED
+                result.headers.setHeader("content-location", request.path)
+
             returnValue(result)
 
         except ValueError, e:
@@ -127,6 +139,18 @@
                 destinationparent = parent,
             )
             result = (yield storer.run())
+
+            # Look for Prefer header
+            prefer = request.headers.getHeader("prefer", {})
+            returnRepresentation = "return-representation" in prefer
+
+            if returnRepresentation and result.code / 100 == 2:
+                oldcode = result.code
+                result = (yield self.http_GET(request))
+                if oldcode == responsecode.CREATED:
+                    result.code =  responsecode.CREATED
+                result.headers.setHeader("content-location", request.path)
+
             returnValue(result)
 
         except ValueError, e:

Modified: CalendarServer/trunk/twistedcaldav/method/report_common.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/method/report_common.py	2012-05-22 19:19:49 UTC (rev 9263)
+++ CalendarServer/trunk/twistedcaldav/method/report_common.py	2012-05-22 19:23:22 UTC (rev 9264)
@@ -333,7 +333,11 @@
         responsecode.NOT_FOUND : [],
     }
     
-    brief = request.headers.getHeader("brief", False)
+    # Look for Prefer header first, then try Brief
+    prefer = request.headers.getHeader("prefer", {})
+    returnMinimal = "return-minimal" in prefer
+    if not returnMinimal:
+        returnMinimal = request.headers.getHeader("brief", False)
 
     for property in props:
         if isinstance(property, caldavxml.CalendarData):
@@ -366,15 +370,15 @@
                 prop = (yield resource.readProperty(qname, request))
                 if prop is not None:
                     properties_by_status[responsecode.OK].append(prop)
-                elif not brief:
+                elif not returnMinimal:
                     properties_by_status[responsecode.NOT_FOUND].append(propertyName(qname))
             except HTTPError:
                 f = Failure()
                 status = statusForFailure(f, "getting property: %s" % (qname,))
                 if status not in properties_by_status: properties_by_status[status] = []
-                if not brief or status != responsecode.NOT_FOUND:
+                if not returnMinimal or status != responsecode.NOT_FOUND:
                     properties_by_status[status].append(propertyName(qname))
-        elif not brief:
+        elif not returnMinimal:
             properties_by_status[responsecode.NOT_FOUND].append(propertyName(qname))
     
     returnValue(properties_by_status)
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20120522/38de5b83/attachment-0001.html>


More information about the calendarserver-changes mailing list