[CalendarServer-changes] [143] CalendarServer/branches/users/cdaboo/quota

source_changes at macosforge.org source_changes at macosforge.org
Mon Sep 18 08:32:01 PDT 2006


Revision: 143
Author:   cdaboo at apple.com
Date:     2006-09-18 08:31:58 -0700 (Mon, 18 Sep 2006)

Log Message:
-----------
merge -r136:HEAD https://svn.opensource.apple.com/repository/calendarserver/CalendarServer/trunk .

Modified Paths:
--------------
    CalendarServer/branches/users/cdaboo/quota/run

Removed Paths:
-------------
    CalendarServer/branches/users/cdaboo/quota/lib-patches/Twisted/twisted.web2.auth.basic.patch
    CalendarServer/branches/users/cdaboo/quota/lib-patches/Twisted/twisted.web2.auth.digest.patch
    CalendarServer/branches/users/cdaboo/quota/lib-patches/Twisted/twisted.web2.auth.interfaces.patch
    CalendarServer/branches/users/cdaboo/quota/lib-patches/Twisted/twisted.web2.auth.wrapper.patch
    CalendarServer/branches/users/cdaboo/quota/lib-patches/Twisted/twisted.web2.dav.resource.patch
    CalendarServer/branches/users/cdaboo/quota/lib-patches/Twisted/twisted.web2.dav.static.patch
    CalendarServer/branches/users/cdaboo/quota/lib-patches/Twisted/twisted.web2.test.test_httpauth.patch

Deleted: CalendarServer/branches/users/cdaboo/quota/lib-patches/Twisted/twisted.web2.auth.basic.patch
===================================================================
--- CalendarServer/branches/users/cdaboo/quota/lib-patches/Twisted/twisted.web2.auth.basic.patch	2006-09-15 23:08:28 UTC (rev 142)
+++ CalendarServer/branches/users/cdaboo/quota/lib-patches/Twisted/twisted.web2.auth.basic.patch	2006-09-18 15:31:58 UTC (rev 143)
@@ -1,13 +0,0 @@
-Index: twisted/web2/auth/basic.py
-===================================================================
---- twisted/web2/auth/basic.py	(revision 18157)
-+++ twisted/web2/auth/basic.py	(working copy)
-@@ -20,7 +20,7 @@
-     def getChallenge(self, peer):
-         return {'realm': self.realm}
- 
--    def decode(self, response, method=None):
-+    def decode(self, response, request):
-         try:
-             creds = (response + '===').decode('base64')
-         except:

Deleted: CalendarServer/branches/users/cdaboo/quota/lib-patches/Twisted/twisted.web2.auth.digest.patch
===================================================================
--- CalendarServer/branches/users/cdaboo/quota/lib-patches/Twisted/twisted.web2.auth.digest.patch	2006-09-15 23:08:28 UTC (rev 142)
+++ CalendarServer/branches/users/cdaboo/quota/lib-patches/Twisted/twisted.web2.auth.digest.patch	2006-09-18 15:31:58 UTC (rev 143)
@@ -1,19 +0,0 @@
-Index: twisted/web2/auth/digest.py
-===================================================================
---- twisted/web2/auth/digest.py	(revision 18157)
-+++ twisted/web2/auth/digest.py	(working copy)
-@@ -154,7 +154,7 @@
-                 'algorithm': self.algorithm,
-                 'realm': self.realm}
- 
--    def decode(self, response, method='GET'):
-+    def decode(self, response, request):
-         def unq(s):
-             if s[0] == s[-1] == '"':
-                 return s[1:-1]
-@@ -172,4 +172,4 @@
- 
-         del self.outstanding[auth['opaque']]
-             
--        return DigestedCredentials(username, method, self.realm, auth)
-+        return DigestedCredentials(username, request.method, self.realm, auth)

