[CalendarServer-changes] [5481] CalendarServer/trunk/twistedcaldav/method

source_changes at macosforge.org source_changes at macosforge.org
Thu Apr 15 13:58:42 PDT 2010


Revision: 5481
          http://trac.macosforge.org/projects/calendarserver/changeset/5481
Author:   cdaboo at apple.com
Date:     2010-04-15 13:58:40 -0700 (Thu, 15 Apr 2010)
Log Message:
-----------
CardDAV specific clean-up.

Modified Paths:
--------------
    CalendarServer/trunk/twistedcaldav/method/put.py
    CalendarServer/trunk/twistedcaldav/method/put_addressbook_common.py
    CalendarServer/trunk/twistedcaldav/method/report_addressbook_multiget.py
    CalendarServer/trunk/twistedcaldav/method/report_addressbook_query.py

Modified: CalendarServer/trunk/twistedcaldav/method/put.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/method/put.py	2010-04-15 19:05:29 UTC (rev 5480)
+++ CalendarServer/trunk/twistedcaldav/method/put.py	2010-04-15 20:58:40 UTC (rev 5481)
@@ -93,11 +93,14 @@
         # Read the vcard component from the stream
         try:
             vcarddata = (yield allDataFromStream(request.stream))
+            if not hasattr(request, "extendedLogItems"):
+                request.extendedLogItems = {}
+            request.extendedLogItems["cl"] = str(len(vcarddata)) if vcarddata else "0"
 
             # We must have some data at this point
             if vcarddata is None:
                 # Use correct DAV:error response
-                raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (carddav_namespace, "valid-address-data")))
+                raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (carddav_namespace, "valid-address-data"), description="No vcard data"))
 
             storer = StoreAddressObjectResource(
                 request = request,

Modified: CalendarServer/trunk/twistedcaldav/method/put_addressbook_common.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/method/put_addressbook_common.py	2010-04-15 19:05:29 UTC (rev 5480)
+++ CalendarServer/trunk/twistedcaldav/method/put_addressbook_common.py	2010-04-15 20:58:40 UTC (rev 5481)
@@ -20,17 +20,17 @@
 
 __all__ = ["StoreAddressObjectResource"]
 
+import os
 import types
 
 from twisted.internet import reactor
 from twisted.internet.defer import Deferred, inlineCallbacks, succeed
-from twisted.internet.defer import maybeDeferred, returnValue
+from twisted.internet.defer import returnValue
 from twisted.python import failure
 from twext.python.filepath import CachingFilePath as FilePath
 from twext.web2 import responsecode
 from twext.web2.dav import davxml
 from twext.web2.dav.element.base import dav_namespace
-from twext.web2.dav.element.base import PCDATAElement
 from twext.web2.dav.fileop import delete
 from twext.web2.dav.http import ErrorResponse
 from twext.web2.dav.resource import TwistedGETContentMD5
@@ -38,16 +38,13 @@
 from twext.web2.dav.util import joinURL, parentForURL
 from twext.web2.http import HTTPError
 from twext.web2.http import StatusResponse
-from twext.web2.iweb import IResponse
 from twext.web2.stream import MemoryStream
 
 from twistedcaldav.config import config
-from twistedcaldav.caldavxml import NumberOfRecurrencesWithinLimits
 from twistedcaldav.carddavxml import NoUIDConflict, carddav_namespace
 from twistedcaldav.fileops import copyToWithXAttrs
 from twistedcaldav.fileops import putWithXAttrs
 from twistedcaldav.fileops import copyWithXAttrs
-from twistedcaldav.instance import TooManyInstancesError
 from twistedcaldav.vcard import Component
 from twistedcaldav.vcardindex import ReservationError
 from twext.python.log import Logger
@@ -268,7 +265,7 @@
                         raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (carddav_namespace, "valid-address-data")))
                         
                 # Valid vcard data for CalDAV check
