[CalendarServer-changes] [5754] CalendarServer/branches/new-store/twistedcaldav/method/put_common.py

source_changes at macosforge.org source_changes at macosforge.org
Wed Jun 16 09:35:59 PDT 2010


Revision: 5754
          http://trac.macosforge.org/projects/calendarserver/changeset/5754
Author:   glyph at apple.com
Date:     2010-06-16 09:35:58 -0700 (Wed, 16 Jun 2010)
Log Message:
-----------
restore UID conflict checking logic; no idea what I thought I was doing when I removed it

Modified Paths:
--------------
    CalendarServer/branches/new-store/twistedcaldav/method/put_common.py

Modified: CalendarServer/branches/new-store/twistedcaldav/method/put_common.py
===================================================================
--- CalendarServer/branches/new-store/twistedcaldav/method/put_common.py	2010-06-16 16:35:17 UTC (rev 5753)
+++ CalendarServer/branches/new-store/twistedcaldav/method/put_common.py	2010-06-16 16:35:58 UTC (rev 5754)
@@ -29,6 +29,7 @@
 from twisted.internet.defer import returnValue
 from twisted.python.failure import Failure
 
+from twext.web2.dav.util import joinURL, parentForURL
 from twext.web2 import responsecode
 from twext.web2.dav import davxml
 from twext.web2.dav.element.base import dav_namespace
@@ -46,7 +47,7 @@
 from twext.web2.dav.http import ErrorResponse
 
 from twistedcaldav.config import config
-from twistedcaldav.caldavxml import ScheduleTag
+from twistedcaldav.caldavxml import ScheduleTag, NoUIDConflict
 from twistedcaldav.caldavxml import NumberOfRecurrencesWithinLimits
 from twistedcaldav.caldavxml import caldav_namespace, MaxAttendeesPerInstance
 from twistedcaldav.customxml import calendarserver_namespace ,\
@@ -576,6 +577,50 @@
         
         returnValue(new_has_private_comments)
 
+
+    def noUIDConflict(self, uid): 
+        """ 
+        Check that the UID of the new calendar object conforms to the requirements of 
+        CalDAV, i.e. it must be unique in the collection and we must not overwrite a 
+        different UID. 
+        @param uid: the UID for the resource being stored. 
+        @return: tuple: (True/False if the UID is valid, log message string, 
+            name of conflicted resource). 
+        """ 
+        
+        result = True 
+        message = "" 
+        rname = "" 
+        
+        # Adjust for a move into same calendar collection 
+        oldname = None 
+        if self.sourceparent and (self.sourceparent.fp.path == self.destinationparent.fp.path) and self.deletesource: 
+            oldname = self.source.fp.basename() 
+        
+        # UID must be unique 
+        index = self.destinationparent.index() 
+        if not index.isAllowedUID(uid, oldname, self.destination.fp.basename()): 
+            rname = index.resourceNameForUID(uid) 
+            # This can happen if two simultaneous PUTs occur with the same UID. 
+            # i.e. one PUT has reserved the UID but has not yet written the resource, 
+            # the other PUT tries to reserve and fails but no index entry exists yet. 
+            if rname is None: 
+                rname = "<<Unknown Resource>>" 
+            result = False 
+            message = "Calendar resource %s already exists with same UID %s" % (rname, uid) 
+        else: 
+            # Cannot overwrite a resource with different UID 
+            if self.destination.fp.exists(): 
+                olduid = index.resourceUIDForName(self.destination.fp.basename()) 
+                if olduid != uid: 
+                    rname = self.destination.fp.basename() 
+                    result = False 
+                    message = "Cannot overwrite calendar resource %s with different UID %s" % (rname, olduid) 
+         
+        return result, message, rname 
+
+
+
     @inlineCallbacks
     def doImplicitScheduling(self):
 
@@ -814,12 +859,25 @@
             yield self.fullValidation()
 
             # Reservation and UID conflict checking is next.
-            if self.destinationcal:    
+            if self.destinationcal:
                 # Reserve UID
                 self.destination_index = self.destinationparent.index()
-                reservation = StoreCalendarObjectResource.UIDReservation(self.destination_index, self.uid, self.destination_uri, self.internal_request or self.isiTIP)
+                reservation = StoreCalendarObjectResource.UIDReservation(
+                    self.destination_index, self.uid, self.destination_uri,
+                    self.internal_request or self.isiTIP
+                )
                 yield reservation.reserve()
+                # UID conflict check - note we do this after reserving the UID to avoid a race condition where two requests 
+                # try to write the same calendar data to two different resource URIs. 
+                if not self.isiTIP: 
+                    result, message, rname = self.noUIDConflict(self.uid) 
+                    if not result: 
+                        log.err(message) 
+                        raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, 
+                            NoUIDConflict(davxml.HRef.fromString(joinURL(parentForURL(self.destination_uri), rname.encode("utf-8")))) 
+                        ))
 
+
             # Get current quota state.
             yield self.checkQuota()
     
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20100616/c9d8f122/attachment.html>


More information about the calendarserver-changes mailing list