[CalendarServer-changes] [13319] CalendarServer/trunk
source_changes at macosforge.org
source_changes at macosforge.org
Fri Apr 18 08:01:49 PDT 2014
Revision: 13319
http://trac.calendarserver.org//changeset/13319
Author: cdaboo at apple.com
Date: 2014-04-18 08:01:49 -0700 (Fri, 18 Apr 2014)
Log Message:
-----------
Reinstate MaximumAttachmentSize limit.
Modified Paths:
--------------
CalendarServer/trunk/conf/caldavd-apple.plist
CalendarServer/trunk/conf/caldavd-test.plist
CalendarServer/trunk/conf/caldavd.plist
CalendarServer/trunk/twistedcaldav/stdconfig.py
CalendarServer/trunk/twistedcaldav/storebridge.py
CalendarServer/trunk/txdav/caldav/datastore/file.py
CalendarServer/trunk/txdav/caldav/datastore/sql.py
CalendarServer/trunk/txdav/caldav/datastore/test/test_attachments.py
CalendarServer/trunk/txdav/caldav/icalendarstore.py
Modified: CalendarServer/trunk/conf/caldavd-apple.plist
===================================================================
--- CalendarServer/trunk/conf/caldavd-apple.plist 2014-04-18 15:01:12 UTC (rev 13318)
+++ CalendarServer/trunk/conf/caldavd-apple.plist 2014-04-18 15:01:49 UTC (rev 13319)
@@ -167,8 +167,12 @@
<!-- User quota (in bytes) [0 = no quota] applies to attachments only -->
<key>UserQuota</key>
- <integer>104857600</integer><!-- 100Mb -->
+ <integer>104857600</integer> <!-- 100Mb -->
+ <!-- Maximum size for a single attachment (in bytes) [0 = no limit] -->
+ <key>MaximumAttachmentSize</key>
+ <integer>10485760</integer> <!-- 10Mb -->
+
<!-- Maximum number of calendars/address books allowed in a home -->
<!-- 0 for no limit -->
<key>MaxCollectionsPerHome</key>
Modified: CalendarServer/trunk/conf/caldavd-test.plist
===================================================================
--- CalendarServer/trunk/conf/caldavd-test.plist 2014-04-18 15:01:12 UTC (rev 13318)
+++ CalendarServer/trunk/conf/caldavd-test.plist 2014-04-18 15:01:49 UTC (rev 13319)
@@ -145,8 +145,12 @@
<!-- User quota (in bytes) [0 = no quota] applies to attachments only -->
<key>UserQuota</key>
- <integer>104857600</integer><!-- 100Mb -->
+ <integer>104857600</integer> <!-- 100Mb -->
+ <!-- Maximum size for a single attachment (in bytes) [0 = no limit] -->
+ <key>MaximumAttachmentSize</key>
+ <integer>10485760</integer> <!-- 10Mb -->
+
<!-- Maximum number of calendars/address books allowed in a home -->
<!-- 0 for no limit -->
<key>MaxCollectionsPerHome</key>
Modified: CalendarServer/trunk/conf/caldavd.plist
===================================================================
--- CalendarServer/trunk/conf/caldavd.plist 2014-04-18 15:01:12 UTC (rev 13318)
+++ CalendarServer/trunk/conf/caldavd.plist 2014-04-18 15:01:49 UTC (rev 13319)
@@ -126,6 +126,10 @@
<key>UserQuota</key>
<integer>104857600</integer> <!-- 100Mb -->
+ <!-- Maximum size for a single attachment (in bytes) [0 = no limit] -->
+ <key>MaximumAttachmentSize</key>
+ <integer>10485760</integer> <!-- 10Mb -->
+
<!-- Maximum number of calendars/address books allowed in a home -->
<!-- 0 for no limit -->
<key>MaxCollectionsPerHome</key>
Modified: CalendarServer/trunk/twistedcaldav/stdconfig.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/stdconfig.py 2014-04-18 15:01:12 UTC (rev 13318)
+++ CalendarServer/trunk/twistedcaldav/stdconfig.py 2014-04-18 15:01:49 UTC (rev 13319)
@@ -350,7 +350,8 @@
#
# Attachments
- "UserQuota": 104857600, # User attachment quota (in bytes)
+ "UserQuota": 104857600, # User attachment quota (in bytes - default 100MB)
+ "MaximumAttachmentSize": 10485760, # Maximum size for a single attachment (in bytes - default 10MB)
# Resource data
"MaxCollectionsPerHome": 50, # Maximum number of calendars/address books allowed in a home
Modified: CalendarServer/trunk/twistedcaldav/storebridge.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/storebridge.py 2014-04-18 15:01:12 UTC (rev 13318)
+++ CalendarServer/trunk/twistedcaldav/storebridge.py 2014-04-18 15:01:49 UTC (rev 13319)
@@ -60,7 +60,7 @@
InvalidPerUserDataMerge,
AttendeeAllowedError, ResourceDeletedError, InvalidAttachmentOperation,
ShareeAllowedError, DuplicatePrivateCommentsError, InvalidSplit
-)
+, AttachmentSizeTooLarge)
from txdav.carddav.iaddressbookstore import (
KindChangeNotAllowedError, GroupWithUnsharedAddressNotAllowedError
)
@@ -2123,6 +2123,11 @@
try:
yield t.loseConnection()
+ except AttachmentSizeTooLarge:
+ raise HTTPError(
+ ErrorResponse(FORBIDDEN,
+ (caldav_namespace, "max-attachment-size"))
+ )
except QuotaExceeded:
raise HTTPError(
ErrorResponse(INSUFFICIENT_STORAGE_SPACE,
@@ -3176,6 +3181,12 @@
"The action parameter in the request-URI is not valid",
))
+ except AttachmentSizeTooLarge:
+ raise HTTPError(
+ ErrorResponse(FORBIDDEN,
+ (caldav_namespace, "max-attachment-size"))
+ )
+
except QuotaExceeded:
raise HTTPError(ErrorResponse(
INSUFFICIENT_STORAGE_SPACE,
Modified: CalendarServer/trunk/txdav/caldav/datastore/file.py
===================================================================
--- CalendarServer/trunk/txdav/caldav/datastore/file.py 2014-04-18 15:01:12 UTC (rev 13318)
+++ CalendarServer/trunk/txdav/caldav/datastore/file.py 2014-04-18 15:01:49 UTC (rev 13319)
@@ -46,7 +46,7 @@
from twistedcaldav.config import config
from twistedcaldav.ical import InvalidICalendarDataError
-from txdav.caldav.icalendarstore import IAttachment
+from txdav.caldav.icalendarstore import IAttachment, AttachmentSizeTooLarge
from txdav.caldav.icalendarstore import ICalendar, ICalendarObject
from txdav.caldav.icalendarstore import ICalendarHome
@@ -803,6 +803,13 @@
newSize = self._file.tell()
# FIXME: do anything
self._file.close()
+
+ # Check max size for attachment
+ if newSize > config.MaximumAttachmentSize:
+ self._path.remove()
+ return fail(AttachmentSizeTooLarge())
+
+ # Check overall user quota
allowed = home.quotaAllowedBytes()
if allowed is not None and allowed < (home.quotaUsedBytes()
+ (newSize - oldSize)):
Modified: CalendarServer/trunk/txdav/caldav/datastore/sql.py
===================================================================
--- CalendarServer/trunk/txdav/caldav/datastore/sql.py 2014-04-18 15:01:12 UTC (rev 13318)
+++ CalendarServer/trunk/txdav/caldav/datastore/sql.py 2014-04-18 15:01:49 UTC (rev 13319)
@@ -77,7 +77,8 @@
ValidOrganizerError, ShareeAllowedError, ComponentRemoveState, \
InvalidDefaultCalendar, \
InvalidAttachmentOperation, DuplicatePrivateCommentsError, \
- TimeRangeUpperLimit, TimeRangeLowerLimit, InvalidSplit
+ TimeRangeUpperLimit, TimeRangeLowerLimit, InvalidSplit, \
+ AttachmentSizeTooLarge
from txdav.caldav.icalendarstore import QuotaExceeded
from txdav.common.datastore.sql import CommonHome, CommonHomeChild, \
CommonObjectResource, ECALENDARTYPE
@@ -4053,6 +4054,15 @@
oldSize = self._attachment.size()
newSize = self._file.tell()
self._file.close()
+
+ # Check max size for attachment
+ if newSize > config.MaximumAttachmentSize:
+ self._path.remove()
+ if self._creating:
+ yield self._attachment._internalRemove()
+ raise AttachmentSizeTooLarge()
+
+ # Check overall user quota
allowed = home.quotaAllowedBytes()
if allowed is not None and allowed < ((yield home.quotaUsedBytes())
+ (newSize - oldSize)):
Modified: CalendarServer/trunk/txdav/caldav/datastore/test/test_attachments.py
===================================================================
--- CalendarServer/trunk/txdav/caldav/datastore/test/test_attachments.py 2014-04-18 15:01:12 UTC (rev 13318)
+++ CalendarServer/trunk/txdav/caldav/datastore/test/test_attachments.py 2014-04-18 15:01:49 UTC (rev 13319)
@@ -36,7 +36,7 @@
from txdav.caldav.datastore.test.common import CaptureProtocol
from txdav.caldav.datastore.test.util import buildCalendarStore
from txdav.caldav.icalendarstore import IAttachmentStorageTransport, IAttachment, \
- QuotaExceeded
+ QuotaExceeded, AttachmentSizeTooLarge
from txdav.common.datastore.sql_tables import schema
from txdav.common.datastore.test.util import CommonCommonTests, \
populateCalendarsFrom, deriveQuota, withSpecialQuota
@@ -523,6 +523,77 @@
yield checkOriginal()
+ @inlineCallbacks
+ def exceedSizeTest(self, getit):
+ """
+ If too many bytes are passed to the transport returned by
+ L{ICalendarObject.createAttachmentWithName},
+ L{IAttachmentStorageTransport.loseConnection} will return a L{Deferred}
+ that fails with L{AttachmentSizeTooLarge}.
+ """
+ attachment = yield getit()
+ t = attachment.store(MimeType("text", "x-fixture"), "")
+ sample = "all work and no play makes jack a dull boy"
+ chunk = (sample * (config.MaximumAttachmentSize / len(sample)))
+
+ t.write(chunk)
+ t.writeSequence([chunk, chunk])
+
+ d = t.loseConnection()
+ yield self.failUnlessFailure(d, AttachmentSizeTooLarge)
+
+
+ @inlineCallbacks
+ def test_exceedSizeNew(self):
+ """
+ When size is exceeded on a new attachment, that attachment will no
+ longer exist.
+ """
+
+ self.patch(config, "MaximumAttachmentSize", 100)
+ obj = yield self.calendarObjectUnderTest()
+ yield self.exceedSizeTest(
+ lambda: obj.createAttachmentWithName("too-big.attachment")
+ )
+ self.assertEquals((yield obj.attachments()), [])
+ yield self.commit()
+ obj = yield self.calendarObjectUnderTest()
+ self.assertEquals((yield obj.attachments()), [])
+
+
+ @inlineCallbacks
+ def test_exceedSizeReplace(self):
+ """
+ When size is exceeded while replacing an attachment, that attachment's
+ contents will not be replaced.
+ """
+ self.patch(config, "MaximumAttachmentSize", 100)
+ obj = yield self.calendarObjectUnderTest()
+ create = lambda: obj.createAttachmentWithName("exists.attachment")
+ get = lambda: obj.attachmentWithName("exists.attachment")
+ attachment = yield create()
+ t = attachment.store(MimeType("text", "x-fixture"), "")
+ sampleData = "a reasonably sized attachment"
+ t.write(sampleData)
+ yield t.loseConnection()
+ yield self.exceedSizeTest(get)
+ @inlineCallbacks
+ def checkOriginal():
+ actual = yield self.attachmentToString(attachment)
+ expected = sampleData
+ # note: 60 is less than len(expected); trimming is just to make
+ # the error message look sane when the test fails.
+ actual = actual[:60]
+ self.assertEquals(actual, expected)
+ yield checkOriginal()
+ yield self.commit()
+ # Make sure that things go back to normal after a commit of that
+ # transaction.
+ obj = yield self.calendarObjectUnderTest()
+ attachment = yield get()
+ yield checkOriginal()
+
+
def test_removeAttachmentWithName(self, refresh=lambda x: x):
"""
L{ICalendarObject.removeAttachmentWithName} will remove the calendar
@@ -1061,6 +1132,76 @@
yield checkOriginal()
+ @inlineCallbacks
+ def exceedSizeTest(self, getit):
+ """
+ If too many bytes are passed to the transport returned by
+ L{ICalendarObject.createAttachmentWithName},
+ L{IAttachmentStorageTransport.loseConnection} will return a L{Deferred}
+ that fails with L{AttachmentSizeTooLarge}.
+ """
+ attachment = yield getit()
+ t = attachment.store(MimeType("text", "x-fixture"), "")
+ sample = "all work and no play makes jack a dull boy"
+ chunk = (sample * (config.MaximumAttachmentSize / len(sample)))
+
+ t.write(chunk)
+ t.writeSequence([chunk, chunk])
+
+ d = t.loseConnection()
+ yield self.failUnlessFailure(d, AttachmentSizeTooLarge)
+
+
+ @inlineCallbacks
+ def test_exceedSizeNew(self):
+ """
+ When size is exceeded on a new attachment, that attachment will no
+ longer exist.
+ """
+ self.patch(config, "MaximumAttachmentSize", 100)
+ obj = yield self.calendarObjectUnderTest()
+ yield self.exceedSizeTest(
+ lambda: obj.createAttachmentWithName("too-big.attachment")
+ )
+ self.assertEquals((yield obj.attachments()), [])
+ yield self.commit()
+ obj = yield self.calendarObjectUnderTest()
+ self.assertEquals((yield obj.attachments()), [])
+
+
+ @inlineCallbacks
+ def test_exceedSizeReplace(self):
+ """
+ When size is exceeded while replacing an attachment, that attachment's
+ contents will not be replaced.
+ """
+ self.patch(config, "MaximumAttachmentSize", 100)
+ obj = yield self.calendarObjectUnderTest()
+ create = lambda: obj.createAttachmentWithName("exists.attachment")
+ get = lambda: obj.attachmentWithName("exists.attachment")
+ attachment = yield create()
+ t = attachment.store(MimeType("text", "x-fixture"), "")
+ sampleData = "a reasonably sized attachment"
+ t.write(sampleData)
+ yield t.loseConnection()
+ yield self.exceedSizeTest(get)
+ @inlineCallbacks
+ def checkOriginal():
+ actual = yield self.attachmentToString(attachment)
+ expected = sampleData
+ # note: 60 is less than len(expected); trimming is just to make
+ # the error message look sane when the test fails.
+ actual = actual[:60]
+ self.assertEquals(actual, expected)
+ yield checkOriginal()
+ yield self.commit()
+ # Make sure that things go back to normal after a commit of that
+ # transaction.
+ obj = yield self.calendarObjectUnderTest()
+ attachment = yield get()
+ yield checkOriginal()
+
+
def test_removeManagedAttachmentWithID(self, refresh=lambda x: x):
"""
L{ICalendarObject.removeManagedAttachmentWithID} will remove the calendar
Modified: CalendarServer/trunk/txdav/caldav/icalendarstore.py
===================================================================
--- CalendarServer/trunk/txdav/caldav/icalendarstore.py 2014-04-18 15:01:12 UTC (rev 13318)
+++ CalendarServer/trunk/txdav/caldav/icalendarstore.py 2014-04-18 15:01:49 UTC (rev 13319)
@@ -775,6 +775,13 @@
+class AttachmentSizeTooLarge(Exception):
+ """
+ Unable to store an attachment because it is too large.
+ """
+
+
+
class AttachmentStoreValidManagedID(Exception):
"""
Specified attachment managed-id is not valid.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20140418/0f644fd1/attachment-0001.html>
More information about the calendarserver-changes
mailing list