-                result, message = self.validCardDAVDataCheck()
+                result, message = self.validAddressDataCheck()
                 if not result:
                     log.err(message)
                     raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (carddav_namespace, "valid-addressbook-object-resource")))
@@ -323,7 +320,7 @@
 
         return result, message
         
-    def validCardDAVDataCheck(self):
+    def validAddressDataCheck(self):
         """
         Check that the vcard data is valid vCard.
         @return:         tuple: (True/False if the vcard data is valid,
@@ -343,22 +340,6 @@
         
         return result, message
     
-    def validCalDAVDataCheck(self):
-        """
-        Check that the vcard data is valid as a CalDAV vcard object resource.
-        @return:         tuple: (True/False if the vcard data is valid,
-                                 log message string).
-        """
-        result = True
-        message = ""
-        try:
-            self.vcard.validateForCardDAV()
-        except ValueError, e:
-            result = False
-            message = "Calendar data does not conform to CalDAV requirements: %s" % (e,)
-        
-        return result, message
-    
     def validSizeCheck(self):
         """
         Make sure that the content-type of the source resource is text/vcard.
@@ -451,11 +432,15 @@
         so rename the original file in case we need to rollback.
         """
 
+        def _createRollbackPath(path):
+            parent, child = os.path.split(path)
+            child = "." + child + ".rollback"
+            return os.path.join(parent, child)
+
         self.rollback = StoreAddressObjectResource.RollbackState(self)
         self.overwrite = self.destination.exists()
         if self.overwrite:
-            self.rollback.destination_copy = FilePath(self.destination.fp.path)
-            self.rollback.destination_copy.path += ".rollback"
+            self.rollback.destination_copy = FilePath(_createRollbackPath(self.destination.fp.path))
             copyToWithXAttrs(self.destination.fp, self.rollback.destination_copy)
             log.debug("Rollback: backing up destination %s to %s" % (self.destination.fp.path, self.rollback.destination_copy.path))
         else:
@@ -463,8 +448,7 @@
             log.debug("Rollback: will create new destination %s" % (self.destination.fp.path,))
 
         if self.deletesource:
-            self.rollback.source_copy = FilePath(self.source.fp.path)
-            self.rollback.source_copy.path += ".rollback"
+            self.rollback.source_copy = FilePath(_createRollbackPath(self.source.fp.path))
             copyToWithXAttrs(self.source.fp, self.rollback.source_copy)
             log.debug("Rollback: backing up source %s to %s" % (self.source.fp.path, self.rollback.source_copy.path))
 
@@ -472,27 +456,19 @@
     def doStore(self):
         # Do put or copy based on whether source exists
         if self.source is not None:
-            response = maybeDeferred(copyWithXAttrs, self.source.fp, self.destination.fp, self.destination_uri)
+            response = (yield copyWithXAttrs(self.source.fp, self.destination.fp, self.destination_uri))
         else:
             if self.vcarddata is None:
                 self.vcarddata = str(self.vcard)
             md5 = MD5StreamWrapper(MemoryStream(self.vcarddata))
-            response = maybeDeferred(putWithXAttrs, md5, self.destination.fp)
-        response = (yield response)
-
-        # Update the MD5 value on the resource
-        if self.source is not None:
-            # Copy MD5 value from source to destination
-            if self.source.hasDeadProperty(TwistedGETContentMD5):
-                md5 = self.source.readDeadProperty(TwistedGETContentMD5)
-                self.destination.writeDeadProperty(md5)
-        else:
+            response = (yield putWithXAttrs(md5, self.destination.fp))
+    
             # Finish MD5 calculation and write dead property
             md5.close()
             md5 = md5.getMD5()
             self.destination.writeDeadProperty(TwistedGETContentMD5.fromString(md5))
     
-        returnValue(IResponse(response))
+        returnValue(response)
 
     @inlineCallbacks
     def doSourceDelete(self):
@@ -542,17 +518,8 @@
         """
         
         # Add or update the index for this resource.
