[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