Deleted: CalendarServer/branches/users/cdaboo/quota/lib-patches/Twisted/twisted.web2.auth.interfaces.patch
===================================================================
--- CalendarServer/branches/users/cdaboo/quota/lib-patches/Twisted/twisted.web2.auth.interfaces.patch	2006-09-15 23:08:28 UTC (rev 142)
+++ CalendarServer/branches/users/cdaboo/quota/lib-patches/Twisted/twisted.web2.auth.interfaces.patch	2006-09-18 15:31:58 UTC (rev 143)
@@ -1,24 +0,0 @@
-Index: twisted/web2/auth/interfaces.py
-===================================================================
---- twisted/web2/auth/interfaces.py	(revision 18157)
-+++ twisted/web2/auth/interfaces.py	(working copy)
-@@ -13,7 +13,7 @@
-         @return: dictionary of challenge arguments
-         """
- 
--    def decode(response, method=None):
-+    def decode(response, request):
-         """Create a credentials object from the given response.
-         May raise twisted.cred.error.LoginFailed if the response is invalid.
-     
-@@ -20,8 +20,8 @@
-         @type response: C{str}
-         @param response: scheme specific response string
- 
--        @type method: C{str}
--        @param method: the method by which this response was sent
-+        @type request: L{twisted.web2.server.Request}
-+        @param request: the request being processed
- 
-         @return: ICredentials
-         """

Deleted: CalendarServer/branches/users/cdaboo/quota/lib-patches/Twisted/twisted.web2.auth.wrapper.patch
===================================================================
--- CalendarServer/branches/users/cdaboo/quota/lib-patches/Twisted/twisted.web2.auth.wrapper.patch	2006-09-15 23:08:28 UTC (rev 142)
+++ CalendarServer/branches/users/cdaboo/quota/lib-patches/Twisted/twisted.web2.auth.wrapper.patch	2006-09-18 15:31:58 UTC (rev 143)
@@ -1,13 +0,0 @@
-Index: twisted/web2/auth/wrapper.py
-===================================================================
---- twisted/web2/auth/wrapper.py	(revision 18157)
-+++ twisted/web2/auth/wrapper.py	(working copy)
-@@ -87,7 +87,7 @@
-             return UnauthorizedResource(self.credentialFactories)
- 
-         try:
--            creds = factory.decode(response, req.method)
-+            creds = factory.decode(response, req)
-         except error.LoginFailed:
-             return UnauthorizedResource(self.credentialFactories)
- 

Deleted: CalendarServer/branches/users/cdaboo/quota/lib-patches/Twisted/twisted.web2.dav.resource.patch
===================================================================
--- CalendarServer/branches/users/cdaboo/quota/lib-patches/Twisted/twisted.web2.dav.resource.patch	2006-09-15 23:08:28 UTC (rev 142)
+++ CalendarServer/branches/users/cdaboo/quota/lib-patches/Twisted/twisted.web2.dav.resource.patch	2006-09-18 15:31:58 UTC (rev 143)
@@ -1,304 +0,0 @@
-Index: twisted/web2/dav/resource.py
-===================================================================
---- twisted/web2/dav/resource.py	(revision 18157)
-+++ twisted/web2/dav/resource.py	(working copy)
-@@ -126,6 +126,8 @@
-         (dav_namespace, "acl-restrictions"          ), # RFC 3744, section 5.6
-         (dav_namespace, "inherited-acl-set"         ), # RFC 3744, section 5.7
-         (dav_namespace, "principal-collection-set"  ), # RFC 3744, section 5.8
-+        (dav_namespace, "quota-available-bytes"     ), # RFC 4331, section 3
-+        (dav_namespace, "quota-used-bytes"          ), # RFC 4331, section 4
- 
-         (twisted_dav_namespace, "resource-class"),
-     )
-@@ -264,6 +266,32 @@
-                         # TODO: Merge change from original patch
-                         lambda: self.safeAccessControlList(request)
-                     )
-+                    
-+                if name == "quota-available-bytes":
-+                    def callback(qvalue):
-+                        if qvalue is None:
-+                            raise HTTPError(StatusResponse(
-+                                responsecode.NOT_FOUND,
-+                                "Property %s does not exist." % (sname,)
-+                            ))
-+                        else:
-+                            return davxml.QuotaAvailableBytes(str(qvalue[0]))
-+                    d = self.quota(request)
-+                    d.addCallback(callback)
-+                    return d
-+
-+                if name == "quota-used-bytes":
-+                    def callback(qvalue):
-+                        if qvalue is None:
-+                            raise HTTPError(StatusResponse(
-+                                responsecode.NOT_FOUND,
-+                                "Property %s does not exist." % (sname,)
-+                            ))
-+                        else:
-+                            return davxml.QuotaUsedBytes(str(qvalue[1]))
-+                    d = self.quota(request)
-+                    d.addCallback(callback)
-+                    return d
- 
-             if namespace == twisted_dav_namespace:
-                 if name == "resource-class":
-@@ -596,7 +624,7 @@
-             else:
-                 factory = request.credentialFactories[authHeader[0]]
- 
--                creds = factory.decode(authHeader[1], request.method)
-+                creds = factory.decode(authHeader[1], request)
- 
-                 # Try to match principals in each principal collection on the resource
-                 def gotDetails(details):
-@@ -1502,6 +1530,219 @@
-         return None
- 
-     ##
-+    # Quota
-+    ##
-+    
-+    """
-+    The basic policy here is to define a private 'quota-root' property on a collection.
-+    That property will contain the maximum allowed bytes for the collections and all
-+    its contents.
-+    
-+    In order to determine the quota property values on a resource, the server must look
-+    for the private property on that resource and any of its parents. If found on a parent,
-+    then that parent should be queried for quota information. If not found, no quota
-+    exists for the resource.
-+    
-+    To determine tha actual quota in use we will cache the used byte count on the quota-root
-+    collection in another private property. It is the servers responsibility to
-+    keep that property up to date by adjusting it after every PUT, DELETE, COPY,
-+    MOVE, MKCOL, PROPPATCH, ACL, POST or any other method that may affect the size of
-+    stored data. If the private property is not present, the server will fall back to
-+    getting the size by iterating over all resources (this is done in static.py).
-+    
-+    """
-+
-+    def quota(self, request):
-+        """
-+        Get current available & used quota values for this resource's quota root
-+        collection.
-+
-+        @return: an L{Defered} with result C{tuple} containing two C{int}'s the first is 
-+            quota-available-bytes, the second is quota-used-bytes, or
-+            C{None} if quota is not defined on the resource.
-+        """
-+        
-+        # See if already cached
-+        if hasattr(request, "quota"):
-+            yield request.quota
-+            return
-+
-+        # Check this resource first
-+        if self.isCollection():
-+            qroot = self.quotaRoot(request)
-+            if qroot is not None:
-+                used = self.currentQuotaUse(request)
-+                available = qroot - used
-+                if available < 0:
-+                    available = 0
-+                request.quota = (available, used)
-+                yield request.quota
-+                return
-+        
-+        # Check the next parent
-+        url = request.urlForResource(self)
-+        if url != "/":
-+            parent = waitForDeferred(request.locateResource(parentForURL(url)))
-+            yield parent
-+            parent = parent.getResult()
-+            d = waitForDeferred(parent.quota(request))
-+            yield d
-+            request.quota = d.getResult()
-+        else:
-+            request.quota = None
-+
-+        yield request.quota
-+        return
-+    
-+    quota = deferredGenerator(quota)
-+
-+    def quotaRoot(self, request):
-+        """
-+        @return: a C{int} containing the maximum allowed bytes if this collection
-+            is quota-controlled, or C{None} if not quota controlled.
-+        """
-+        if self.hasDeadProperty(TwistedQuotaRootProperty):
-+            return int(str(self.readDeadProperty(TwistedQuotaRootProperty)))
-+        else:
-+            return None
-+    
-+    def quotaRootParent(self, request):
-+        """
-+        Return the next quota root above this resource.
-+        
-+        @return: L{DAVResource} or C{None}
-+        """
-+
-+        # Check the next parent
-+        url = request.urlForResource(self)
-+        while (url != "/"):
-+            url = parentForURL(url)
-+            parent = waitForDeferred(request.locateResource(url))
-+            yield parent
-+            parent = parent.getResult()
-+            if parent.hasDeadProperty(TwistedQuotaRootProperty):
-+                yield parent
-+                return
-+
-+        yield None
-+    
-+    quotaRootParent = deferredGenerator(quotaRootParent)
-+        
-+    def setQuotaRoot(self, request, maxsize):
-+        """
-+        @param maxsize: a C{int} containing the maximum allowed bytes for the contents
-+            of this collection.
-+        """
-+        assert self.isCollection(), "Only collections can have a quota root"
-+        assert isinstance(maxsize, int), "maxsize must be an int"
-+        
-+        self.writeDeadProperty(TwistedQuotaRootProperty.fromString(str(maxsize)))
-+    
-+    def quotaSize(self, request):
-+        """
-+        Get the size of this resource (if its a collection get total for all children as well).
-+        TODO: Take into account size of dead-properties.
-+
-+        @return: a C{int} containing the size of the resource.
-+        """
-+        unimplemented(self)
-+
-+    def checkQuota(self, request, available):
-+        """
-+        Check to see whether all quota roots have sufficient available bytes.
-+        We currently do not use hierarchical quota checks - i.e. only the most
-+        immediate quota root parent is checked for quota.
-+        
-+        @param available: a C{int} containing the additional quota required.
-+        @return: C{True} if there is sufficient quota remaining on all quota roots,
-+            C{False} otherwise.
-+        """
-+        
-+        quotaroot = self
-+        while(quotaroot is not None):
-+            # Check quota on this root (if it has one)
-+            quota = quotaroot.quotaRoot(request)
-+            if quota is not None:
-+                if available > quota[0]:
-+                    yield False
-+                    return
-+
-+            # Check the next parent with a quota root
-+            quotaroot = waitForDeferred(quotaroot.quotaRootParent(request))
-+            yield quotaroot
-+            quotaroot = quotaroot.getResult()
-+
-+        yield True
-+
-+    checkQuota = deferredGenerator(checkQuota)
-+
-+    def quotaSizeAdjust(self, request, adjust):
-+        """
-+        Update the quota used value on all quota root parents of this resource.
-+
-+        @param adjust: a C{int} containing the number of bytes added (positive) or
-+        removed (negative) that should be used to adjust the cached total.
-+        """
-+        
-+        # Check this resource first
-+        if self.isCollection():
-+            if self.hasDeadProperty(TwistedQuotaRootProperty):
-+                self.updateQuotaUse(request, adjust)
-+        
-+        # Check the next parent
-+        url = request.urlForResource(self)
-+        if url != "/":
-+            parent = waitForDeferred(request.locateResource(parentForURL(url)))
-+            yield parent
-+            parent = parent.getResult()
-+            d = waitForDeferred(parent.quotaSizeAdjust(request, adjust))
-+            yield d
-+            d.getResult()
-+
-+        yield None
-+
-+    quotaSizeAdjust = deferredGenerator(quotaSizeAdjust)
-+
-+    def currentQuotaUse(self, request):
-+        """
-+        Get the cached quota use value, or if not present (or invalid) determine
-+        quota use by brute force.
-+
-+        @return: a C{int} containing the current used byte if this collection
-+            is quota-controlled, or C{None} if not quota controlled.
-+        """
-+        assert self.isCollection(), "Only collections can have a quota root"
-+        assert self.hasDeadProperty(TwistedQuotaRootProperty), "Quota use only on quota root collection"
-+        
-+        # Try to get the cached value property
-+        if self.hasDeadProperty(TwistedQuotaUsedProperty):
-+            return int(str(self.readDeadProperty(TwistedQuotaUsedProperty)))
-+        else:
-+            # Do brute force size determination
-+            result = self.quotaSize(request)
-+            
-+            # Cache the brute force value in the private property
-+            self.writeDeadProperty(TwistedQuotaUsedProperty.fromString(str(result)))
-+            
-+            return result
-+
-+    def updateQuotaUse(self, request, adjust):
-+        """
-+        Update the quota used value on this resource.
-+
-+        @param adjust: a C{int} containing the number of bytes added (positive) or
-+        removed (negative) that should be used to adjust the cached total.
-+        @return: a C{int} containing the current used byte if this collection
-+            is quota-controlled, or C{None} if not quota controlled.
-+        """
-+        assert self.isCollection(), "Only collections can have a quota root"
-+        
-+        # Get current value
-+        size = self.currentQuotaUse(request)
-+        size += adjust
-+        self.writeDeadProperty(TwistedQuotaUsedProperty.fromString(str(size)))
-+        
-+    ##
-     # HTTP
-     ##
- 
-@@ -1736,6 +1977,28 @@
- 
- davxml.registerElement(TwistedAccessDisabledProperty)
- 
-+"""
-+When set on a collection, this property indicates that the collection has a quota limit for
-+the size of all resources stored in the collection (and any associate meta-data such as properties).
-+The value is a number - the maximum size in bytes allowed.
-+"""
-+class TwistedQuotaRootProperty (davxml.WebDAVTextElement):
-+    namespace = twisted_private_namespace
-+    name = "quota-root"
-+
-+davxml.registerElement(TwistedQuotaRootProperty)
-+
-+"""
-+When set on a collection, this property contains the cached running total of the size of all
-+resources stored in the collection (and any associate meta-data such as properties).
-+The value is a number - the size in bytes used.
-+"""
-+class TwistedQuotaUsedProperty (davxml.WebDAVTextElement):
-+    namespace = twisted_private_namespace
-+    name = "quota-used"
-+
-+davxml.registerElement(TwistedQuotaUsedProperty)
-+
- allACL = davxml.ACL(
-     davxml.ACE(
-         davxml.Principal(davxml.All()),

Deleted: CalendarServer/branches/users/cdaboo/quota/lib-patches/Twisted/twisted.web2.dav.static.patch
===================================================================
--- CalendarServer/branches/users/cdaboo/quota/lib-patches/Twisted/twisted.web2.dav.static.patch	2006-09-15 23:08:28 UTC (rev 142)
+++ CalendarServer/branches/users/cdaboo/quota/lib-patches/Twisted/twisted.web2.dav.static.patch	2006-09-18 15:31:58 UTC (rev 143)
@@ -1,80 +0,0 @@
-Index: twisted/web2/dav/static.py
-===================================================================
---- twisted/web2/dav/static.py	(revision 18157)
-+++ twisted/web2/dav/static.py	(working copy)
-@@ -29,6 +29,7 @@
- __all__ = ["DAVFile"]
- 
- import os
-+import stat
- 
- from twisted.python import log
- from twisted.internet.defer import succeed, deferredGenerator, waitForDeferred
-@@ -34,6 +35,8 @@
- from twisted.internet.defer import succeed, deferredGenerator, waitForDeferred
- from twisted.web2.static import File
- from twisted.web2 import dirlist
-+from twisted.web2 import http
-+from twisted.web2 import responsecode
- from twisted.web2.dav import davxml
- from twisted.web2.dav.idav import IDAVResource
- from twisted.web2.dav.resource import DAVResource, davPrivilegeSet
-@@ -98,6 +101,58 @@
-         return succeed(davPrivilegeSet)
- 
-     ##
-+    # Quota
-+    ##
-+
-+    def quotaSize(self, request):
-+        """
-+        Get the size of this resource.
-+        TODO: Take into account size of dead-properties. Does stat
-+            include xattrs size?
-+
-+        @return: a C{int} containing the size of the resource.
-+        """
-+        if self.isCollection():
-+            return self.collectionQuotaUse(request)
-+        else:
-+            result = os.stat(self.fp.path)
-+            return result[stat.ST_SIZE]
-+
-+    def collectionQuotaUse(self, request):
-+        """
-+        Brute force determination of quota used by this collection.
-+
-+        @return: a C{int} containing the current used byte if this collection
-+            is quota-controlled, or C{None} if not quota controlled.
-+        """
-+        assert self.isCollection(), "Only collections can have a quota root"
-+
-+        def walktree(top):
-+            """
-+            Recursively descend the directory tree rooted at top,
-+            calling the callback function for each regular file
-+            """
-+        
-+            total = 0
-+            for f in os.listdir(top):
-+                pathname = os.path.join(top, f)
-+                result = os.stat(pathname)
-+                mode = result[stat.ST_MODE]
-+                if stat.S_ISDIR(mode):
-+                    # It's a directory, recurse into it
-+                    total += walktree(pathname)
-+                elif stat.S_ISREG(mode):
-+                    # It's a file, call the callback function
-+                    total += result[stat.ST_SIZE]
-+                else:
-+                    # Unknown file type, print a message
-+                    pass
-+        
-+            return total
-+        
-+        return walktree(self.fp.path)
-+
-+    ##
-     # Workarounds for issues with File
-     ##
- 

Deleted: CalendarServer/branches/users/cdaboo/quota/lib-patches/Twisted/twisted.web2.test.test_httpauth.patch
===================================================================
--- CalendarServer/branches/users/cdaboo/quota/lib-patches/Twisted/twisted.web2.test.test_httpauth.patch	2006-09-15 23:08:28 UTC (rev 142)
+++ CalendarServer/branches/users/cdaboo/quota/lib-patches/Twisted/twisted.web2.test.test_httpauth.patch	2006-09-18 15:31:58 UTC (rev 143)
@@ -1,71 +0,0 @@
-Index: twisted/web2/test/test_httpauth.py
-===================================================================
---- twisted/web2/test/test_httpauth.py	(revision 18157)
-+++ twisted/web2/test/test_httpauth.py	(working copy)
-@@ -2,6 +2,7 @@
- from twisted.internet import defer
- from twisted.cred import error
- from twisted.web2.auth import basic, digest, wrapper
-+from twisted.web2.test.test_server import SimpleRequest
- 
- from twisted.web2.test import test_server
- 
-@@ -25,7 +26,7 @@
-                 self.username,
-                 self.password))
- 
--        creds = self.credentialFactory.decode(response)
-+        creds = self.credentialFactory.decode(response, SimpleRequest(None, 'GET', '/'))
-         self.failUnless(creds.checkPassword(self.password))
- 
-     def testIncorrectPassword(self):
-@@ -33,7 +34,7 @@
-                 self.username,
-                 'incorrectPassword'))
- 
--        creds = self.credentialFactory.decode(response)
-+        creds = self.credentialFactory.decode(response, SimpleRequest(None, 'GET', '/'))
-         self.failIf(creds.checkPassword(self.password))
- 
-     def testIncorrectPadding(self):
-@@ -43,7 +44,7 @@
- 
-         response = response.strip('=')
- 
--        creds = self.credentialFactory.decode(response)
-+        creds = self.credentialFactory.decode(response, SimpleRequest(None, 'GET', '/'))
-         self.failUnless(creds.checkPassword(self.password))
- 
-     def testInvalidCredentials(self):
-@@ -51,7 +52,7 @@
- 
-         self.assertRaises(error.LoginFailed, 
-                           self.credentialFactory.decode, 
--                          response)
-+                          response, SimpleRequest(None, 'GET', '/'))
- 
- challengeResponse = ('digest', {'nonce': '178288758716122392881254770685', 
-                                 'qop': 'auth', 'realm': 'test realm', 
-@@ -74,7 +75,7 @@
-     def testResponse(self):
-         challenge = self.credentialFactory.getChallenge(None)
- 
--        creds = self.credentialFactory.decode(authRequest, 'GET')
-+        creds = self.credentialFactory.decode(authRequest, SimpleRequest(None, 'GET', '/'))
-         self.failUnless(creds.checkPassword('password'))
- 
-     def testFailsWithDifferentMethod(self):
-@@ -80,11 +81,11 @@
-     def testFailsWithDifferentMethod(self):
-         challenge = self.credentialFactory.getChallenge(None)
-         
--        creds = self.credentialFactory.decode(authRequest, 'POST')
-+        creds = self.credentialFactory.decode(authRequest, SimpleRequest(None, 'POST', '/'))
-         self.failIf(creds.checkPassword('password'))
- 
-     def testNoUsername(self):
--        self.assertRaises(error.LoginFailed, self.credentialFactory.decode, namelessAuthRequest, 'GET')
-+        self.assertRaises(error.LoginFailed, self.credentialFactory.decode, namelessAuthRequest, SimpleRequest(None, 'GET', '/'))
- 
- from zope.interface import Interface, implements
- from twisted.cred import portal, checkers

Modified: CalendarServer/branches/users/cdaboo/quota/run
===================================================================
--- CalendarServer/branches/users/cdaboo/quota/run	2006-09-15 23:08:28 UTC (rev 142)
+++ CalendarServer/branches/users/cdaboo/quota/run	2006-09-18 15:31:58 UTC (rev 143)
@@ -412,7 +412,7 @@
     svn_uri="svn://svn.twistedmatrix.com/svn/Twisted/branches/acl-1608-8";
   fi;
 
-  svn_get "Twisted" "${twisted}" "${svn_uri}" 18155;
+  svn_get "Twisted" "${twisted}" "${svn_uri}" 18165;
 fi;
 py_install "Twisted" "${twisted}";
  

-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20060918/460f318f/attachment.html


More information about the calendarserver-changes mailing list