-        try:
-            self.source_index.addResource(self.source.fp.basename(), self.vcard, self.newrevision)
-        except TooManyInstancesError, ex:
-            raise HTTPError(ErrorResponse(
-                responsecode.FORBIDDEN,
-                    NumberOfRecurrencesWithinLimits(PCDATAElement(str(ex.max_allowed)))
-                ))
+        self.source_index.addResource(self.source.fp.basename(), self.vcard, self.newrevision)
 
-            self.source.writeDeadProperty(davxml.GETContentType.fromString("text/vcard"))
-            return None
-
     def doDestinationIndex(self, vcardtoindex):
         """
         Do destination resource indexing, replacing any index previous stored.
@@ -569,8 +536,9 @@
             self.destination_index.addResource(self.destination.fp.basename(), vcardtoindex, self.newrevision)
             log.debug("Destination indexed %s" % (self.destination.fp.path,))
         except (ValueError, TypeError), ex:
-            log.err("Cannot index vcard resource: %s" % (ex,))
-            raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (carddav_namespace, "valid-address-data")))
+            msg = "Cannot index vcard resource: %s" % (ex,)
+            log.err(msg)
+            raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (carddav_namespace, "valid-address-data"), description=msg))
 
         self.destination.writeDeadProperty(davxml.GETContentType.fromString("text/vcard"))
         return None

Modified: CalendarServer/trunk/twistedcaldav/method/report_addressbook_multiget.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/method/report_addressbook_multiget.py	2010-04-15 19:05:29 UTC (rev 5480)
+++ CalendarServer/trunk/twistedcaldav/method/report_addressbook_multiget.py	2010-04-15 20:58:40 UTC (rev 5481)
@@ -20,7 +20,6 @@
 
 __all__ = ["report_urn_ietf_params_xml_ns_carddav_addressbook_multiget"]
 
-import time
 from urllib import unquote
 
 from twisted.internet.defer import inlineCallbacks, returnValue
@@ -41,6 +40,7 @@
 
 log = Logger()
 
+max_number_of_addressbook_multigets = 5000
 
 @inlineCallbacks
 def report_urn_ietf_params_xml_ns_carddav_addressbook_multiget(self, request, multiget):
@@ -49,8 +49,6 @@
     (CardDAV, section 8.7)
     """
 
-    startTime = time.time()
-
     # Verify root element
     if multiget.qname() != (carddav_namespace, "addressbook-multiget"):
         raise ValueError("{CardDAV:}addressbook-multiget expected as root element, not %s." % (multiget.sname(),))
@@ -67,6 +65,15 @@
     propertyreq = multiget.property
     resources  = multiget.resources
     
+    if not hasattr(request, "extendedLogItems"):
+        request.extendedLogItems = {}
+    request.extendedLogItems["rcount"] = len(resources)
+    
+    # Check size of results is within limit
+    if len(resources) > max_number_of_addressbook_multigets:
+        log.err("Too many results in multiget report: %d" % len(resources))
+        raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, davxml.NumberOfMatchesWithinLimits()))
+
     if propertyreq.qname() == ("DAV:", "allprop"):
         propertiesForResource = report_common.allPropertiesForResource
 
@@ -227,11 +234,23 @@
         
                     # Get properties for all valid readable resources
                     for resource, href in ok_resources:
