Revision: 9264 http://trac.macosforge.org/projects/calendarserver/changeset/9264 Author: cdaboo@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)
participants (1)
-
source_changes@macosforge.org