-                        yield report_common.responseForHrefAB(request, responses, davxml.HRef.fromString(href), resource, propertiesForResource, propertyreq)
-                                
-                    # Indicate error for all valid non-readable resources
-                    for ignore_resource, href in bad_resources: #@UnusedVariable
-                        responses.append(davxml.StatusResponse(davxml.HRef.fromString(href), davxml.Status.fromResponseCode(responsecode.FORBIDDEN)))
+                        try:
+                            yield report_common.responseForHrefAB(request, responses, davxml.HRef.fromString(href), resource, propertiesForResource, propertyreq)
+                        except ValueError:
+                            log.err("Invalid address resource during multiget: %s" % (href,))
+                            responses.append(davxml.StatusResponse(davxml.HRef.fromString(href), davxml.Status.fromResponseCode(responsecode.FORBIDDEN)))
+                        except IOError:
+                            # This can happen because of a race-condition between the
+                            # time we determine which resources exist and the deletion
+                            # of one of these resources in another request.  In this
+                            # case, return a 404 for the now missing resource rather
+                            # than raise an error for the entire report.
+                            log.err("Missing calendar resource during multiget: %s" % (href,))
+                            responses.append(davxml.StatusResponse(davxml.HRef.fromString(href), davxml.Status.fromResponseCode(responsecode.NOT_FOUND)))
+                                        
+                            # Indicate error for all valid non-readable resources
+                            for ignore_resource, href in bad_resources: #@UnusedVariable
+                                responses.append(davxml.StatusResponse(davxml.HRef.fromString(href), davxml.Status.fromResponseCode(responsecode.FORBIDDEN)))
             
             finally:
                 if directoryAddressBookLock:
@@ -309,10 +328,4 @@
         
                 yield report_common.responseForHrefAB(request, responses, href, child, propertiesForResource, propertyreq)
 
-    retValue = MultiStatusResponse(responses)
-    
-    elaspedTime = time.time() - startTime
-    self.log_info("Timing: CARDDAV:addressbook-multiget Report total: %.1f ms" % (elaspedTime*1000,))
-
-    returnValue(retValue)
-
+    returnValue(MultiStatusResponse(responses))

Modified: CalendarServer/trunk/twistedcaldav/method/report_addressbook_query.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/method/report_addressbook_query.py	2010-04-15 19:05:29 UTC (rev 5480)
+++ CalendarServer/trunk/twistedcaldav/method/report_addressbook_query.py	2010-04-15 20:58:40 UTC (rev 5481)
@@ -21,7 +21,6 @@
 __all__ = ["report_urn_ietf_params_xml_ns_carddav_addressbook_query"]
 
 import urllib
-import time
 
 from twisted.internet.defer import succeed, inlineCallbacks, returnValue, maybeDeferred
 
@@ -40,16 +39,12 @@
 
 log = Logger()
 
-
 @inlineCallbacks
 def report_urn_ietf_params_xml_ns_carddav_addressbook_query(self, request, addressbook_query):
     """
     Generate an addressbook-query REPORT.
     (CardDAV, section 8.6)
     """
-    startTime = time.time()
-    #print("Timing: report_urn_ietf_params_xml_ns_carddav_addressbook_query.starttime=%f" % startTime)
-    
     # Verify root element
     if addressbook_query.qname() != (carddav_namespace, "addressbook-query"):
         raise ValueError("{CardDAV:}addressbook-query expected as root element, not %s." % (addressbook_query.sname(),))
@@ -161,8 +156,6 @@
         directoryAddressBookLock = None
         try:                
 
-        #self.maxDSQueryRecords and len(queryResults) >= self.maxDSQueryRecords
- 
             if addrresource.isDirectoryBackedAddressBookCollection() and addrresource.directory.cacheQuery:
                 
                 directory = addrresource.directory
@@ -290,10 +283,9 @@
                         #davxml.ResponseDescription("Results limited by %s at %d" % resultsWereLimited),
                         davxml.ResponseDescription("Results limited to %d items" % e.maxLimit()),
                     ))
-           
-    retValue = MultiStatusResponse(responses)
     
-    elaspedTime = time.time() - startTime
-    self.log_info("Timing: CARDDAV:addressbook-query Report total: %.1f ms" % (elaspedTime*1000,))
+    if not hasattr(request, "extendedLogItems"):
+        request.extendedLogItems = {}
+    request.extendedLogItems["responses"] = len(responses)
 
-    returnValue(retValue)
+    returnValue(MultiStatusResponse(responses))
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20100415/d6555d3a/attachment-0001.html>


More information about the calendarserver-changes mailing list