[CalendarServer-changes] [4130] CalendarServer/branches/exarkun/update-twisted-3816-3
source_changes at macosforge.org
source_changes at macosforge.org
Fri May 1 10:19:57 PDT 2009
Revision: 4130
http://trac.macosforge.org/projects/calendarserver/changeset/4130
Author: exarkun at twistedmatrix.com
Date: 2009-05-01 10:19:57 -0700 (Fri, 01 May 2009)
Log Message:
-----------
Merge forward from exarkun/update-twisted-3816-2 so I can integrate r4116, r4053, and r4024 properly
Modified Paths:
--------------
CalendarServer/branches/exarkun/update-twisted-3816-3/run
CalendarServer/branches/exarkun/update-twisted-3816-3/twistedcaldav/notify.py
CalendarServer/branches/exarkun/update-twisted-3816-3/twistedcaldav/test/test_index.py
CalendarServer/branches/exarkun/update-twisted-3816-3/twistedcaldav/test/test_upgrade.py
CalendarServer/branches/exarkun/update-twisted-3816-3/twistedcaldav/test/util.py
Removed Paths:
-------------
CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.application.app.patch
CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.conch.test.test_keys.patch
CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.internet._sslverify.patch
CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.internet.defer.patch
CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.mail.imap4.patch
CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.mail.pop3client.patch
CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.persisted.sob.patch
CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.plugins.__init__.patch
CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.python.filepath.patch
CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.runner.procmon.patch
CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.spread.pb.patch
CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.test.test_plugin.patch
CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.test.test_tcp.patch
CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web.test.test_webclient.patch
CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.auth.basic.patch
CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.auth.digest.patch
CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.auth.interfaces.patch
CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.auth.wrapper.patch
CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.__init__.patch
CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.auth.patch
CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.davxml.patch
CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.element.__init__.patch
CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.element.base.patch
CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.element.extensions.patch
CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.element.parser.patch
CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.element.rfc2518.patch
CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.element.rfc3744.patch
CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.element.rfc4331.patch
CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.fileop.patch
CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.http.patch
CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.idav.patch
CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.method.__init__.patch
CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.method.copymove.patch
CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.method.delete.patch
CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.method.prop_common.patch
CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.method.propfind.patch
CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.method.put.patch
CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.method.put_common.patch
CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.method.report.patch
CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.method.report_acl_principal_prop_set.patch
CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.method.report_expand.patch
CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.method.report_principal_match.patch
CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.method.report_principal_property_search.patch
CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.resource.patch
CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.static.patch
CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.stream.patch
CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.test.data.quota_100.patch
CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.test.test_acl.patch
CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.test.test_copy.patch
CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.test.test_pipeline.patch
CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.test.test_prop.patch
CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.test.test_quota.patch
CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.test.test_resource.patch
CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.test.test_static.patch
CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.test.test_stream.patch
CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.test.test_xml.patch
CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.test.tworequest_client.patch
CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.test.util.patch
CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.util.patch
CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.xattrprops.patch
CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.http.patch
CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.log.patch
CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.server.patch
CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.static.patch
CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.test.test_http.patch
CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.test.test_httpauth.patch
CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.words.protocols.jabber.sasl_mechanisms.patch
Deleted: CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.application.app.patch
===================================================================
--- CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.application.app.patch 2009-05-01 17:16:27 UTC (rev 4129)
+++ CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.application.app.patch 2009-05-01 17:19:57 UTC (rev 4130)
@@ -1,13 +0,0 @@
-Index: twisted/application/app.py
-===================================================================
---- twisted/application/app.py (revision 19773)
-+++ twisted/application/app.py (working copy)
-@@ -18,7 +18,7 @@
- def runWithProfiler(reactor, config):
- """Run reactor under standard profiler."""
- try:
-- import profile
-+ import cProfile as profile
- except ImportError, e:
- s = "Failed to import module profile: %s" % e
- s += """
Deleted: CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.conch.test.test_keys.patch
===================================================================
--- CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.conch.test.test_keys.patch 2009-05-01 17:16:27 UTC (rev 4129)
+++ CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.conch.test.test_keys.patch 2009-05-01 17:19:57 UTC (rev 4130)
@@ -1,16 +0,0 @@
-Index: twisted/conch/test/test_keys.py
-===================================================================
---- twisted/conch/test/test_keys.py (revision 19773)
-+++ twisted/conch/test/test_keys.py (working copy)
-@@ -4,10 +4,10 @@
-
- try:
- import Crypto
-+ from twisted.conch.ssh import keys
- except ImportError:
- Crypto = None
-
--from twisted.conch.ssh import keys
- from twisted.trial import unittest
-
- publicRSA_openssh = "ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAGEArzJx8OYOnJmzf4tfBEvLi8DVPrJ3/c9k2I/Az64fxjHf9imyRJbixtQhlH9lfNjUIx+4LmrJH5QNRsFporcHDKOTwTTYLh5KmRpslkYHRivcJSkbh/C+BR3utDS555mV comment"
Deleted: CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.internet._sslverify.patch
===================================================================
--- CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.internet._sslverify.patch 2009-05-01 17:16:27 UTC (rev 4129)
+++ CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.internet._sslverify.patch 2009-05-01 17:19:57 UTC (rev 4130)
@@ -1,35 +0,0 @@
-Index: twisted/internet/_sslverify.py
-===================================================================
---- twisted/internet/_sslverify.py (revision 19773)
-+++ twisted/internet/_sslverify.py (working copy)
-@@ -1,7 +1,11 @@
- # -*- test-case-name: twisted.test.test_sslverify -*-
- # Copyright 2005 Divmod, Inc. See LICENSE file for details
-
--import itertools, md5
-+import itertools
-+try:
-+ from hashlib import md5
-+except ImportError:
-+ from md5 import new as md5
- from OpenSSL import SSL, crypto
-
- from twisted.python import reflect, util
-@@ -666,7 +670,7 @@
- MD5 hex digest of signature on an empty certificate request with this
- key.
- """
-- return md5.md5(self._emptyReq).hexdigest()
-+ return md5(self._emptyReq).hexdigest()
-
-
- def inspect(self):
-@@ -942,7 +946,7 @@
- ctx.set_options(self._OP_ALL)
-
- if self.enableSessions:
-- sessionName = md5.md5("%s-%d" % (reflect.qual(self.__class__), _sessionCounter())).hexdigest()
-+ sessionName = md5("%s-%d" % (reflect.qual(self.__class__), _sessionCounter())).hexdigest()
- ctx.set_session_id(sessionName)
-
- return ctx
Deleted: CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.internet.defer.patch
===================================================================
--- CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.internet.defer.patch 2009-05-01 17:16:27 UTC (rev 4129)
+++ CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.internet.defer.patch 2009-05-01 17:19:57 UTC (rev 4130)
@@ -1,12 +0,0 @@
-Index: twisted/internet/defer.py
-===================================================================
---- twisted/internet/defer.py (revision 19773)
-+++ twisted/internet/defer.py (working copy)
-@@ -998,6 +998,6 @@
- __all__ = ["Deferred", "DeferredList", "succeed", "fail", "FAILURE", "SUCCESS",
- "AlreadyCalledError", "TimeoutError", "gatherResults",
- "maybeDeferred",
-- "waitForDeferred", "deferredGenerator", "inlineCallbacks",
-+ "waitForDeferred", "deferredGenerator", "returnValue", "inlineCallbacks",
- "DeferredLock", "DeferredSemaphore", "DeferredQueue",
- ]
Deleted: CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.mail.imap4.patch
===================================================================
--- CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.mail.imap4.patch 2009-05-01 17:16:27 UTC (rev 4129)
+++ CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.mail.imap4.patch 2009-05-01 17:19:57 UTC (rev 4130)
@@ -1,65 +0,0 @@
-Index: twisted/mail/imap4.py
-===================================================================
---- twisted/mail/imap4.py (revision 19773)
-+++ twisted/mail/imap4.py (working copy)
-@@ -363,16 +363,11 @@
- for L in self.lines:
- names = parseNestedParens(L)
- N = len(names)
-+ # This section is patched as described in http://twistedmatrix.com/trac/ticket/1105
- if (N >= 1 and names[0] in self._1_RESPONSES or
-+ N >= 2 and names[1] in self._2_RESPONSES or
- N >= 2 and names[0] == 'OK' and isinstance(names[1], types.ListType) and names[1][0] in self._OK_RESPONSES):
- send.append(L)
-- elif N >= 3 and names[1] in self._2_RESPONSES:
-- if isinstance(names[2], list) and len(names[2]) >= 1 and names[2][0] == 'FLAGS' and 'FLAGS' not in self.args:
-- unuse.append(L)
-- else:
-- send.append(L)
-- elif N >= 2 and names[1] in self._2_RESPONSES:
-- send.append(L)
- else:
- unuse.append(L)
- d, self.defer = self.defer, None
-@@ -2245,10 +2240,12 @@
- for f in fetched.get('FLAGS', []):
- sum.append(f)
- flags.setdefault(mId, []).extend(sum)
-+ elif L.find('BYE LOGOUT') != -1:
-+ pass
- else:
- log.msg('Unhandled unsolicited response: ' + repr(L))
-- if flags:
-- self.flagsChanged(flags)
-+ #if flags:
-+ # self.flagsChanged(flags)
- if recent is not None or exists is not None:
- self.newMessages(exists, recent)
-
-@@ -3336,6 +3333,8 @@
- if len(data) < 2:
- raise IllegalServerResponse("Not enough arguments", data)
- flags.setdefault(id, {})[data[0]] = data[1]
-+ if data[0] == 'FLAGS':
-+ self.flagsChanged({id: data[1]})
- del data[:2]
- else:
- print '(2)Ignoring ', parts
-@@ -3431,7 +3430,16 @@
- except ValueError:
- raise IllegalServerResponse, line
- else:
-- info[id] = parseNestedParens(parts[2])
-+ data = parseNestedParens(parts[2])[0]
-+ # This section is patched as described in http://twistedmatrix.com/trac/ticket/1105
-+ # XXX this will fail if 'FLAGS' is a retrieved part
-+ for i in range(len(data) -1):
-+ if data[i] == 'FLAGS':
-+ self.flagsChanged({id: data[i+1]})
-+ del data[i:i+2]
-+ break
-+ if data:
-+ info.setdefault(id, []).append(data)
- return info
-
- def _fetch(self, messages, useUID=0, **terms):
Deleted: CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.mail.pop3client.patch
===================================================================
--- CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.mail.pop3client.patch 2009-05-01 17:16:27 UTC (rev 4129)
+++ CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.mail.pop3client.patch 2009-05-01 17:19:57 UTC (rev 4130)
@@ -1,28 +0,0 @@
-Index: twisted/mail/pop3client.py
-===================================================================
---- twisted/mail/pop3client.py (revision 19773)
-+++ twisted/mail/pop3client.py (working copy)
-@@ -11,8 +11,13 @@
- API Stability: Unstable
- """
-
--import re, md5
-+import re
-
-+try:
-+ from hashlib import md5
-+except ImportError:
-+ from md5 import new as md5
-+
- from twisted.python import log
- from twisted.internet import defer
- from twisted.protocols import basic
-@@ -486,7 +491,7 @@
- def _apop(self, username, password, challenge):
- # Internal helper. Computes and sends an APOP response. Returns
- # a Deferred that fires when the server responds to the response.
-- digest = md5.new(challenge + password).hexdigest()
-+ digest = md5(challenge + password).hexdigest()
- return self.apop(username, digest)
-
- def apop(self, username, digest):
Deleted: CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.persisted.sob.patch
===================================================================
--- CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.persisted.sob.patch 2009-05-01 17:16:27 UTC (rev 4129)
+++ CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.persisted.sob.patch 2009-05-01 17:19:57 UTC (rev 4130)
@@ -1,32 +0,0 @@
-Index: twisted/persisted/sob.py
-===================================================================
---- twisted/persisted/sob.py (revision 19773)
-+++ twisted/persisted/sob.py (working copy)
-@@ -10,8 +10,12 @@
- Maintainer: U{Moshe Zadka<mailto:moshez at twistedmatrix.com>}
- """
-
--import os, md5, sys
-+import os, sys
- try:
-+ from hashlib import md5
-+except ImportError:
-+ from md5 import new as md5
-+try:
- import cPickle as pickle
- except ImportError:
- import pickle
-@@ -32,11 +36,11 @@
- leftover = len(data) % cipher.block_size
- if leftover:
- data += ' '*(cipher.block_size - leftover)
-- return cipher.new(md5.new(passphrase).digest()[:16]).encrypt(data)
-+ return cipher.new(md5(passphrase).digest()[:16]).encrypt(data)
-
- def _decrypt(passphrase, data):
- from Crypto.Cipher import AES
-- return AES.new(md5.new(passphrase).digest()[:16]).decrypt(data)
-+ return AES.new(md5(passphrase).digest()[:16]).decrypt(data)
-
-
- class IPersistable(Interface):
Deleted: CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.plugins.__init__.patch
===================================================================
--- CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.plugins.__init__.patch 2009-05-01 17:16:27 UTC (rev 4129)
+++ CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.plugins.__init__.patch 2009-05-01 17:19:57 UTC (rev 4130)
@@ -1,12 +0,0 @@
-Index: twisted/plugins/__init__.py
-===================================================================
---- twisted/plugins/__init__.py (revision 19773)
-+++ twisted/plugins/__init__.py (working copy)
-@@ -12,6 +12,6 @@
- """
-
- import os, sys
--__path__ = [os.path.abspath(os.path.join(x, 'twisted', 'plugins')) for x in sys.path]
-+__path__ = [os.path.abspath(os.path.join(x, 'twisted', 'plugins')) for x in sys.path if not x.startswith('/System')]
-
- __all__ = [] # nothing to see here, move along, move along
Deleted: CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.python.filepath.patch
===================================================================
--- CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.python.filepath.patch 2009-05-01 17:16:27 UTC (rev 4129)
+++ CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.python.filepath.patch 2009-05-01 17:19:57 UTC (rev 4130)
@@ -1,28 +0,0 @@
-Index: twisted/python/filepath.py
-===================================================================
---- twisted/python/filepath.py (revision 19773)
-+++ twisted/python/filepath.py (working copy)
-@@ -9,9 +9,13 @@
- import os
- import errno
- import random
--import sha
- import base64
-
-+try:
-+ from hashlib import sha1
-+except ImportError:
-+ from sha import new as sha1
-+
- from os.path import isabs, exists, normpath, abspath, splitext
- from os.path import basename, dirname
- from os.path import join as joinpath
-@@ -109,7 +113,7 @@
- """
- Create a pseudorandom, 16-character string for use in secure filenames.
- """
-- return armor(sha.new(randomBytes(64)).digest())[:16]
-+ return armor(sha1(randomBytes(64)).digest())[:16]
-
- class _PathHelper:
- """
Deleted: CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.runner.procmon.patch
===================================================================
--- CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.runner.procmon.patch 2009-05-01 17:16:27 UTC (rev 4129)
+++ CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.runner.procmon.patch 2009-05-01 17:19:57 UTC (rev 4130)
@@ -1,39 +0,0 @@
-Index: twisted/runner/procmon.py
-===================================================================
---- twisted/runner/procmon.py (revision 19773)
-+++ twisted/runner/procmon.py (working copy)
-@@ -59,6 +59,9 @@
-
- disconnecting = 0
-
-+ def loseConnection(self):
-+ pass
-+
- transport = DummyTransport()
-
- class LineLogger(basic.LineReceiver):
-@@ -130,10 +133,10 @@
- self.consistency = reactor.callLater(self.consistencyDelay,
- self._checkConsistency)
-
-- def addProcess(self, name, args, uid=None, gid=None):
-+ def addProcess(self, name, args, uid=None, gid=None, env={}):
- if self.processes.has_key(name):
- raise KeyError("remove %s first" % name)
-- self.processes[name] = args, uid, gid
-+ self.processes[name] = args, uid, gid, env
- if self.active:
- self.startProcess(name)
-
-@@ -175,9 +178,9 @@
- p = self.protocols[name] = LoggingProtocol()
- p.service = self
- p.name = name
-- args, uid, gid = self.processes[name]
-+ args, uid, gid, env = self.processes[name]
- self.timeStarted[name] = time.time()
-- reactor.spawnProcess(p, args[0], args, uid=uid, gid=gid)
-+ reactor.spawnProcess(p, args[0], args, uid=uid, gid=gid, env=env)
-
- def _forceStopProcess(self, proc):
- try:
Deleted: CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.spread.pb.patch
===================================================================
--- CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.spread.pb.patch 2009-05-01 17:16:27 UTC (rev 4129)
+++ CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.spread.pb.patch 2009-05-01 17:19:57 UTC (rev 4130)
@@ -1,53 +0,0 @@
-Index: twisted/spread/pb.py
-===================================================================
---- twisted/spread/pb.py (revision 19773)
-+++ twisted/spread/pb.py (working copy)
-@@ -64,7 +64,11 @@
- except ImportError:
- import StringIO
-
--import md5
-+try:
-+ from hashlib import md5
-+except ImportError:
-+ from md5 import new as md5
-+
- import random
- import new
- import types
-@@ -1003,10 +1007,10 @@
-
- This is useful for challenge/response authentication.
- """
-- m = md5.new()
-+ m = md5()
- m.update(password)
- hashedPassword = m.digest()
-- m = md5.new()
-+ m = md5()
- m.update(hashedPassword)
- m.update(challenge)
- doubleHashedPassword = m.digest()
-@@ -1017,7 +1021,7 @@
- crap = ''
- for x in range(random.randrange(15,25)):
- crap = crap + chr(random.randint(65,90))
-- crap = md5.new(crap).digest()
-+ crap = md5(crap).digest()
- return crap
-
-
-@@ -1226,11 +1230,11 @@
-
- # IUsernameHashedPassword:
- def checkPassword(self, password):
-- return self.checkMD5Password(md5.md5(password).digest())
-+ return self.checkMD5Password(md5(password).digest())
-
- # IUsernameMD5Password
- def checkMD5Password(self, md5Password):
-- md = md5.new()
-+ md = md5()
- md.update(md5Password)
- md.update(self.challenge)
- correct = md.digest()
Deleted: CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.test.test_plugin.patch
===================================================================
--- CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.test.test_plugin.patch 2009-05-01 17:16:27 UTC (rev 4129)
+++ CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.test.test_plugin.patch 2009-05-01 17:19:57 UTC (rev 4130)
@@ -1,11 +0,0 @@
-Index: twisted/test/test_plugin.py
-===================================================================
---- twisted/test/test_plugin.py (revision 19773)
-+++ twisted/test/test_plugin.py (working copy)
-@@ -518,3 +518,6 @@
- self.assertEqual(len(self.flushLoggedErrors()), 0)
- self.assertIn('one', self.getAllPlugins())
- self.assertEqual(len(self.flushLoggedErrors()), 1)
-+
-+
-+ test_newPluginsOnReadOnlyPath.skip = "Seems not to work on OS X 10.4 buildbot machine."
Deleted: CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.test.test_tcp.patch
===================================================================
--- CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.test.test_tcp.patch 2009-05-01 17:16:27 UTC (rev 4129)
+++ CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.test.test_tcp.patch 2009-05-01 17:19:57 UTC (rev 4130)
@@ -1,13 +0,0 @@
-Index: twisted/test/test_tcp.py
-===================================================================
---- twisted/test/test_tcp.py (revision 19773)
-+++ twisted/test/test_tcp.py (working copy)
-@@ -1294,6 +1294,8 @@
- self.client.transport.loseConnection()
- log.flushErrors(RuntimeError)
- return d.addCallback(check)
-+
-+ testReadNotificationRaises.todo = "self.f.protocol is None"
-
- def testWriteNotificationRaises(self):
- self.client.writeConnectionLost = self.aBug
Deleted: CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web.test.test_webclient.patch
===================================================================
--- CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web.test.test_webclient.patch 2009-05-01 17:16:27 UTC (rev 4129)
+++ CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web.test.test_webclient.patch 2009-05-01 17:19:57 UTC (rev 4130)
@@ -1,13 +0,0 @@
-Index: twisted/web/test/test_webclient.py
-===================================================================
---- twisted/web/test/test_webclient.py (revision 19773)
-+++ twisted/web/test/test_webclient.py (working copy)
-@@ -206,6 +206,8 @@
- d.addBoth(self._cleanupDownloadPageError3)
- return d
-
-+ testDownloadPageError3.skip = "Seems not to work on OS X."
-+
- def _cleanupDownloadPageError3(self, ignored):
- os.chmod("unwritable", 0700)
- os.unlink("unwritable")
Deleted: CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.auth.basic.patch
===================================================================
--- CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.auth.basic.patch 2009-05-01 17:16:27 UTC (rev 4129)
+++ CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.auth.basic.patch 2009-05-01 17:19:57 UTC (rev 4130)
@@ -1,29 +0,0 @@
-Index: twisted/web2/auth/basic.py
-===================================================================
---- twisted/web2/auth/basic.py (revision 19773)
-+++ twisted/web2/auth/basic.py (working copy)
-@@ -1,6 +1,7 @@
- # -*- test-case-name: twisted.web2.test.test_httpauth -*-
-
- from twisted.cred import credentials, error
-+from twisted.internet.defer import succeed
- from twisted.web2.auth.interfaces import ICredentialFactory
-
- from zope.interface import implements
-@@ -18,7 +19,7 @@
- self.realm = realm
-
- def getChallenge(self, peer):
-- return {'realm': self.realm}
-+ return succeed({'realm': self.realm})
-
- def decode(self, response, request):
- try:
-@@ -28,6 +29,6 @@
-
- creds = creds.split(':', 1)
- if len(creds) == 2:
-- return credentials.UsernamePassword(*creds)
-+ return succeed(credentials.UsernamePassword(*creds))
- else:
- raise error.LoginFailed('Invalid credentials')
Deleted: CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.auth.digest.patch
===================================================================
--- CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.auth.digest.patch 2009-05-01 17:16:27 UTC (rev 4129)
+++ CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.auth.digest.patch 2009-05-01 17:19:57 UTC (rev 4130)
@@ -1,135 +0,0 @@
-Index: twisted/web2/auth/digest.py
-===================================================================
---- twisted/web2/auth/digest.py (revision 19773)
-+++ twisted/web2/auth/digest.py (working copy)
-@@ -8,19 +8,28 @@
- import time
-
- from twisted.cred import credentials, error
-+from twisted.internet.defer import succeed
- from zope.interface import implements, Interface
-
- from twisted.web2.auth.interfaces import ICredentialFactory
-+from twisted.web2.http_headers import tokenize
-+from twisted.web2.http_headers import Token
-+from twisted.web2.http_headers import split
-+from twisted.web2.http_headers import parseKeyValue
-
--import md5, sha
-+try:
-+ from hashlib import md5, sha1
-+except ImportError:
-+ from md5 import new as md5
-+ from sha import new as sha1
- import random, sys
-
- # The digest math
-
- algorithms = {
-- 'md5': md5.new,
-- 'md5-sess': md5.new,
-- 'sha': sha.new,
-+ 'md5': md5,
-+ 'md5-sess': md5,
-+ 'sha': sha1,
- }
-
- # DigestCalcHA1
-@@ -153,7 +162,18 @@
- calcHA1(algo, self.username, self.realm, password, nonce, cnonce),
- algo, nonce, nc, cnonce, qop, self.method, uri, None
- )
-+
-+ if expected == response:
-+ return True
-
-+ # IE7 sends cnonce and nc values, but auth fails if they are used.
-+ # So try again without them...
-+ # They can be omitted for backwards compatibility [RFC 2069].
-+ expected = calcResponse(
-+ calcHA1(algo, self.username, self.realm, password, nonce, cnonce),
-+ algo, nonce, None, None, qop, self.method, uri, None
-+ )
-+
- return expected == response
-
- def checkHash(self, digestHash):
-@@ -228,9 +248,9 @@
- # Now, what we do is encode the nonce, client ip and a timestamp
- # in the opaque value with a suitable digest
- key = "%s,%s,%s" % (nonce, clientip, str(int(self._getTime())))
-- digest = md5.new(key + self.privateKey).hexdigest()
-+ digest = md5(key + self.privateKey).hexdigest()
- ekey = key.encode('base64')
-- return "%s-%s" % (digest, ekey.strip('\n'))
-+ return "%s-%s" % (digest, ekey.replace('\n', ''))
-
- def verifyOpaque(self, opaque, nonce, clientip):
- """
-@@ -274,7 +294,7 @@
- 'Invalid response, incompatible opaque/nonce too old')
-
- # Verify the digest
-- digest = md5.new(key + self.privateKey).hexdigest()
-+ digest = md5(key + self.privateKey).hexdigest()
- if digest != opaqueParts[0]:
- raise error.LoginFailed('Invalid response, invalid opaque value')
-
-@@ -293,11 +313,12 @@
- c = self.generateNonce()
- o = self.generateOpaque(c, peer.host)
-
-- return {'nonce': c,
-- 'opaque': o,
-- 'qop': 'auth',
-- 'algorithm': self.algorithm,
-- 'realm': self.realm}
-+ return succeed({'nonce': c,
-+ 'opaque': o,
-+ 'qop': 'auth',
-+ 'algorithm': self.algorithm,
-+ 'realm': self.realm,
-+ })
-
- def decode(self, response, request):
- """
-@@ -315,18 +336,18 @@
- @raise: L{error.LoginFailed} if the response does not contain a
- username, a nonce, an opaque, or if the opaque is invalid.
- """
-- def unq(s):
-- if s[0] == s[-1] == '"':
-- return s[1:-1]
-- return s
- response = ' '.join(response.splitlines())
-- parts = response.split(',')
--
-- auth = {}
--
-- for (k, v) in [p.split('=', 1) for p in parts]:
-- auth[k.strip()] = unq(v.strip())
--
-+
-+ try:
-+ parts = split(tokenize((response,), foldCase=False), Token(","))
-+
-+ auth = {}
-+
-+ for (k, v) in [parseKeyValue(p) for p in parts]:
-+ auth[k.strip()] = v.strip()
-+ except ValueError:
-+ raise error.LoginFailed('Invalid response.')
-+
- username = auth.get('username')
- if not username:
- raise error.LoginFailed('Invalid response, no username given.')
-@@ -342,7 +363,7 @@
- auth.get('nonce'),
- request.remoteAddr.host):
-
-- return DigestedCredentials(username,
-+ return succeed(DigestedCredentials(username,
- request.method,
- self.realm,
-- auth)
-+ auth))
Deleted: CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.auth.interfaces.patch
===================================================================
--- CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.auth.interfaces.patch 2009-05-01 17:16:27 UTC (rev 4129)
+++ CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.auth.interfaces.patch 2009-05-01 17:19:57 UTC (rev 4130)
@@ -1,22 +0,0 @@
-Index: twisted/web2/auth/interfaces.py
-===================================================================
---- twisted/web2/auth/interfaces.py (revision 19773)
-+++ twisted/web2/auth/interfaces.py (working copy)
-@@ -18,7 +18,7 @@
- @param peer: The client's address
-
- @rtype: C{dict}
-- @return: dictionary of challenge arguments
-+ @return: deferred returning dictionary of challenge arguments
- """
-
- def decode(response, request):
-@@ -32,7 +32,7 @@
- @type request: L{twisted.web2.server.Request}
- @param request: the request being processed
-
-- @return: ICredentials
-+ @return: deferred returning ICredentials
- """
-
-
Deleted: CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.auth.wrapper.patch
===================================================================
--- CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.auth.wrapper.patch 2009-05-01 17:16:27 UTC (rev 4129)
+++ CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.auth.wrapper.patch 2009-05-01 17:19:57 UTC (rev 4130)
@@ -1,205 +0,0 @@
-Index: twisted/web2/auth/wrapper.py
-===================================================================
---- twisted/web2/auth/wrapper.py (revision 19773)
-+++ twisted/web2/auth/wrapper.py (working copy)
-@@ -5,32 +5,45 @@
- """
- from zope.interface import implements, directlyProvides
- from twisted.cred import error, credentials
--from twisted.python import failure
- from twisted.web2 import responsecode
- from twisted.web2 import http
- from twisted.web2 import iweb
- from twisted.web2.auth.interfaces import IAuthenticatedRequest
-+from twisted.internet.defer import inlineCallbacks, returnValue
-
- class UnauthorizedResponse(http.StatusResponse):
- """A specialized response class for generating www-authenticate headers
- from the given L{CredentialFactory} instances
- """
-
-- def __init__(self, factories, remoteAddr=None):
-+ @staticmethod
-+ def makeResponse(factories, remoteAddr=None):
-+
-+ response = UnauthorizedResponse()
-+ d = response.generateHeaders(factories, remoteAddr)
-+ d.addCallback(lambda _:response)
-+ return d
-+
-+ def __init__(self):
-+
-+ super(UnauthorizedResponse, self).__init__(
-+ responsecode.UNAUTHORIZED,
-+ "You are not authorized to access this resource."
-+ )
-+
-+ @inlineCallbacks
-+ def generateHeaders(self, factories, remoteAddr=None):
- """
- @param factories: A L{dict} of {'scheme': ICredentialFactory}
-
- @param remoteAddr: An L{IAddress} for the connecting client.
- """
-
-- super(UnauthorizedResponse, self).__init__(
-- responsecode.UNAUTHORIZED,
-- "You are not authorized to access this resource.")
--
- authHeaders = []
- for factory in factories.itervalues():
-- authHeaders.append((factory.scheme,
-- factory.getChallenge(remoteAddr)))
-+ scheme = factory.scheme
-+ challenge = (yield factory.getChallenge(remoteAddr))
-+ authHeaders.append((scheme, challenge,))
-
- self.headers.setHeader('www-authenticate', authHeaders)
-
-@@ -71,8 +84,6 @@
-
- def _loginSucceeded(self, avatar, request):
- """
-- Callback for successful login.
--
- @param avatar: A tuple of the form (interface, avatar) as
- returned by your realm.
-
-@@ -85,6 +96,7 @@
-
- directlyProvides(request, IAuthenticatedRequest)
-
-+ @inlineCallbacks
- def _addAuthenticateHeaders(request, response):
- """
- A response filter that adds www-authenticate headers
-@@ -93,14 +105,16 @@
- """
- if response.code == responsecode.UNAUTHORIZED:
- if not response.headers.hasHeader('www-authenticate'):
-- newResp = UnauthorizedResponse(self.credentialFactories,
-- request.remoteAddr)
-+ newResp = (yield UnauthorizedResponse.makeResponse(
-+ self.credentialFactories,
-+ request.remoteAddr
-+ ))
-
- response.headers.setHeader(
- 'www-authenticate',
- newResp.headers.getHeader('www-authenticate'))
-
-- return response
-+ returnValue(response)
-
- _addAuthenticateHeaders.handleErrors = True
-
-@@ -108,27 +122,22 @@
-
- return self.wrappedResource
-
-- def _loginFailed(self, result, request):
-+ @inlineCallbacks
-+ def _loginFailed(self, request):
- """
-- Errback for failed login.
--
-- @param result: L{Failure} returned by portal.login
--
- @param request: L{IRequest} that encapsulates this auth
- attempt.
-
-- @return: A L{Failure} containing an L{HTTPError} containing the
-- L{UnauthorizedResponse} if C{result} is an L{UnauthorizedLogin}
-- or L{UnhandledCredentials} error
-+ @raise: always rais HTTPError
- """
-- result.trap(error.UnauthorizedLogin, error.UnhandledCredentials)
-
-- return failure.Failure(
-- http.HTTPError(
-- UnauthorizedResponse(
-- self.credentialFactories,
-- request.remoteAddr)))
-+ response = (yield UnauthorizedResponse.makeResponse(
-+ self.credentialFactories,
-+ request.remoteAddr
-+ ))
-+ raise http.HTTPError(response)
-
-+ @inlineCallbacks
- def login(self, factory, response, request):
- """
- @param factory: An L{ICredentialFactory} that understands the given
-@@ -142,50 +151,48 @@
- or a failure containing an L{UnauthorizedResponse}
- """
- try:
-- creds = factory.decode(response, request)
-+ creds = (yield factory.decode(response, request))
- except error.LoginFailed:
-- raise http.HTTPError(UnauthorizedResponse(
-- self.credentialFactories,
-- request.remoteAddr))
-+ yield self._loginFailed(request)
-
-+ try:
-+ avatar = (yield self.portal.login(creds, None, *self.interfaces))
-+ except (error.UnauthorizedLogin, error.UnhandledCredentials):
-+ yield self._loginFailed(request)
-+ resource = self._loginSucceeded(avatar, request)
-+ returnValue(resource)
-
-- return self.portal.login(creds, None, *self.interfaces
-- ).addCallbacks(self._loginSucceeded,
-- self._loginFailed,
-- (request,), None,
-- (request,), None)
--
-+ @inlineCallbacks
- def authenticate(self, request):
- """
-- Attempt to authenticate the givin request
-+ Attempt to authenticate the giving request
-
- @param request: An L{IRequest} to be authenticated.
- """
- authHeader = request.headers.getHeader('authorization')
-
- if authHeader is None:
-- return self.portal.login(credentials.Anonymous(),
-- None,
-- *self.interfaces
-- ).addCallbacks(self._loginSucceeded,
-- self._loginFailed,
-- (request,), None,
-- (request,), None)
-+ try:
-+ avatar = (yield self.portal.login(credentials.Anonymous(), None, *self.interfaces))
-+ except:
-+ yield self._loginFailed(request)
-+ resource = self._loginSucceeded(avatar, request)
-+ returnValue(resource)
-
- elif authHeader[0] not in self.credentialFactories:
-- raise http.HTTPError(UnauthorizedResponse(
-- self.credentialFactories,
-- request.remoteAddr))
-+ yield self._loginFailed(request)
- else:
-- return self.login(self.credentialFactories[authHeader[0]],
-- authHeader[1], request)
-+ result = (yield self.login(self.credentialFactories[authHeader[0]], authHeader[1], request))
-+ returnValue(result)
-
- def locateChild(self, request, seg):
- """
- Authenticate the request then return the C{self.wrappedResource}
- and the unmodified segments.
- """
-- return self.authenticate(request), seg
-+ d = self.authenticate(request)
-+ d.addCallback(lambda result:(result, seg,))
-+ return d
-
- def renderHTTP(self, request):
- """
Deleted: CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.__init__.patch
===================================================================
--- CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.__init__.patch 2009-05-01 17:16:27 UTC (rev 4129)
+++ CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.__init__.patch 2009-05-01 17:19:57 UTC (rev 4130)
@@ -1,12 +0,0 @@
-Index: twisted/web2/dav/__init__.py
-===================================================================
---- twisted/web2/dav/__init__.py (revision 19773)
-+++ twisted/web2/dav/__init__.py (working copy)
-@@ -45,6 +45,7 @@
- "noneprops",
- "resource",
- "static",
-+ "stream",
- "util",
- "xattrprops",
- ]
Deleted: CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.auth.patch
===================================================================
--- CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.auth.patch 2009-05-01 17:16:27 UTC (rev 4129)
+++ CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.auth.patch 2009-05-01 17:19:57 UTC (rev 4130)
@@ -1,83 +0,0 @@
-Index: twisted/web2/dav/auth.py
-===================================================================
---- twisted/web2/dav/auth.py (revision 19773)
-+++ twisted/web2/dav/auth.py (working copy)
-@@ -5,7 +5,13 @@
- from twisted.web2.dav import davxml
- from twisted.web2.dav.davxml import twisted_private_namespace
-
--__all__ = ["PrincipalCredentials", "AuthenticationWrapper"]
-+__all__ = [
-+ "IPrincipal",
-+ "DavRealm",
-+ "IPrincipalCredentials",
-+ "PrincipalCredentials",
-+ "AuthenticationWrapper",
-+]
-
- class AuthenticationWrapper(WrapperResource):
- def __init__(self, resource, portal, credentialFactories, loginInterfaces):
-@@ -40,7 +46,7 @@
-
- def requestAvatar(self, avatarId, mind, *interfaces):
- if IPrincipal in interfaces:
-- return IPrincipal, davxml.Principal(davxml.HRef(avatarId))
-+ return IPrincipal, davxml.Principal(davxml.HRef(avatarId[0])), davxml.Principal(davxml.HRef(avatarId[1]))
-
- raise NotImplementedError("Only IPrincipal interface is supported")
-
-@@ -52,33 +58,44 @@
- class PrincipalCredentials(object):
- implements(IPrincipalCredentials)
-
-- def __init__(self, principal, principalURI, credentials):
-- self.principal = principal
-- self.principalURI = principalURI
-+ def __init__(self, authnPrincipal, authzPrincipal, credentials):
-+ """
-+ Initialize with both authentication and authorization values. Note that in most cases theses will be the same
-+ since HTTP auth makes no distinction between the two - but we may be layering some addition auth on top of this
-+ (.e.g.. proxy auth, cookies, forms etc) that make result in authentication and authorization being different.
-+
-+ @param authnPrincipal: L{IDAVPrincipalResource} for the authenticated principal.
-+ @param authnURI: C{str} containing the URI of the authenticated principal.
-+ @param authzPrincipal: L{IDAVPrincipalResource} for the authorized principal.
-+ @param authzURI: C{str} containing the URI of the authorized principal.
-+ @param credentials: L{ICredentials} for the authentication credentials.
-+ """
-+ self.authnPrincipal = authnPrincipal
-+ self.authzPrincipal = authzPrincipal
- self.credentials = credentials
-
- def checkPassword(self, password):
- return self.credentials.checkPassword(password)
-
-
--class TwistedPropertyChecker:
-+class TwistedPropertyChecker(object):
- implements(checkers.ICredentialsChecker)
-
- credentialInterfaces = (IPrincipalCredentials,)
-
-- def _cbPasswordMatch(self, matched, principalURI):
-+ def _cbPasswordMatch(self, matched, principalURIs):
- if matched:
-- return principalURI
-+ # We return both URIs
-+ return principalURIs
- else:
-- raise error.UnauthorizedLogin(
-- "Bad credentials for: %s" % (principalURI,))
-+ raise error.UnauthorizedLogin("Bad credentials for: %s" % (principalURIs[0],))
-
- def requestAvatarId(self, credentials):
- pcreds = IPrincipalCredentials(credentials)
-- pswd = str(pcreds.principal.readDeadProperty(TwistedPasswordProperty))
-+ pswd = str(pcreds.authnPrincipal.readDeadProperty(TwistedPasswordProperty))
-
- d = defer.maybeDeferred(credentials.checkPassword, pswd)
-- d.addCallback(self._cbPasswordMatch, pcreds.principalURI)
-+ d.addCallback(self._cbPasswordMatch, (pcreds.authnPrincipal.principalURL(), pcreds.authzPrincipal.principalURL()))
- return d
-
- ##
Deleted: CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.davxml.patch
===================================================================
--- CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.davxml.patch 2009-05-01 17:16:27 UTC (rev 4129)
+++ CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.davxml.patch 2009-05-01 17:19:57 UTC (rev 4130)
@@ -1,30 +0,0 @@
-Index: twisted/web2/dav/davxml.py
-===================================================================
---- twisted/web2/dav/davxml.py (revision 19773)
-+++ twisted/web2/dav/davxml.py (working copy)
-@@ -45,6 +45,8 @@
- from twisted.web2.dav.element.rfc2518 import *
- from twisted.web2.dav.element.rfc3253 import *
- from twisted.web2.dav.element.rfc3744 import *
-+from twisted.web2.dav.element.rfc4331 import *
-+from twisted.web2.dav.element.extensions import *
-
- #
- # Register all XML elements with the parser
-@@ -56,11 +58,15 @@
- import twisted.web2.dav.element.rfc2518
- import twisted.web2.dav.element.rfc3253
- import twisted.web2.dav.element.rfc3744
-+import twisted.web2.dav.element.rfc4331
-+import twisted.web2.dav.element.extensions
-
- __all__ = (
- registerElements(twisted.web2.dav.element.base ) +
- registerElements(twisted.web2.dav.element.parser ) +
- registerElements(twisted.web2.dav.element.rfc2518) +
- registerElements(twisted.web2.dav.element.rfc3253) +
-- registerElements(twisted.web2.dav.element.rfc3744)
-+ registerElements(twisted.web2.dav.element.rfc3744) +
-+ registerElements(twisted.web2.dav.element.rfc4331) +
-+ registerElements(twisted.web2.dav.element.extensions)
- )
Deleted: CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.element.__init__.patch
===================================================================
--- CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.element.__init__.patch 2009-05-01 17:16:27 UTC (rev 4129)
+++ CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.element.__init__.patch 2009-05-01 17:19:57 UTC (rev 4130)
@@ -1,11 +0,0 @@
-Index: twisted/web2/dav/element/__init__.py
-===================================================================
---- twisted/web2/dav/element/__init__.py (revision 19773)
-+++ twisted/web2/dav/element/__init__.py (working copy)
-@@ -35,4 +35,6 @@
- "rfc2518",
- "rfc3253",
- "rfc3744",
-+ "rfc4331",
-+ "extensions",
- ]
Deleted: CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.element.base.patch
===================================================================
--- CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.element.base.patch 2009-05-01 17:16:27 UTC (rev 4129)
+++ CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.element.base.patch 2009-05-01 17:19:57 UTC (rev 4130)
@@ -1,267 +0,0 @@
-Index: twisted/web2/dav/element/base.py
-===================================================================
---- twisted/web2/dav/element/base.py (revision 19773)
-+++ twisted/web2/dav/element/base.py (working copy)
-@@ -45,7 +45,7 @@
- ]
-
- import string
--import StringIO
-+import cStringIO as StringIO
- import xml.dom.minidom
-
- import datetime
-@@ -90,6 +90,35 @@
- raise NotImplementedError("WebDAVElement subclass %s is not implemented."
- % (self.__class__.__name__,))
-
-+ my_children = []
-+
-+ allowPCDATA = self.allowed_children.has_key(PCDATAElement)
-+
-+ for child in children:
-+ if child is None:
-+ continue
-+
-+ if isinstance(child, (str, unicode)):
-+ child = PCDATAElement(child)
-+
-+ if isinstance(child, PCDATAElement) and not allowPCDATA:
-+ continue
-+
-+ my_children.append(child)
-+
-+ self.children = tuple(my_children)
-+
-+ self.attributes = attributes
-+
-+ def validate(self):
-+
-+ children = self.children
-+ attributes = self.attributes
-+
-+ if self.allowed_children is None:
-+ raise NotImplementedError("WebDAVElement subclass %s is not implemented."
-+ % (self.__class__.__name__,))
-+
- #
- # Validate that children are of acceptable types
- #
-@@ -102,13 +131,10 @@
- my_children = []
-
- for child in children:
-- if child is None:
-- continue
-
-- if isinstance(child, (str, unicode)):
-- child = PCDATAElement(child)
--
- assert isinstance(child, (WebDAVElement, PCDATAElement)), "Not an element: %r" % (child,)
-+
-+ child.validate()
-
- for allowed, (min, max) in allowed_children.items():
- if type(allowed) == type and isinstance(child, allowed):
-@@ -145,24 +171,26 @@
-
- if self.allowed_attributes:
- for name in attributes:
-- if name in self.allowed_attributes:
-- my_attributes[name] = attributes[name]
-- else:
-- log.msg("Attribute %s is unexpected and therefore ignored in %s element"
-- % (name, self.sname()))
-+ if name not in self.allowed_attributes:
-+ log.msg("Attribute %s is unexpected in %s element" % (name, self.sname()))
-+ my_attributes[name] = attributes[name]
-
- for name, required in self.allowed_attributes.items():
- if required and name not in my_attributes:
- raise ValueError("Attribute %s is required in %s element"
- % (name, self.sname()))
-
-- elif not isinstance(self, WebDAVUnknownElement):
-- if attributes:
-- log.msg("Attributes %s are unexpected and therefore ignored in %s element"
-+ else:
-+ if not isinstance(self, WebDAVUnknownElement) and attributes:
-+ log.msg("Attributes %s are unexpected in %s element"
- % (attributes.keys(), self.sname()))
-+ my_attributes.update(attributes)
-
- self.attributes = my_attributes
-
-+ def emptyCopy(self):
-+ return self.__class__()
-+
- def __str__(self):
- return self.sname()
-
-@@ -190,14 +218,93 @@
- return child in self.children
-
- def writeXML(self, output):
-- document = xml.dom.minidom.Document()
-- self.addToDOM(document, None)
-- PrintXML(document, stream=output)
-+ # FIXME: Now have a 'fast' write implementation as well as previous PyXML-based one.
-+ # For now the fast one is the default and we will test to see if its good enough.
-+
-+ usePyXML = False
-+ if usePyXML:
-+ document = xml.dom.minidom.Document()
-+ self.addToDOM(document, None)
-+ PrintXML(document, stream=output)
-+ else:
-+ output.write("<?xml version='1.0' encoding='UTF-8'?>\r\n")
-+ self.writeToStream(output, "", 0, True)
-+ output.write("\r\n")
-+
-+ def writeToStream(self, output, ns, level, pretty):
-+ """
-+ Fast XML output.
-
-+ @param output: C{stream} to write to.
-+ @param ns: C{str} containing the namespace of the enclosing element.
-+ @param level: C{int} containing the element nesting level (starts at 0).
-+ @param pretty: C{bool} whether to use 'pretty' formatted output or not.
-+ """
-+
-+ # Do pretty indent
-+ if pretty and level:
-+ output.write(" " * level)
-+
-+ # Check for empty element (one with either no children or a single PCDATA that is itself empty)
-+ if (len(self.children) == 0 or
-+ (len(self.children) == 1 and isinstance(self.children[0], PCDATAElement) and len(str(self.children[0])) == 0)):
-+
-+ # Write out any attributes or the namespace if difference from enclosing element.
-+ if self.attributes or (ns != self.namespace):
-+ output.write("<%s" % (self.name,))
-+ for name, value in self.attributes.iteritems():
-+ self.writeAttributeToStream(output, name, value)
-+ if ns != self.namespace:
-+ output.write(" xmlns='%s'" % (self.namespace,))
-+ output.write("/>")
-+ else:
-+ output.write("<%s/>" % (self.name,))
-+ else:
-+ # Write out any attributes or the namespace if difference from enclosing element.
-+ if self.attributes or (ns != self.namespace):
-+ output.write("<%s" % (self.name,))
-+ for name, value in self.attributes.iteritems():
-+ self.writeAttributeToStream(output, name, value)
-+ if ns != self.namespace:
-+ output.write(" xmlns='%s'" % (self.namespace,))
-+ ns = self.namespace
-+ output.write(">")
-+ else:
-+ output.write("<%s>" % (self.name,))
-+
-+ # Determine nature of children when doing pretty print: we do
-+ # not want to insert CRLFs or any other whitespace in PCDATA.
-+ hasPCDATA = False
-+ for child in self.children:
-+ if isinstance(child, PCDATAElement):
-+ hasPCDATA = True
-+ break
-+
-+ # Write out the children.
-+ if pretty and not hasPCDATA:
-+ output.write("\r\n")
-+ for child in self.children:
-+ child.writeToStream(output, ns, level+1, pretty)
-+
-+ # Close the element.
-+ if pretty and not hasPCDATA and level:
-+ output.write(" " * level)
-+ output.write("</%s>" % (self.name,))
-+
-+ if pretty and level:
-+ output.write("\r\n")
-+
-+ def writeAttributeToStream(self, output, name, value):
-+
-+ # Quote any single quotes. We do not need to be any smarter than this.
-+ value = value.replace("'", "'")
-+
-+ output.write(" %s='%s'" % (name, value,))
-+
- def toxml(self):
- output = StringIO.StringIO()
- self.writeXML(output)
-- return output.getvalue()
-+ return str(output.getvalue())
-
- def element(self, document):
- element = document.createElementNS(self.namespace, self.name)
-@@ -285,6 +392,9 @@
-
- self.data = data
-
-+ def validate(self):
-+ pass
-+
- def __str__(self):
- return str(self.data)
-
-@@ -324,6 +434,22 @@
- log.err("Invalid PCDATA: %r" % (self.data,))
- raise
-
-+ def writeToStream(self, output, ns, level, pretty):
-+ # Do escaping/CDATA behavior
-+ if "\r" in self.data or "\n" in self.data:
-+ # Do CDATA
-+ cdata = "<![CDATA[%s]]>" % (self.data.replace("]]>", "]]>"),)
-+ else:
-+ cdata = self.data
-+ if "&" in cdata:
-+ cdata = cdata.replace("&", "&")
-+ if "<" in cdata:
-+ cdata = cdata.replace("<", "<")
-+ if ">" in cdata:
-+ cdata = cdata.replace(">", ">")
-+
-+ output.write(cdata)
-+
- class WebDAVOneShotElement (WebDAVElement):
- """
- Element with exactly one WebDAVEmptyElement child and no attributes.
-@@ -364,6 +490,18 @@
- PCDATAElement: (0, None),
- }
-
-+ def qname(self):
-+ return (self.namespace, self.name)
-+
-+ def sname(self):
-+ return "{%s}%s" % (self.namespace, self.name)
-+
-+ def emptyCopy(self):
-+ copied = self.__class__()
-+ copied.name = self.name
-+ copied.namespace = self.namespace
-+ return copied
-+
- class WebDAVEmptyElement (WebDAVElement):
- """
- WebDAV element with no contents.
-@@ -388,6 +526,7 @@
- """
- WebDAV element containing PCDATA.
- """
-+ @classmethod
- def fromString(clazz, string):
- if string is None:
- return clazz()
-@@ -396,8 +535,6 @@
- else:
- return clazz(PCDATAElement(str(string)))
-
-- fromString = classmethod(fromString)
--
- allowed_children = { PCDATAElement: (0, None) }
-
- def __str__(self):
Deleted: CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.element.extensions.patch
===================================================================
--- CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.element.extensions.patch 2009-05-01 17:16:27 UTC (rev 4129)
+++ CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.element.extensions.patch 2009-05-01 17:19:57 UTC (rev 4130)
@@ -1,44 +0,0 @@
-Index: twisted/web2/dav/element/extensions.py
-===================================================================
---- twisted/web2/dav/element/extensions.py (revision 0)
-+++ twisted/web2/dav/element/extensions.py (revision 0)
-@@ -0,0 +1,39 @@
-+##
-+# Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
-+#
-+# Permission is hereby granted, free of charge, to any person obtaining a copy
-+# of this software and associated documentation files (the "Software"), to deal
-+# in the Software without restriction, including without limitation the rights
-+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-+# copies of the Software, and to permit persons to whom the Software is
-+# furnished to do so, subject to the following conditions:
-+#
-+# The above copyright notice and this permission notice shall be included in all
-+# copies or substantial portions of the Software.
-+#
-+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-+# SOFTWARE.
-+#
-+##
-+
-+from twisted.web2.dav.element.base import *
-+
-+##
-+# draft-sanchez-webdav-current-principal
-+##
-+
-+class CurrentUserPrincipal(WebDAVElement):
-+ """
-+ Current principal information
-+ """
-+
-+ name = "current-user-principal"
-+ allowed_children = {
-+ (dav_namespace, "href" ) : (0, 1),
-+ (dav_namespace, "unauthenticated" ) : (0, 1),
-+ }
Deleted: CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.element.parser.patch
===================================================================
--- CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.element.parser.patch 2009-05-01 17:16:27 UTC (rev 4129)
+++ CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.element.parser.patch 2009-05-01 17:19:57 UTC (rev 4130)
@@ -1,81 +0,0 @@
-Index: twisted/web2/dav/element/parser.py
-===================================================================
---- twisted/web2/dav/element/parser.py (revision 19773)
-+++ twisted/web2/dav/element/parser.py (working copy)
-@@ -37,7 +37,7 @@
- "WebDAVDocument",
- ]
-
--import StringIO
-+import cStringIO as StringIO
- import xml.dom.minidom
- import xml.sax
-
-@@ -106,6 +106,12 @@
- "children" : [],
- }]
-
-+ # Keep a cache of the subclasses we create for unknown XML
-+ # elements, so that we don't create multiple classes for the
-+ # same element; it's fairly typical for elements to appear
-+ # multiple times in a document.
-+ self.unknownElementClasses = {}
-+
- def endDocument(self):
- top = self.stack[-1]
-
-@@ -115,6 +121,7 @@
- assert len(top["children"]) is 1, "Must have exactly one root element, got %d" % len(top["children"])
-
- self.dom = WebDAVDocument(top["children"][0])
-+ del(self.unknownElementClasses)
-
- def startElementNS(self, name, qname, attributes):
- attributes_dict = {}
-@@ -125,13 +132,17 @@
-
- tag_namespace, tag_name = name
-
-- if (name not in elements_by_tag_name):
-- class UnknownElement (WebDAVUnknownElement):
-- namespace = tag_namespace
-- name = tag_name
-- element_class = UnknownElement
-+ if name in elements_by_tag_name:
-+ element_class = elements_by_tag_name[name]
-+ elif name in self.unknownElementClasses:
-+ element_class = self.unknownElementClasses[name]
- else:
-- element_class = elements_by_tag_name[name]
-+ def element_class(*args, **kwargs):
-+ element = WebDAVUnknownElement(*args, **kwargs)
-+ element.namespace = tag_namespace
-+ element.name = tag_name
-+ return element
-+ self.unknownElementClasses[name] = element_class
-
- self.stack.append({
- "name" : name,
-@@ -158,7 +169,12 @@
- self.stack[-1]["children"].append(element)
-
- def characters(self, content):
-- self.stack[-1]["children"].append(PCDATAElement(content))
-+ # Coalesce adjacent PCDATAElements
-+ pcdata = PCDATAElement(content)
-+ if len(self.stack[-1]["children"]) and isinstance(self.stack[-1]["children"][-1], PCDATAElement):
-+ self.stack[-1]["children"][-1] = self.stack[-1]["children"][-1] + pcdata
-+ else:
-+ self.stack[-1]["children"].append(pcdata)
-
- def ignorableWhitespace(self, whitespace):
- self.characters(self, whitespace)
-@@ -194,6 +210,8 @@
- except xml.sax.SAXParseException, e:
- raise ValueError(e)
-
-+ #handler.dom.root_element.validate()
-+
- return handler.dom
-
- return parse
Deleted: CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.element.rfc2518.patch
===================================================================
--- CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.element.rfc2518.patch 2009-05-01 17:16:27 UTC (rev 4129)
+++ CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.element.rfc2518.patch 2009-05-01 17:19:57 UTC (rev 4130)
@@ -1,37 +0,0 @@
-Index: twisted/web2/dav/element/rfc2518.py
-===================================================================
---- twisted/web2/dav/element/rfc2518.py (revision 19773)
-+++ twisted/web2/dav/element/rfc2518.py (working copy)
-@@ -59,8 +59,8 @@
- """
- name = "depth"
-
-- def __init__(self, *children, **attributes):
-- super(Depth, self).__init__(*children, **attributes)
-+ def validate(self):
-+ super(Depth, self).validate()
-
- depth = str(self)
- if depth not in ("0", "1", "infinity"):
-@@ -382,8 +382,8 @@
- PCDATAElement: (0, 1),
- }
-
-- def __init__(self, *children, **attributes):
-- super(KeepAlive, self).__init__(*children, **attributes)
-+ def validate(self):
-+ super(KeepAlive, self).validate()
-
- type = None
-
-@@ -450,8 +450,8 @@
- (dav_namespace, "prop" ): (0, 1),
- }
-
-- def __init__(self, *children, **attributes):
-- super(PropertyFind, self).__init__(*children, **attributes)
-+ def validate(self):
-+ super(PropertyFind, self).validate()
-
- if len(self.children) != 1:
- raise ValueError(
Deleted: CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.element.rfc3744.patch
===================================================================
--- CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.element.rfc3744.patch 2009-05-01 17:16:27 UTC (rev 4129)
+++ CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.element.rfc3744.patch 2009-05-01 17:19:57 UTC (rev 4130)
@@ -1,102 +0,0 @@
-Index: twisted/web2/dav/element/rfc3744.py
-===================================================================
---- twisted/web2/dav/element/rfc3744.py (revision 19773)
-+++ twisted/web2/dav/element/rfc3744.py (working copy)
-@@ -131,8 +131,8 @@
- (dav_namespace, "self" ): (0, 1),
- }
-
-- def __init__(self, *children, **attributes):
-- super(Principal, self).__init__(*children, **attributes)
-+ def validate(self):
-+ super(Principal, self).validate()
-
- if len(self.children) > 1:
- raise ValueError(
-@@ -385,9 +385,14 @@
- self.inherited = None
- self.protected = False
-
-+ my_children = []
-+
- for child in self.children:
- namespace, name = child.qname()
-
-+ if isinstance(child, PCDATAElement):
-+ continue
-+
- if (namespace == dav_namespace):
- if name in ("principal", "invert"):
- if self.principal is not None:
-@@ -417,6 +422,10 @@
- elif name == "protected":
- self.protected = True
-
-+ my_children.append(child)
-+
-+ self.children = tuple(my_children)
-+
- if self.principal is None:
- raise ValueError(
- "One of DAV:principal or DAV:invert is required in %s, got: %s"
-@@ -456,7 +465,7 @@
- """
- name = "self"
-
--class Invert (WebDAVEmptyElement):
-+class Invert (WebDAVElement):
- """
- Principal which matches a user if the user does not match the principal
- contained by this principal. (RFC 3744, section 5.5.1)
-@@ -551,8 +560,8 @@
- (dav_namespace, "property" ): (0, None),
- }
-
-- def __init__(self, *children, **attributes):
-- super(RequiredPrincipal, self).__init__(*children, **attributes)
-+ def validate(self):
-+ super(RequiredPrincipal, self).validate()
-
- type = None
-
-@@ -628,8 +637,8 @@
-
- allowed_children = { WebDAVElement: (0, None) }
-
-- def __init__(self, *children, **attributes):
-- super(ACLPrincipalPropSet, self).__init__(*children, **attributes)
-+ def validate(self):
-+ super(ACLPrincipalPropSet, self).validate()
-
- prop = False
-
-@@ -656,8 +665,8 @@
- (dav_namespace, "prop" ): (0, 1),
- }
-
-- def __init__(self, *children, **attributes):
-- super(PrincipalMatch, self).__init__(*children, **attributes)
-+ def validate(self):
-+ super(PrincipalMatch, self).validate()
-
- # This element can be empty when uses in supported-report-set
- if not len(self.children):
-@@ -705,6 +714,7 @@
- (dav_namespace, "prop" ): (0, 1),
- (dav_namespace, "apply-to-principal-collection-set"): (0, 1),
- }
-+ allowed_attributes = { "test": False }
-
- class PropertySearch (WebDAVElement):
- """
-@@ -745,4 +755,10 @@
- (dav_namespace, "description"): (1, 1),
- }
-
-+class NumberOfMatchesWithinLimits (WebDAVEmptyElement):
-+ """
-+ Error which indicates too many results
-+ """
-+ name = "number-of-matches-within-limits"
-+
- # For DAV:description element (RFC 3744, section 9.5) see Description class above.
Deleted: CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.element.rfc4331.patch
===================================================================
--- CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.element.rfc4331.patch 2009-05-01 17:16:27 UTC (rev 4129)
+++ CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.element.rfc4331.patch 2009-05-01 17:19:57 UTC (rev 4130)
@@ -1,60 +0,0 @@
-Index: twisted/web2/dav/element/rfc4331.py
-===================================================================
---- twisted/web2/dav/element/rfc4331.py (revision 0)
-+++ twisted/web2/dav/element/rfc4331.py (revision 0)
-@@ -0,0 +1,55 @@
-+##
-+# Copyright (c) 2005-2007 Apple Inc. All rights reserved.
-+#
-+# Permission is hereby granted, free of charge, to any person obtaining a copy
-+# of this software and associated documentation files (the "Software"), to deal
-+# in the Software without restriction, including without limitation the rights
-+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-+# copies of the Software, and to permit persons to whom the Software is
-+# furnished to do so, subject to the following conditions:
-+#
-+# The above copyright notice and this permission notice shall be included in all
-+# copies or substantial portions of the Software.
-+#
-+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-+# SOFTWARE.
-+#
-+# DRI: Cyrus Daboo, cdaboo at apple.com
-+##
-+
-+"""
-+RFC 4331 (Quota and Size Properties for WebDAV Collections) XML Elements
-+
-+This module provides XML element definitions for use with WebDAV.
-+
-+See RFC 4331: http://www.ietf.org/rfc/rfc4331.txt
-+"""
-+
-+from twisted.web2.dav.element.base import WebDAVTextElement
-+
-+##
-+# Section 3 & 4 (Quota Properties)
-+##
-+
-+class QuotaAvailableBytes (WebDAVTextElement):
-+ """
-+ Property which contains the the number of bytes available under the
-+ current quota to store data in a collection (RFC 4331, section 3)
-+ """
-+ name = "quota-available-bytes"
-+ hidden = True
-+ protected = True
-+
-+class QuotaUsedBytes (WebDAVTextElement):
-+ """
-+ Property which contains the the number of bytes used under the
-+ current quota to store data in a collection (RFC 4331, section 4)
-+ """
-+ name = "quota-used-bytes"
-+ hidden = True
-+ protected = True
Deleted: CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.fileop.patch
===================================================================
--- CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.fileop.patch 2009-05-01 17:16:27 UTC (rev 4129)
+++ CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.fileop.patch 2009-05-01 17:19:57 UTC (rev 4130)
@@ -1,31 +0,0 @@
-Index: twisted/web2/dav/fileop.py
-===================================================================
---- twisted/web2/dav/fileop.py (revision 19773)
-+++ twisted/web2/dav/fileop.py (working copy)
-@@ -35,6 +35,7 @@
- "move",
- "put",
- "mkcollection",
-+ "rmdir",
- ]
-
- import os
-@@ -287,7 +288,7 @@
- response = waitForDeferred(copy(FilePath(source_path), FilePath(destination_path), destination_uri, depth))
- yield response
- response = response.getResult()
-- checkResponse(response, "copy", responsecode.NO_CONTENT)
-+ checkResponse(response, "copy", responsecode.CREATED, responsecode.NO_CONTENT)
-
- for subdir in subdirs:
- source_path, destination_path = paths(dir, subdir)
-@@ -509,7 +510,5 @@
- os.rmdir(dirname)
-
- def checkResponse(response, method, *codes):
-- assert (
-- response in codes,
-- "%s() should have raised, but returned one of %r instead" % (method, codes)
-- )
-+ assert response in codes, \
-+ "%s() returned %r, but should have returned one of %r instead" % (method, response, codes)
Deleted: CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.http.patch
===================================================================
--- CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.http.patch 2009-05-01 17:16:27 UTC (rev 4129)
+++ CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.http.patch 2009-05-01 17:19:57 UTC (rev 4130)
@@ -1,41 +0,0 @@
-Index: twisted/web2/dav/http.py
-===================================================================
---- twisted/web2/dav/http.py (revision 19773)
-+++ twisted/web2/dav/http.py (working copy)
-@@ -28,10 +28,13 @@
-
- __all__ = [
- "ErrorResponse",
-+ "NeedPrivilegesResponse",
- "MultiStatusResponse",
- "ResponseQueue",
- "PropertyStatusResponseQueue",
- "statusForFailure",
-+ "errorForFailure",
-+ "messageForFailure",
- ]
-
- import errno
-@@ -69,10 +72,9 @@
- """
- if type(error) is tuple:
- xml_namespace, xml_name = error
-- class EmptyError (davxml.WebDAVEmptyElement):
-- namespace = xml_namespace
-- name = xml_name
-- error = EmptyError()
-+ error = davxml.WebDAVUnknownElement()
-+ error.namespace = xml_namespace
-+ error.name = xml_name
-
- output = davxml.Error(error).toxml()
-
-@@ -227,7 +229,7 @@
-
- if len(property.children) > 0:
- # Re-instantiate as empty element.
-- property = property.__class__()
-+ property = property.emptyCopy()
-
- if code > 400: # Error codes only
- log.err("Error during %s for %s: %s" % (self.method, property, message))
Deleted: CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.idav.patch
===================================================================
--- CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.idav.patch 2009-05-01 17:16:27 UTC (rev 4129)
+++ CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.idav.patch 2009-05-01 17:19:57 UTC (rev 4130)
@@ -1,157 +0,0 @@
-Index: twisted/web2/dav/idav.py
-===================================================================
---- twisted/web2/dav/idav.py (revision 19773)
-+++ twisted/web2/dav/idav.py (working copy)
-@@ -26,7 +26,7 @@
- web2.dav interfaces.
- """
-
--__all__ = [ "IDAVResource", "IDAVPrincipalResource" ]
-+__all__ = [ "IDAVResource", "IDAVPrincipalResource", "IDAVPrincipalCollectionResource", ]
-
- from twisted.web2.iweb import IResource
-
-@@ -41,7 +41,7 @@
- otherwise.
- """
-
-- def findChildren(depth, request, callback, privileges):
-+ def findChildren(depth, request, callback, privileges, inherited_aces):
- """
- Returns an iterable of child resources for the given depth.
- Because resources do not know their request URIs, chidren are returned
-@@ -52,6 +52,8 @@
- @param callback: C{callable} that will be called for each child found
- @param privileges: the list of L{Privilege}s to test for. This should
- default to None.
-+ @param inherited_aces: a list of L{Privilege}s for aces being inherited from
-+ the parent collection used to bypass inheritance lookup.
- @return: An L{Deferred} that fires when all the children have been found
- """
-
-@@ -125,15 +127,10 @@
- L{responsecode.UNAUTHORIZED}) if not authorized.
- """
-
-- def principalCollections(request):
-+ def principalCollections():
- """
-- Provides the DAV:HRef's of collection resources which contain principal
-- resources which may be used in access control entries on this resource.
-- (RFC 3744, section 5.8)
-- @param request: the request being processed.
-- @return: a deferred sequence of L{davxml.HRef}s referring to
-- collection resources which implement the
-- C{DAV:principal-property-search} C{REPORT}.
-+ @return: an interable of L{IDAVPrincipalCollectionResource}s which
-+ contain principals used in ACLs for this resource.
- """
-
- def setAccessControlList(acl):
-@@ -180,6 +177,80 @@
- the specified principal.
- """
-
-+ ##
-+ # Quota
-+ ##
-+
-+ def quota(request):
-+ """
-+ Get current available & used quota values for this resource's quota root
-+ collection.
-+
-+ @return: a 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.
-+ """
-+
-+ def hasQuota(request):
-+ """
-+ Check whether this resource is undre quota control by checking each parent to see if
-+ it has a quota root.
-+
-+ @return: C{True} if under quota control, C{False} if not.
-+ """
-+
-+ def hasQuotaRoot(request):
-+ """
-+ Determine whether the resource has a quota root.
-+
-+ @return: a C{True} if this resource has quota root, C{False} otherwise.
-+ """
-+
-+
-+ def quotaRoot(request):
-+ """
-+ Get the quota root (max. allowed bytes) value for this collection.
-+
-+ @return: a C{int} containing the maximum allowed bytes if this collection
-+ is quota-controlled, or C{None} if not quota controlled.
-+ """
-+
-+ def setQuotaRoot(request, maxsize):
-+ """
-+ Set the quota root (max. allowed bytes) value for this collection.
-+
-+ @param maxsize: a C{int} containing the maximum allowed bytes for the contents
-+ of this collection.
-+ """
-+
-+ def quotaSize(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 L{Deferred} with a C{int} result containing the size of the resource.
-+ """
-+
-+ def currentQuotaUse(request):
-+ """
-+ Get the cached quota use value, or if not present (or invalid) determine
-+ quota use by brute force.
-+
-+ @return: an L{Deferred} with a C{int} result containing the current used byte count if
-+ this collection is quota-controlled, or C{None} if not quota controlled.
-+ """
-+
-+ def updateQuotaUse(request, adjust):
-+ """
-+ Adjust current quota use on this all all parent collections that also
-+ have quota roots.
-+
-+ @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: an L{Deferred} with a C{int} result containing the current used byte if this collection
-+ is quota-controlled, or C{None} if not quota controlled.
-+ """
-+
- class IDAVPrincipalResource (IDAVResource):
- """
- WebDAV principal resource. (RFC 3744, section 2)
-@@ -203,12 +274,23 @@
- """
- Provides the principal URLs of principals that are direct members of
- this (group) principal. (RFC 3744, section 4.3)
-- @return: a iterable of principal URLs.
-+ @return: a deferred returning an iterable of principal URLs.
- """
-
- def groupMemberships():
- """
- Provides the URLs of the group principals in which the principal is
- directly a member. (RFC 3744, section 4.4)
-- @return: a iterable of group principal URLs.
-+ @return: a deferred containing an iterable of group principal URLs.
- """
-+
-+class IDAVPrincipalCollectionResource (IDAVResource):
-+ """
-+ WebDAV principal collection resource. (RFC 3744, section 5.8)
-+ """
-+ def principalCollectionURL():
-+ """
-+ Provides a URL for this resource which may be used to identify this
-+ resource in ACL requests. (RFC 3744, section 5.8)
-+ @return: a URL.
-+ """
Deleted: CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.method.__init__.patch
===================================================================
--- CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.method.__init__.patch 2009-05-01 17:16:27 UTC (rev 4129)
+++ CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.method.__init__.patch 2009-05-01 17:19:57 UTC (rev 4130)
@@ -1,12 +0,0 @@
-Index: twisted/web2/dav/method/__init__.py
-===================================================================
---- twisted/web2/dav/method/__init__.py (revision 19773)
-+++ twisted/web2/dav/method/__init__.py (working copy)
-@@ -40,6 +40,7 @@
- "proppatch",
- "prop_common",
- "put",
-+ "put_common",
- "report",
- "report_acl_principal_prop_set",
- "report_expand",
Deleted: CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.method.copymove.patch
===================================================================
--- CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.method.copymove.patch 2009-05-01 17:16:27 UTC (rev 4129)
+++ CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.method.copymove.patch 2009-05-01 17:19:57 UTC (rev 4130)
@@ -1,76 +0,0 @@
-Index: twisted/web2/dav/method/copymove.py
-===================================================================
---- twisted/web2/dav/method/copymove.py (revision 19773)
-+++ twisted/web2/dav/method/copymove.py (working copy)
-@@ -34,11 +34,12 @@
- from twisted.python import log
- from twisted.internet.defer import waitForDeferred, deferredGenerator
- from twisted.web2 import responsecode
-+from twisted.web2.dav.fileop import move
- from twisted.web2.http import HTTPError, StatusResponse
- from twisted.web2.filter.location import addLocation
- from twisted.web2.dav import davxml
- from twisted.web2.dav.idav import IDAVResource
--from twisted.web2.dav.fileop import copy, move
-+from twisted.web2.dav.method import put_common
- from twisted.web2.dav.util import parentForURL
-
- # FIXME: This is circular
-@@ -81,7 +82,15 @@
- # May need to add a location header
- addLocation(request, destination_uri)
-
-- x = waitForDeferred(copy(self.fp, destination.fp, destination_uri, depth))
-+ #x = waitForDeferred(copy(self.fp, destination.fp, destination_uri, depth))
-+ x = waitForDeferred(put_common.storeResource(request,
-+ source=self,
-+ source_uri=request.uri,
-+ destination=destination,
-+ destination_uri=destination_uri,
-+ deletesource=False,
-+ depth=depth
-+ ))
- yield x
- yield x.getResult()
-
-@@ -100,7 +109,8 @@
- #
- # Check authentication and access controls
- #
-- parent = waitForDeferred(request.locateResource(parentForURL(request.uri)))
-+ parentURL = parentForURL(request.uri)
-+ parent = waitForDeferred(request.locateResource(parentURL))
- yield parent
- parent = parent.getResult()
-
-@@ -117,7 +127,8 @@
- yield x
- x.getResult()
- else:
-- destparent = waitForDeferred(request.locateResource(parentForURL(destination_uri)))
-+ destparentURL = parentForURL(destination_uri)
-+ destparent = waitForDeferred(request.locateResource(destparentURL))
- yield destparent
- destparent = destparent.getResult()
-
-@@ -144,7 +155,19 @@
- log.err(msg)
- raise HTTPError(StatusResponse(responsecode.BAD_REQUEST, msg))
-
-- x = waitForDeferred(move(self.fp, request.uri, destination.fp, destination_uri, depth))
-+ # Lets optimise a move within the same directory to a new resource as a simple move
-+ # rather than using the full transaction based storeResource api. This allows simple
-+ # "rename" operations to work quickly.
-+ if (not destination.exists()) and destparent == parent:
-+ x = waitForDeferred(move(self.fp, request.uri, destination.fp, destination_uri, depth))
-+ else:
-+ x = waitForDeferred(put_common.storeResource(request,
-+ source=self,
-+ source_uri=request.uri,
-+ destination=destination,
-+ destination_uri=destination_uri,
-+ deletesource=True,
-+ depth=depth))
- yield x
- yield x.getResult()
-
Deleted: CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.method.delete.patch
===================================================================
--- CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.method.delete.patch 2009-05-01 17:16:27 UTC (rev 4129)
+++ CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.method.delete.patch 2009-05-01 17:19:57 UTC (rev 4130)
@@ -1,34 +0,0 @@
-Index: twisted/web2/dav/method/delete.py
-===================================================================
---- twisted/web2/dav/method/delete.py (revision 19773)
-+++ twisted/web2/dav/method/delete.py (working copy)
-@@ -58,8 +58,28 @@
- yield x
- x.getResult()
-
-+ # Do quota checks before we start deleting things
-+ myquota = waitForDeferred(self.quota(request))
-+ yield myquota
-+ myquota = myquota.getResult()
-+ if myquota is not None:
-+ old_size = waitForDeferred(self.quotaSize(request))
-+ yield old_size
-+ old_size = old_size.getResult()
-+ else:
-+ old_size = 0
-+
-+ # Do delete
- x = waitForDeferred(delete(request.uri, self.fp, depth))
- yield x
-- yield x.getResult()
-+ result = x.getResult()
-
-+ # Adjust quota
-+ if myquota is not None:
-+ d = waitForDeferred(self.quotaSizeAdjust(request, -old_size))
-+ yield d
-+ d.getResult()
-+
-+ yield result
-+
- http_DELETE = deferredGenerator(http_DELETE)
Deleted: CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.method.prop_common.patch
===================================================================
--- CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.method.prop_common.patch 2009-05-01 17:16:27 UTC (rev 4129)
+++ CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.method.prop_common.patch 2009-05-01 17:19:57 UTC (rev 4130)
@@ -1,36 +0,0 @@
-Index: twisted/web2/dav/method/prop_common.py
-===================================================================
---- twisted/web2/dav/method/prop_common.py (revision 19773)
-+++ twisted/web2/dav/method/prop_common.py (working copy)
-@@ -23,19 +23,21 @@
- properties_by_status = waitForDeferred(propertiesForResource(request, propertyreq, resource))
- yield properties_by_status
- properties_by_status = properties_by_status.getResult()
--
-+
-+ propstats = []
-+
- for status in properties_by_status:
- properties = properties_by_status[status]
- if properties:
-- responses.append(
-- davxml.PropertyStatusResponse(
-- href,
-- davxml.PropertyStatus(
-- davxml.PropertyContainer(*properties),
-- davxml.Status.fromResponseCode(status)
-- )
-- )
-- )
-+ xml_status = davxml.Status.fromResponseCode(status)
-+ xml_container = davxml.PropertyContainer(*properties)
-+ xml_propstat = davxml.PropertyStatus(xml_container, xml_status)
-+
-+ propstats.append(xml_propstat)
-+
-+ if propstats:
-+ responses.append(davxml.PropertyStatusResponse(href, *propstats))
-+
- else:
- responses.append(
- davxml.StatusResponse(
Deleted: CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.method.propfind.patch
===================================================================
--- CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.method.propfind.patch 2009-05-01 17:16:27 UTC (rev 4129)
+++ CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.method.propfind.patch 2009-05-01 17:19:57 UTC (rev 4130)
@@ -1,28 +0,0 @@
-Index: twisted/web2/dav/method/propfind.py
-===================================================================
---- twisted/web2/dav/method/propfind.py (revision 19773)
-+++ twisted/web2/dav/method/propfind.py (working copy)
-@@ -27,7 +27,10 @@
- WebDAV PROPFIND method
- """
-
--__all__ = ["http_PROPFIND"]
-+__all__ = [
-+ "http_PROPFIND",
-+ "propertyName",
-+]
-
- from twisted.python import log
- from twisted.python.failure import Failure
-@@ -200,7 +203,7 @@
-
- def propertyName(name):
- property_namespace, property_name = name
-- class PropertyName (davxml.WebDAVEmptyElement):
-- namespace = property_namespace
-- name = property_name
-- return PropertyName()
-+ pname = davxml.WebDAVUnknownElement()
-+ pname.namespace = property_namespace
-+ pname.name = property_name
-+ return pname
Deleted: CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.method.put.patch
===================================================================
--- CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.method.put.patch 2009-05-01 17:16:27 UTC (rev 4129)
+++ CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.method.put.patch 2009-05-01 17:19:57 UTC (rev 4130)
@@ -1,20 +0,0 @@
-Index: twisted/web2/dav/method/put.py
-===================================================================
---- twisted/web2/dav/method/put.py (revision 19773)
-+++ twisted/web2/dav/method/put.py (working copy)
-@@ -34,7 +34,7 @@
- from twisted.web2 import responsecode
- from twisted.web2.http import HTTPError, StatusResponse
- from twisted.web2.dav import davxml
--from twisted.web2.dav.fileop import put
-+from twisted.web2.dav.method import put_common
- from twisted.web2.dav.util import parentForURL
-
- def preconditions_PUT(self, request):
-@@ -107,4 +107,5 @@
- # to return a MULTI_STATUS response, which is WebDAV-specific (and PUT is
- # not).
- #
-- return put(request.stream, self.fp)
-+ #return put(request.stream, self.fp)
-+ return put_common.storeResource(request, destination=self, destination_uri=request.uri)
Deleted: CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.method.put_common.patch
===================================================================
--- CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.method.put_common.patch 2009-05-01 17:16:27 UTC (rev 4129)
+++ CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.method.put_common.patch 2009-05-01 17:19:57 UTC (rev 4130)
@@ -1,270 +0,0 @@
-Index: twisted/web2/dav/method/put_common.py
-===================================================================
---- twisted/web2/dav/method/put_common.py (revision 0)
-+++ twisted/web2/dav/method/put_common.py (revision 0)
-@@ -0,0 +1,265 @@
-+##
-+# Copyright (c) 2005-2007 Apple Inc. All rights reserved.
-+#
-+# Licensed under the Apache License, Version 2.0 (the "License");
-+# you may not use this file except in compliance with the License.
-+# You may obtain a copy of the License at
-+#
-+# http://www.apache.org/licenses/LICENSE-2.0
-+#
-+# Unless required by applicable law or agreed to in writing, software
-+# distributed under the License is distributed on an "AS IS" BASIS,
-+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-+# See the License for the specific language governing permissions and
-+# limitations under the License.
-+#
-+# DRI: Cyrus Daboo, cdaboo at apple.com
-+##
-+
-+"""
-+PUT/COPY/MOVE common behavior.
-+"""
-+
-+__version__ = "0.0"
-+
-+__all__ = ["storeCalendarObjectResource"]
-+
-+from twisted.internet.defer import deferredGenerator, maybeDeferred, waitForDeferred
-+from twisted.python import failure, log
-+from twisted.python.filepath import FilePath
-+from twisted.web2 import responsecode
-+from twisted.web2.dav import davxml
-+from twisted.web2.dav.element.base import dav_namespace
-+from twisted.web2.dav.fileop import copy, delete, put
-+from twisted.web2.dav.http import ErrorResponse
-+from twisted.web2.dav.resource import TwistedGETContentMD5
-+from twisted.web2.dav.stream import MD5StreamWrapper
-+from twisted.web2.http import HTTPError
-+from twisted.web2.http_headers import generateContentType
-+from twisted.web2.iweb import IResponse
-+from twisted.web2.stream import MemoryStream
-+
-+def storeResource(
-+ request,
-+ source=None, source_uri=None, data=None,
-+ destination=None, destination_uri=None,
-+ deletesource=False,
-+ depth="0"
-+):
-+ """
-+ Function that does common PUT/COPY/MOVE behaviour.
-+
-+ @param request: the L{twisted.web2.server.Request} for the current HTTP request.
-+ @param source: the L{DAVFile} for the source resource to copy from, or None if source data
-+ is to be read from the request.
-+ @param source_uri: the URI for the source resource.
-+ @param data: a C{str} to copy data from instead of the request stream.
-+ @param destination: the L{DAVFile} for the destination resource to copy into.
-+ @param destination_uri: the URI for the destination resource.
-+ @param deletesource: True if the source resource is to be deleted on successful completion, False otherwise.
-+ @param depth: a C{str} containing the COPY/MOVE Depth header value.
-+ @return: status response.
-+ """
-+
-+ try:
-+ assert request is not None and destination is not None and destination_uri is not None
-+ assert (source is None) or (source is not None and source_uri is not None)
-+ assert not deletesource or (deletesource and source is not None)
-+ except AssertionError:
-+ log.err("Invalid arguments to storeResource():")
-+ log.err("request=%s\n" % (request,))
-+ log.err("source=%s\n" % (source,))
-+ log.err("source_uri=%s\n" % (source_uri,))
-+ log.err("data=%s\n" % (data,))
-+ log.err("destination=%s\n" % (destination,))
-+ log.err("destination_uri=%s\n" % (destination_uri,))
-+ log.err("deletesource=%s\n" % (deletesource,))
-+ log.err("depth=%s\n" % (depth,))
-+ raise
-+
-+ class RollbackState(object):
-+ """
-+ This class encapsulates the state needed to rollback the entire PUT/COPY/MOVE
-+ transaction, leaving the server state the same as it was before the request was
-+ processed. The DoRollback method will actually execute the rollback operations.
-+ """
-+
-+ def __init__(self):
-+ self.active = True
-+ self.source_copy = None
-+ self.destination_copy = None
-+ self.destination_created = False
-+ self.source_deleted = False
-+
-+ def Rollback(self):
-+ """
-+ Rollback the server state. Do not allow this to raise another exception. If
-+ rollback fails then we are going to be left in an awkward state that will need
-+ to be cleaned up eventually.
-+ """
-+ if self.active:
-+ self.active = False
-+ log.err("Rollback: rollback")
-+ try:
-+ if self.source_copy and self.source_deleted:
-+ self.source_copy.moveTo(source.fp)
-+ log.err("Rollback: source restored %s to %s" % (self.source_copy.path, source.fp.path))
-+ self.source_copy = None
-+ self.source_deleted = False
-+ if self.destination_copy:
-+ destination.fp.remove()
-+ log.err("Rollback: destination restored %s to %s" % (self.destination_copy.path, destination.fp.path))
-+ self.destination_copy.moveTo(destination.fp)
-+ self.destination_copy = None
-+ elif self.destination_created:
-+ destination.fp.remove()
-+ log.err("Rollback: destination removed %s" % (destination.fp.path,))
-+ self.destination_created = False
-+ except:
-+ log.err("Rollback: exception caught and not handled: %s" % failure.Failure())
-+
-+ def Commit(self):
-+ """
-+ Commit the resource changes by wiping the rollback state.
-+ """
-+ if self.active:
-+ log.err("Rollback: commit")
-+ self.active = False
-+ if self.source_copy:
-+ self.source_copy.remove()
-+ log.err("Rollback: removed source backup %s" % (self.source_copy.path,))
-+ self.source_copy = None
-+ if self.destination_copy:
-+ self.destination_copy.remove()
-+ log.err("Rollback: removed destination backup %s" % (self.destination_copy.path,))
-+ self.destination_copy = None
-+ self.destination_created = False
-+ self.source_deleted = False
-+
-+ rollback = RollbackState()
-+
-+ try:
-+ """
-+ Handle validation operations here.
-+ """
-+
-+ """
-+ Handle rollback setup here.
-+ """
-+
-+ # Do quota checks on destination and source before we start messing with adding other files
-+ destquota = waitForDeferred(destination.quota(request))
-+ yield destquota
-+ destquota = destquota.getResult()
-+ if destquota is not None and destination.exists():
-+ old_dest_size = waitForDeferred(destination.quotaSize(request))
-+ yield old_dest_size
-+ old_dest_size = old_dest_size.getResult()
-+ else:
-+ old_dest_size = 0
-+
-+ if source is not None:
-+ sourcequota = waitForDeferred(source.quota(request))
-+ yield sourcequota
-+ sourcequota = sourcequota.getResult()
-+ if sourcequota is not None and source.exists():
-+ old_source_size = waitForDeferred(source.quotaSize(request))
-+ yield old_source_size
-+ old_source_size = old_source_size.getResult()
-+ else:
-+ old_source_size = 0
-+ else:
-+ sourcequota = None
-+ old_source_size = 0
-+
-+ # We may need to restore the original resource data if the PUT/COPY/MOVE fails,
-+ # so rename the original file in case we need to rollback.
-+ overwrite = destination.exists()
-+ if overwrite:
-+ rollback.destination_copy = FilePath(destination.fp.path)
-+ rollback.destination_copy.path += ".rollback"
-+ destination.fp.copyTo(rollback.destination_copy)
-+ else:
-+ rollback.destination_created = True
-+
-+ if deletesource:
-+ rollback.source_copy = FilePath(source.fp.path)
-+ rollback.source_copy.path += ".rollback"
-+ source.fp.copyTo(rollback.source_copy)
-+
-+ """
-+ Handle actual store operations here.
-+ """
-+
-+ # Do put or copy based on whether source exists
-+ if source is not None:
-+ response = maybeDeferred(copy, source.fp, destination.fp, destination_uri, depth)
-+ else:
-+ datastream = request.stream
-+ if data is not None:
-+ datastream = MemoryStream(data)
-+ md5 = MD5StreamWrapper(datastream)
-+ response = maybeDeferred(put, md5, destination.fp)
-+
-+ response = waitForDeferred(response)
-+ yield response
-+ response = response.getResult()
-+
-+ # Update the MD5 value on the resource
-+ if source is not None:
-+ # Copy MD5 value from source to destination
-+ if source.hasDeadProperty(TwistedGETContentMD5):
-+ md5 = source.readDeadProperty(TwistedGETContentMD5)
-+ destination.writeDeadProperty(md5)
-+ else:
-+ # Finish MD5 calc and write dead property
-+ md5.close()
-+ md5 = md5.getMD5()
-+ destination.writeDeadProperty(TwistedGETContentMD5.fromString(md5))
-+
-+ # Update the content-type value on the resource if it is not been copied or moved
-+ if source is None:
-+ content_type = request.headers.getHeader("content-type")
-+ if content_type is not None:
-+ destination.writeDeadProperty(davxml.GETContentType.fromString(generateContentType(content_type)))
-+
-+ response = IResponse(response)
-+
-+ # Do quota check on destination
-+ if destquota is not None:
-+ # Get size of new/old resources
-+ new_dest_size = waitForDeferred(destination.quotaSize(request))
-+ yield new_dest_size
-+ new_dest_size = new_dest_size.getResult()
-+ diff_size = new_dest_size - old_dest_size
-+ if diff_size >= destquota[0]:
-+ log.err("Over quota: available %d, need %d" % (destquota[0], diff_size))
-+ raise HTTPError(ErrorResponse(responsecode.INSUFFICIENT_STORAGE_SPACE, (dav_namespace, "quota-not-exceeded")))
-+ d = waitForDeferred(destination.quotaSizeAdjust(request, diff_size))
-+ yield d
-+ d.getResult()
-+
-+ if deletesource:
-+ # Delete the source resource
-+ if sourcequota is not None:
-+ delete_size = 0 - old_source_size
-+ d = waitForDeferred(source.quotaSizeAdjust(request, delete_size))
-+ yield d
-+ d.getResult()
-+
-+ delete(source_uri, source.fp, depth)
-+ rollback.source_deleted = True
-+
-+ # Can now commit changes and forget the rollback details
-+ rollback.Commit()
-+
-+ yield response
-+ return
-+
-+ except:
-+ # Roll back changes to original server state. Note this may do nothing
-+ # if the rollback has already ocurred or changes already committed.
-+ rollback.Rollback()
-+ raise
-+
-+storeResource = deferredGenerator(storeResource)
Deleted: CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.method.report.patch
===================================================================
--- CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.method.report.patch 2009-05-01 17:16:27 UTC (rev 4129)
+++ CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.method.report.patch 2009-05-01 17:19:57 UTC (rev 4130)
@@ -1,33 +0,0 @@
-Index: twisted/web2/dav/method/report.py
-===================================================================
---- twisted/web2/dav/method/report.py (revision 19773)
-+++ twisted/web2/dav/method/report.py (working copy)
-@@ -27,7 +27,11 @@
- WebDAV REPORT method
- """
-
--__all__ = ["http_REPORT"]
-+__all__ = [
-+ "max_number_of_matches",
-+ "NumberOfMatchesWithinLimits",
-+ "http_REPORT",
-+]
-
- import string
-
-@@ -43,7 +47,14 @@
- max_number_of_matches = 500
-
- class NumberOfMatchesWithinLimits(Exception):
-- pass
-+
-+ def __init__(self, limit):
-+
-+ super(NumberOfMatchesWithinLimits, self).__init__()
-+ self.limit = limit
-+
-+ def maxLimit(self):
-+ return self.limit
-
- def http_REPORT(self, request):
- """
Deleted: CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.method.report_acl_principal_prop_set.patch
===================================================================
--- CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.method.report_acl_principal_prop_set.patch 2009-05-01 17:16:27 UTC (rev 4129)
+++ CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.method.report_acl_principal_prop_set.patch 2009-05-01 17:19:57 UTC (rev 4130)
@@ -1,22 +0,0 @@
-Index: twisted/web2/dav/method/report_acl_principal_prop_set.py
-===================================================================
---- twisted/web2/dav/method/report_acl_principal_prop_set.py (revision 19773)
-+++ twisted/web2/dav/method/report_acl_principal_prop_set.py (working copy)
-@@ -103,7 +103,7 @@
- # Check size of results is within limit
- matchcount += 1
- if matchcount > max_number_of_matches:
-- raise NumberOfMatchesWithinLimits
-+ raise NumberOfMatchesWithinLimits(max_number_of_matches)
-
- resource = waitForDeferred(request.locateResource(str(principal)))
- yield resource
-@@ -144,7 +144,7 @@
- log.err("Too many matching components")
- raise HTTPError(ErrorResponse(
- responsecode.FORBIDDEN,
-- (dav_namespace, "number-of-matches-within-limits")
-+ davxml.NumberOfMatchesWithinLimits()
- ))
-
- yield MultiStatusResponse(responses)
Deleted: CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.method.report_expand.patch
===================================================================
--- CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.method.report_expand.patch 2009-05-01 17:16:27 UTC (rev 4129)
+++ CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.method.report_expand.patch 2009-05-01 17:19:57 UTC (rev 4130)
@@ -1,214 +0,0 @@
-Index: twisted/web2/dav/method/report_expand.py
-===================================================================
---- twisted/web2/dav/method/report_expand.py (revision 19773)
-+++ twisted/web2/dav/method/report_expand.py (working copy)
-@@ -1,6 +1,6 @@
- # -*- test-case-name: twisted.web2.dav.test.test_report_expand -*-
- ##
--# Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
-+# Copyright (c) 2005-2008 Apple Computer, Inc. All rights reserved.
- #
- # Permission is hereby granted, free of charge, to any person obtaining a copy
- # of this software and associated documentation files (the "Software"), to deal
-@@ -19,8 +19,6 @@
- # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- # SOFTWARE.
--#
--# DRI: Wilfredo Sanchez, wsanchez at apple.com
- ##
-
- """
-@@ -29,86 +27,143 @@
-
- __all__ = ["report_DAV__expand_property"]
-
-+from twisted.internet.defer import inlineCallbacks, returnValue
- from twisted.python import log
- from twisted.python.failure import Failure
--from twisted.internet.defer import deferredGenerator, waitForDeferred
- from twisted.web2 import responsecode
- from twisted.web2.dav import davxml
--from twisted.web2.dav.http import statusForFailure
- from twisted.web2.dav.davxml import dav_namespace
-+from twisted.web2.dav.http import statusForFailure, MultiStatusResponse
-+from twisted.web2.dav.method import prop_common
-+from twisted.web2.dav.method.propfind import propertyName
-+from twisted.web2.dav.resource import AccessDeniedError
-+from twisted.web2.dav.util import parentForURL
-+from twisted.web2.http import HTTPError, StatusResponse
-
-+ at inlineCallbacks
- def report_DAV__expand_property(self, request, expand_property):
- """
- Generate an expand-property REPORT. (RFC 3253, section 3.8)
-+
-+ TODO: for simplicity we will only support one level of expansion.
- """
-- # FIXME: Handle depth header
--
-+ # Verify root element
- if not isinstance(expand_property, davxml.ExpandProperty):
- raise ValueError("%s expected as root element, not %s."
- % (davxml.ExpandProperty.sname(), expand_property.sname()))
-
-+ # Only handle Depth: 0
-+ depth = request.headers.getHeader("depth", "0")
-+ if depth != "0":
-+ log.err("Non-zero depth is not allowed: %s" % (depth,))
-+ raise HTTPError(StatusResponse(responsecode.BAD_REQUEST, "Depth %s not allowed" % (depth,)))
-+
- #
-- # Expand DAV:allprop
-+ # Get top level properties to expand and make sure we only have one level
- #
- properties = {}
-
- for property in expand_property.children:
-- namespace = property.getAttribute("namespace")
-- name = property.getAttribute("name")
-+ namespace = property.attributes.get("namespace", dav_namespace)
-+ name = property.attributes.get("name", "")
-+
-+ # Make sure children have no children
-+ props_to_find = []
-+ for child in property.children:
-+ if child.children:
-+ log.err("expand-property REPORT only supports single level expansion")
-+ raise HTTPError(StatusResponse(
-+ responsecode.NOT_IMPLEMENTED,
-+ "expand-property REPORT only supports single level expansion"
-+ ))
-+ child_namespace = child.attributes.get("namespace", dav_namespace)
-+ child_name = child.attributes.get("name", "")
-+ props_to_find.append((child_namespace, child_name))
-
-- if not namespace: namespace = dav_namespace
-+ properties[(namespace, name)] = props_to_find
-
-- if (namespace, name) == (dav_namespace, "allprop"):
-- all_properties = waitForDeferred(self.listAllProp(request))
-- yield all_properties
-- all_properties = all_properties.getResult()
--
-- for all_property in all_properties:
-- properties[all_property.qname()] = property
-- else:
-- properties[(namespace, name)] = property
--
- #
-- # Look up the requested properties
-+ # Generate the expanded responses status for each top-level property
- #
- properties_by_status = {
- responsecode.OK : [],
- responsecode.NOT_FOUND : [],
- }
-+
-+ filteredaces = None
-+ lastParent = None
-
-- for property in properties:
-- my_properties = waitForDeferred(self.listProperties(request))
-- yield my_properties
-- my_properties = my_properties.getResult()
-+ for qname in properties.iterkeys():
-+ try:
-+ prop = (yield self.readProperty(qname, request))
-+
-+ # Form the PROPFIND-style DAV:prop element we need later
-+ props_to_return = davxml.PropertyContainer(*properties[qname])
-
-- if property in my_properties:
-- try:
-- value = waitForDeferred(self.readProperty(property, request))
-- yield value
-- value = value.getResult()
-+ # Now dereference any HRefs
-+ responses = []
-+ for href in prop.children:
-+ if isinstance(href, davxml.HRef):
-+
-+ # Locate the Href resource and its parent
-+ resource_uri = str(href)
-+ child = (yield request.locateResource(resource_uri))
-+
-+ if not child or not child.exists():
-+ responses.append(davxml.StatusResponse(href, davxml.Status.fromResponseCode(responsecode.NOT_FOUND)))
-+ continue
-+ parent = (yield request.locateResource(parentForURL(resource_uri)))
-+
-+ # Check privileges on parent - must have at least DAV:read
-+ try:
-+ yield parent.checkPrivileges(request, (davxml.Read(),))
-+ except AccessDeniedError:
-+ responses.append(davxml.StatusResponse(href, davxml.Status.fromResponseCode(responsecode.FORBIDDEN)))
-+ continue
-+
-+ # Cache the last parent's inherited aces for checkPrivileges optimization
-+ if lastParent != parent:
-+ lastParent = parent
-+
-+ # Do some optimisation of access control calculation by determining any inherited ACLs outside of
-+ # the child resource loop and supply those to the checkPrivileges on each child.
-+ filteredaces = (yield parent.inheritedACEsforChildren(request))
-
-- if isinstance(value, davxml.HRef):
-- raise NotImplementedError()
-- else:
-- raise NotImplementedError()
-- except:
-- f = Failure()
-+ # Check privileges - must have at least DAV:read
-+ try:
-+ yield child.checkPrivileges(request, (davxml.Read(),), inherited_aces=filteredaces)
-+ except AccessDeniedError:
-+ responses.append(davxml.StatusResponse(href, davxml.Status.fromResponseCode(responsecode.FORBIDDEN)))
-+ continue
-+
-+ # Now retrieve all the requested properties on the HRef resource
-+ yield prop_common.responseForHref(
-+ request,
-+ responses,
-+ href,
-+ child,
-+ prop_common.propertyListForResource,
-+ props_to_return,
-+ )
-+
-+ prop.children = responses
-+ properties_by_status[responsecode.OK].append(prop)
-+ except:
-+ f = Failure()
-
-- log.err("Error reading property %r for resource %s: %s"
-- % (property, self, f.value))
-+ log.err("Error reading property %r for resource %s: %s" % (qname, request.uri, f.value))
-
-- status = statusForFailure(f, "getting property: %s" % (property,))
-- if status not in properties_by_status:
-- properties_by_status[status] = []
-+ status = statusForFailure(f, "getting property: %s" % (qname,))
-+ if status not in properties_by_status: properties_by_status[status] = []
-+ properties_by_status[status].append(propertyName(qname))
-
-- raise NotImplementedError()
-+ # Build the overall response
-+ propstats = [
-+ davxml.PropertyStatus(
-+ davxml.PropertyContainer(*properties_by_status[status]),
-+ davxml.Status.fromResponseCode(status)
-+ )
-+ for status in properties_by_status if properties_by_status[status]
-+ ]
-
-- #properties_by_status[status].append(
-- # ____propertyName(property)
-- #)
-- else:
-- properties_by_status[responsecode.NOT_FOUND].append(property)
--
-- raise NotImplementedError()
--
--report_DAV__expand_property = deferredGenerator(report_DAV__expand_property)
-+ returnValue(MultiStatusResponse((davxml.PropertyStatusResponse(davxml.HRef(request.uri), *propstats),)))
Deleted: CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.method.report_principal_match.patch
===================================================================
--- CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.method.report_principal_match.patch 2009-05-01 17:16:27 UTC (rev 4129)
+++ CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.method.report_principal_match.patch 2009-05-01 17:19:57 UTC (rev 4130)
@@ -1,150 +0,0 @@
-Index: twisted/web2/dav/method/report_principal_match.py
-===================================================================
---- twisted/web2/dav/method/report_principal_match.py (revision 19773)
-+++ twisted/web2/dav/method/report_principal_match.py (working copy)
-@@ -89,40 +89,64 @@
- responses = []
- matchcount = 0
-
-- selfPrincipal = self.currentPrincipal(request).children[0]
-+ selfPrincipalURL = self.currentPrincipal(request).children[0]
-
-- # Do some optimisation of access control calculation by determining any inherited ACLs outside of
-- # the child resource loop and supply those to the checkPrivileges on each child.
-- filteredaces = waitForDeferred(self.inheritedACEsforChildren(request))
-- yield filteredaces
-- filteredaces = filteredaces.getResult()
--
-- children = []
-- d = waitForDeferred(self.findChildren("infinity", request, lambda x, y: children.append((x,y)),
-- privileges=(davxml.Read(),), inherited_aces=filteredaces))
-- yield d
-- d.getResult()
--
- if lookForPrincipals:
-
-- for child, uri in children:
-- if isPrincipalResource(child) and child.principalMatch(selfPrincipal):
-- # Check size of results is within limit
-- matchcount += 1
-- if matchcount > max_number_of_matches:
-- raise NumberOfMatchesWithinLimits
-+ # Find the set of principals that represent "self".
-+
-+ # First add "self"
-+ principal = waitForDeferred(request.locateResource(str(selfPrincipalURL)))
-+ yield principal
-+ principal = principal.getResult()
-+ selfItems = [principal,]
-+
-+ # Get group memberships for "self" and add each of those
-+ d = waitForDeferred(principal.groupMemberships())
-+ yield d
-+ memberships = d.getResult()
-+ selfItems.extend(memberships)
-+
-+ # Now add each principal found to the response provided the principal resource is a child of
-+ # the current resource.
-+ for principal in selfItems:
-+ # Get all the URIs that point to the principal resource
-+ # FIXME: making the assumption that the principalURL() is the URL of the resource we found
-+ principal_uris = [principal.principalURL()]
-+ principal_uris.extend(principal.alternateURIs())
-+
-+ # Compare each one to the request URI and return at most one that matches
-+ for uri in principal_uris:
-+ if uri.startswith(request.uri):
-+ # Check size of results is within limit
-+ matchcount += 1
-+ if matchcount > max_number_of_matches:
-+ raise NumberOfMatchesWithinLimits(max_number_of_matches)
-+
-+ d = waitForDeferred(prop_common.responseForHref(
-+ request,
-+ responses,
-+ davxml.HRef.fromString(uri),
-+ principal,
-+ propertiesForResource,
-+ propElement
-+ ))
-+ yield d
-+ d.getResult()
-+ break
-+ else:
-+ # Do some optimisation of access control calculation by determining any inherited ACLs outside of
-+ # the child resource loop and supply those to the checkPrivileges on each child.
-+ filteredaces = waitForDeferred(self.inheritedACEsforChildren(request))
-+ yield filteredaces
-+ filteredaces = filteredaces.getResult()
-+
-+ children = []
-+ d = waitForDeferred(self.findChildren("infinity", request, lambda x, y: children.append((x,y)),
-+ privileges=(davxml.Read(),), inherited_aces=filteredaces))
-+ yield d
-+ d.getResult()
-
-- d = waitForDeferred(prop_common.responseForHref(
-- request,
-- responses,
-- davxml.HRef.fromString(uri),
-- child,
-- propertiesForResource,
-- propElement
-- ))
-- yield d
-- d.getResult()
-- else:
- for child, uri in children:
- # Try to read the requested property from this resource
- try:
-@@ -137,22 +161,26 @@
- yield principal
- principal = principal.getResult()
-
-- if principal and isPrincipalResource(principal) and principal.principalMatch(selfPrincipal):
-- # Check size of results is within limit
-- matchcount += 1
-- if matchcount > max_number_of_matches:
-- raise NumberOfMatchesWithinLimits
--
-- d = waitForDeferred(prop_common.responseForHref(
-- request,
-- responses,
-- davxml.HRef.fromString(uri),
-- child,
-- propertiesForResource,
-- propElement
-- ))
-+ if principal and isPrincipalResource(principal):
-+ d = waitForDeferred(principal.principalMatch(selfPrincipalURL))
- yield d
-- d.getResult()
-+ matched = d.getResult()
-+ if matched:
-+ # Check size of results is within limit
-+ matchcount += 1
-+ if matchcount > max_number_of_matches:
-+ raise NumberOfMatchesWithinLimits(max_number_of_matches)
-+
-+ d = waitForDeferred(prop_common.responseForHref(
-+ request,
-+ responses,
-+ davxml.HRef.fromString(uri),
-+ child,
-+ propertiesForResource,
-+ propElement
-+ ))
-+ yield d
-+ d.getResult()
- except HTTPError:
- # Just ignore a failure to access the property. We treat this like a property that does not exist
- # or does not match the principal.
-@@ -162,7 +190,7 @@
- log.err("Too many matching components in principal-match report")
- raise HTTPError(ErrorResponse(
- responsecode.FORBIDDEN,
-- (dav_namespace, "number-of-matches-within-limits")
-+ davxml.NumberOfMatchesWithinLimits()
- ))
-
- yield MultiStatusResponse(responses)
Deleted: CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.method.report_principal_property_search.patch
===================================================================
--- CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.method.report_principal_property_search.patch 2009-05-01 17:16:27 UTC (rev 4129)
+++ CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.method.report_principal_property_search.patch 2009-05-01 17:19:57 UTC (rev 4130)
@@ -1,22 +0,0 @@
-Index: twisted/web2/dav/method/report_principal_property_search.py
-===================================================================
---- twisted/web2/dav/method/report_principal_property_search.py (revision 19773)
-+++ twisted/web2/dav/method/report_principal_property_search.py (working copy)
-@@ -166,7 +166,7 @@
- # Check size of results is within limit
- matchcount += 1
- if matchcount > max_number_of_matches:
-- raise NumberOfMatchesWithinLimits
-+ raise NumberOfMatchesWithinLimits(max_number_of_matches)
-
- d = waitForDeferred(prop_common.responseForHref(
- request,
-@@ -183,7 +183,7 @@
- log.err("Too many matching components in prinicpal-property-search report")
- raise HTTPError(ErrorResponse(
- responsecode.FORBIDDEN,
-- (dav_namespace, "number-of-matches-within-limits")
-+ davxml.NumberOfMatchesWithinLimits()
- ))
-
- yield MultiStatusResponse(responses)
Deleted: CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.resource.patch
===================================================================
--- CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.resource.patch 2009-05-01 17:16:27 UTC (rev 4129)
+++ CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.resource.patch 2009-05-01 17:19:57 UTC (rev 4130)
@@ -1,1238 +0,0 @@
-Index: twisted/web2/dav/resource.py
-===================================================================
---- twisted/web2/dav/resource.py (revision 19773)
-+++ twisted/web2/dav/resource.py (working copy)
-@@ -31,20 +31,31 @@
- "DAVResource",
- "DAVLeafResource",
- "DAVPrincipalResource",
-+ "DAVPrincipalCollectionResource",
- "AccessDeniedError",
- "isPrincipalResource",
- "TwistedACLInheritable",
-+ "TwistedGETContentMD5",
-+ "TwistedQuotaRootProperty",
- "allACL",
- "readonlyACL",
- "davPrivilegeSet",
- "unauthenticatedPrincipal",
- ]
-
- import urllib
-+import __builtin__
-+if not hasattr(__builtin__, "set"):
-+ import sets.Set as set
-+if not hasattr(__builtin__, "frozenset"):
-+ import sets.ImmutableSet as frozenset
-
- from zope.interface import implements
- from twisted.python import log
--from twisted.internet.defer import Deferred, maybeDeferred, succeed
-+from twisted.python.failure import Failure
-+from twisted.cred.error import LoginFailed, UnauthorizedLogin
-+from twisted.internet.defer import Deferred, maybeDeferred, succeed,\
-+ inlineCallbacks, returnValue
- from twisted.internet.defer import waitForDeferred, deferredGenerator
- from twisted.internet import reactor
- from twisted.web2 import responsecode
-@@ -52,12 +62,13 @@
- from twisted.web2.http_headers import generateContentType
- from twisted.web2.iweb import IResponse
- from twisted.web2.resource import LeafResource
-+from twisted.web2.server import NoURLForResourceError
- from twisted.web2.static import MetaDataMixin, StaticRenderMixin
- from twisted.web2.auth.wrapper import UnauthorizedResponse
- from twisted.web2.dav import davxml
- from twisted.web2.dav.davxml import dav_namespace, lookupElement
- from twisted.web2.dav.davxml import twisted_dav_namespace, twisted_private_namespace
--from twisted.web2.dav.idav import IDAVResource, IDAVPrincipalResource
-+from twisted.web2.dav.idav import IDAVResource, IDAVPrincipalResource, IDAVPrincipalCollectionResource
- from twisted.web2.dav.http import NeedPrivilegesResponse
- from twisted.web2.dav.noneprops import NonePropertyStore
- from twisted.web2.dav.util import unimplemented, parentForURL, joinURL
-@@ -126,10 +137,13 @@
- #(dav_namespace, "group" ), # RFC 3744, section 5.2
- (dav_namespace, "supported-privilege-set" ), # RFC 3744, section 5.3
- (dav_namespace, "current-user-privilege-set"), # RFC 3744, section 5.4
-+ (dav_namespace, "current-user-principal" ), # draft-sanchez-webdav-current-principal
- (dav_namespace, "acl" ), # RFC 3744, section 5.5
- (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"),
- )
-@@ -166,6 +180,14 @@
- if qname[0] == twisted_private_namespace:
- return succeed(False)
-
-+ # Need to special case the dynamic live properties
-+ namespace, name = qname
-+ if namespace == dav_namespace:
-+ if name in ("quota-available-bytes", "quota-used-bytes"):
-+ d = self.hasQuota(request)
-+ d.addCallback(lambda result: result)
-+ return d
-+
- return succeed(qname in self.liveProperties or self.deadProperties().contains(qname))
-
- def readProperty(self, property, request):
-@@ -201,7 +223,6 @@
- mimeType = self.contentType()
- if mimeType is None:
- return None
-- mimeType.params = None # WebDAV getcontenttype property does not include parameters
- return davxml.GETContentType(generateContentType(mimeType))
-
- if name == "getcontentlength":
-@@ -239,8 +260,10 @@
- )
-
- if name == "supported-report-set":
-- supported = [davxml.SupportedReport(report,) for report in self.supportedReports()]
-- return davxml.SupportedReportSet(*supported)
-+ return davxml.SupportedReportSet(*[
-+ davxml.SupportedReport(report,)
-+ for report in self.supportedReports()
-+ ])
-
- if name == "supported-privilege-set":
- return self.supportedPrivileges(request)
-@@ -252,9 +275,10 @@
- return davxml.InheritedACLSet(*self.inheritedACLSet())
-
- if name == "principal-collection-set":
-- d = self.principalCollections(request)
-- d.addCallback(lambda collections: davxml.PrincipalCollectionSet(*collections))
-- return d
-+ return davxml.PrincipalCollectionSet(*[
-+ davxml.HRef(principalCollection.principalCollectionURL())
-+ for principalCollection in self.principalCollections()
-+ ])
-
- def ifAllowed(privileges, callback):
- def onError(failure):
-@@ -286,7 +310,36 @@
- d.addCallback(gotACL)
- return d
- return ifAllowed((davxml.ReadACL(),), callback)
-+
-+ if name == "current-user-principal":
-+ return davxml.CurrentUserPrincipal(self.currentPrincipal(request).children[0])
-
-+ 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
-+
- elif namespace == twisted_dav_namespace:
- if name == "resource-class":
- class ResourceClass (davxml.WebDAVTextElement):
-@@ -309,10 +362,7 @@
- """
- See L{IDAVResource.writeProperty}.
- """
-- assert (
-- isinstance(property, davxml.WebDAVElement),
-- "Not a property: %r" % (property,)
-- )
-+ assert isinstance(property, davxml.WebDAVElement), "Not a property: %r" % (property,)
-
- def defer():
- if property.protected:
-@@ -363,15 +413,28 @@
- """
- See L{IDAVResource.listProperties}.
- """
-- # FIXME: A set would be better here, that that's a python 2.4+ feature.
-- qnames = list(self.liveProperties)
-+ qnames = set(self.liveProperties)
-
-+ # Add dynamic live properties that exist
-+ dynamicLiveProperties = (
-+ (dav_namespace, "quota-available-bytes" ),
-+ (dav_namespace, "quota-used-bytes" ),
-+ )
-+ for dqname in dynamicLiveProperties:
-+ has = waitForDeferred(self.hasProperty(dqname, request))
-+ yield has
-+ has = has.getResult()
-+ if not has:
-+ qnames.remove(dqname)
-+
- for qname in self.deadProperties().list():
- if (qname not in qnames) and (qname[0] != twisted_private_namespace):
-- qnames.append(qname)
-+ qnames.add(qname)
-
-- return succeed(qnames)
-+ yield qnames
-
-+ listProperties = deferredGenerator(listProperties)
-+
- def listAllprop(self, request):
- """
- Some DAV properties should not be returned to a C{DAV:allprop} query.
-@@ -465,8 +528,22 @@
- return super(DAVPropertyMixIn, self).displayName()
-
- class DAVResource (DAVPropertyMixIn, StaticRenderMixin):
-+ """
-+ WebDAV resource.
-+ """
- implements(IDAVResource)
-
-+ def __init__(self, principalCollections=None):
-+ """
-+ @param principalCollections: an iterable of L{IDAVPrincipalCollectionResource}s
-+ which contain principals to be used in ACLs for this resource.
-+ """
-+ if principalCollections is not None:
-+ self._principalCollections = frozenset([
-+ IDAVPrincipalCollectionResource(principalCollection)
-+ for principalCollection in principalCollections
-+ ])
-+
- ##
- # DAV
- ##
-@@ -553,69 +630,65 @@
- def supportedReports(self):
- """
- See L{IDAVResource.supportedReports}.
-- This implementation lists the three main ACL reports.
-+ This implementation lists the three main ACL reports and expand-property.
- """
- result = []
- result.append(davxml.Report(davxml.ACLPrincipalPropSet(),))
- result.append(davxml.Report(davxml.PrincipalMatch(),))
- result.append(davxml.Report(davxml.PrincipalPropertySearch(),))
-+ result.append(davxml.Report(davxml.ExpandProperty(),))
- return result
-
- ##
- # Authentication
- ##
-
-+ @inlineCallbacks
- def authorize(self, request, privileges, recurse=False):
- """
- See L{IDAVResource.authorize}.
- """
-- def onError(failure):
-- log.err("Invalid authentication details: %s" % (request,))
-- raise HTTPError(UnauthorizedResponse(
-+
-+ try:
-+ yield self.authenticate(request)
-+ except (UnauthorizedLogin, LoginFailed), e:
-+ log.msg("Authentication failed: %s" % (e,))
-+ response = (yield UnauthorizedResponse.makeResponse(
- request.credentialFactories,
- request.remoteAddr
- ))
-+ raise HTTPError(response)
-
-- def onAuth(result):
-- def onErrors(failure):
-- failure.trap(AccessDeniedError)
--
-- # If we were unauthorized to start with (no Authorization header from client) then
-- # we should return an unauthorized response instead to force the client to login if it can
-- if request.user == davxml.Principal(davxml.Unauthenticated()):
-- response = UnauthorizedResponse(request.credentialFactories,
-- request.remoteAddr)
-- else:
-- response = NeedPrivilegesResponse(request.uri,
-- failure.value.errors)
-- #
-- # We're not adding the headers here because this response
-- # class is supposed to be a FORBIDDEN status code and
-- # "Authorization will not help" according to RFC2616
-- #
-- raise HTTPError(response)
-+ try:
-+ yield self.checkPrivileges(request, privileges, recurse)
-+ except AccessDeniedError, e:
-+ # If we were unauthenticated to start with (no Authorization header from client) then
-+ # we should return an unauthorized response instead to force the client to login if it can
-+ if request.authnUser == davxml.Principal(davxml.Unauthenticated()):
-+ response = (yield UnauthorizedResponse.makeResponse(
-+ request.credentialFactories,
-+ request.remoteAddr
-+ ))
-+ else:
-+ response = NeedPrivilegesResponse(request.uri, e.errors)
-+ #
-+ # We're not adding the headers here because this response
-+ # class is supposed to be a FORBIDDEN status code and
-+ # "Authorization will not help" according to RFC2616
-+ #
-+ raise HTTPError(response)
-
-- d = self.checkPrivileges(request, privileges, recurse)
-- d.addErrback(onErrors)
-- return d
--
-- d = maybeDeferred(self.authenticate, request)
-- d.addCallbacks(onAuth, onError)
--
-- return d
--
-+ @inlineCallbacks
- def authenticate(self, request):
-- def loginSuccess(result):
-- request.user = result[1]
-- return request.user
-
- if not (
- hasattr(request, 'portal') and
- hasattr(request, 'credentialFactories') and
- hasattr(request, 'loginInterfaces')
- ):
-- request.user = davxml.Principal(davxml.Unauthenticated())
-- return request.user
-+ request.authnUser = davxml.Principal(davxml.Unauthenticated())
-+ request.authzUser = davxml.Principal(davxml.Unauthenticated())
-+ returnValue((request.authnUser, request.authzUser,))
-
- authHeader = request.headers.getHeader('authorization')
-
-@@ -623,31 +696,32 @@
- if authHeader[0] not in request.credentialFactories:
- log.err("Client authentication scheme %s is not provided by server %s"
- % (authHeader[0], request.credentialFactories.keys()))
-- raise HTTPError(responsecode.FORBIDDEN)
-+
-+ response = (yield UnauthorizedResponse.makeResponse(
-+ request.credentialFactories,
-+ request.remoteAddr
-+ ))
-+ raise HTTPError(response)
- else:
- factory = request.credentialFactories[authHeader[0]]
-
-- creds = factory.decode(authHeader[1], request)
-+ creds = (yield factory.decode(authHeader[1], request))
-
- # Try to match principals in each principal collection on the resource
-- def gotDetails(details):
-- principal = IDAVPrincipalResource(details[0])
-- principalURI = details[1]
-- return PrincipalCredentials(principal, principalURI, creds)
-+ authnPrincipal, authzPrincipal = (yield self.principalsForAuthID(request, creds.username))
-+ authnPrincipal = IDAVPrincipalResource(authnPrincipal)
-+ authzPrincipal = IDAVPrincipalResource(authzPrincipal)
-
-- def login(pcreds):
-- d = request.portal.login(pcreds, None, *request.loginInterfaces)
-- d.addCallback(loginSuccess)
-+ pcreds = PrincipalCredentials(authnPrincipal, authzPrincipal, creds)
-
-- return d
--
-- d = self.findPrincipalForAuthID(request, creds.username)
-- d.addCallback(gotDetails).addCallback(login)
--
-- return d
-+ result = (yield request.portal.login(pcreds, None, *request.loginInterfaces))
-+ request.authnUser = result[1]
-+ request.authzUser = result[2]
-+ returnValue((request.authnUser, request.authzUser,))
- else:
-- request.user = davxml.Principal(davxml.Unauthenticated())
-- return request.user
-+ request.authnUser = davxml.Principal(davxml.Unauthenticated())
-+ request.authzUser = davxml.Principal(davxml.Unauthenticated())
-+ returnValue((request.authnUser, request.authzUser,))
-
- ##
- # ACL
-@@ -656,49 +730,23 @@
- def currentPrincipal(self, request):
- """
- @param request: the request being processed.
-- @return: the current principal, as derived from the given request.
-+ @return: the current authorized principal, as derived from the given request.
- """
-- if hasattr(request, "user"):
-- return request.user
-+ if hasattr(request, "authzUser"):
-+ return request.authzUser
- else:
- return unauthenticatedPrincipal
-
-- def principalCollections(self, request):
-+ def principalCollections(self):
- """
- See L{IDAVResource.accessControlList}.
--
-- This implementation tries to read the L{davxml.PrincipalCollectionSet}
-- from the dead property store of this resource and uses that. If not
-- present on this resource, it tries to get it from the parent, unless it
-- is the root or has no parent.
- """
-- try:
-- principalCollections = self.readDeadProperty(davxml.PrincipalCollectionSet).childrenOfType(davxml.HRef)
-- except HTTPError, e:
-- if e.response.code != responsecode.NOT_FOUND:
-- raise
-+ if hasattr(self, "_principalCollections"):
-+ return self._principalCollections
-+ else:
-+ return ()
-
-- principalCollections = []
--
-- # Try the parent
-- myURL = request.urlForResource(self)
-- if myURL != "/":
-- parentURL = parentForURL(myURL)
--
-- parent = waitForDeferred(request.locateResource(parentURL))
-- yield parent
-- parent = parent.getResult()
--
-- if parent:
-- principalCollections = waitForDeferred(parent.principalCollections(request))
-- yield principalCollections
-- principalCollections = principalCollections.getResult()
--
-- yield principalCollections
--
-- principalCollections = deferredGenerator(principalCollections)
--
-- def defaultAccessControlList(self):
-+ def defaultRootAccessControlList(self):
- """
- @return: the L{davxml.ACL} element containing the default access control
- list for this resource.
-@@ -710,6 +758,17 @@
- #
- return readonlyACL
-
-+ def defaultAccessControlList(self):
-+ """
-+ @return: the L{davxml.ACL} element containing the default access control
-+ list for this resource.
-+ """
-+ #
-+ # The default behaviour is no ACL; we should inherrit from the parent
-+ # collection.
-+ #
-+ return davxml.ACL()
-+
- def setAccessControlList(self, acl):
- """
- See L{IDAVResource.setAccessControlList}.
-@@ -748,13 +807,16 @@
- # 10. Verify that new acl is not in conflict with itself
- # 11. Update acl on the resource
-
-- old_acl = waitForDeferred(self.accessControlList(request))
-+ # Get the current access control list, preserving any private properties on the ACEs as
-+ # we will need to keep those when we change the ACL.
-+ old_acl = waitForDeferred(self.accessControlList(request, expanding=True))
- yield old_acl
- old_acl = old_acl.getResult()
-
- # Check disabled
- if old_acl is None:
- yield None
-+ return
-
- # Need to get list of supported privileges
- supported = []
-@@ -773,10 +835,7 @@
- yield supportedPrivs
- supportedPrivs = supportedPrivs.getResult()
- for item in supportedPrivs.children:
-- assert (
-- isinstance(item, davxml.SupportedPrivilege),
-- "Not a SupportedPrivilege: %r" % (item,)
-- )
-+ assert isinstance(item, davxml.SupportedPrivilege), "Not a SupportedPrivilege: %r" % (item,)
- addSupportedPrivilege(item)
-
- # Steps 1 - 6
-@@ -910,8 +969,7 @@
- supportedPrivs = supportedPrivs.getResult()
-
- # Other principals types don't make sense as actors.
-- assert (
-- principal.children[0].name in ("unauthenticated", "href"),
-+ assert principal.children[0].name in ("unauthenticated", "href"), (
- "Principal is not an actor: %r" % (principal,)
- )
-
-@@ -1019,15 +1077,16 @@
- def getMyURL():
- url = request.urlForResource(self)
-
-- assert url is not None, "urlForResource(self) returned None for resource %s" % (self,)
-+ assert url is not None, (
-+ "urlForResource(self) returned None for resource %s" % (self,)
-+ )
-
- return url
-
- try:
- acl = self.readDeadProperty(davxml.ACL)
- except HTTPError, e:
-- assert (
-- e.response.code == responsecode.NOT_FOUND,
-+ assert e.response.code == responsecode.NOT_FOUND, (
- "Expected %s response from readDeadProperty() exception, not %s"
- % (responsecode.NOT_FOUND, e.response.code)
- )
-@@ -1038,9 +1097,9 @@
-
- if myURL == "/":
- # If we get to the root without any ACLs, then use the default.
-+ acl = self.defaultRootAccessControlList()
-+ else:
- acl = self.defaultAccessControlList()
-- else:
-- acl = davxml.ACL()
-
- # Dynamically update privileges for those ace's that are inherited.
- if inheritance:
-@@ -1076,7 +1135,7 @@
- # Adjust ACE for inherit on this resource
- children = list(ace.children)
- children.remove(TwistedACLInheritable())
-- children.append(davxml.Inherited(davxml.HRef.fromString(parentURL)))
-+ children.append(davxml.Inherited(davxml.HRef(parentURL)))
- aces.append(davxml.ACE(*children))
- else:
- aces.extend(inherited_aces)
-@@ -1105,8 +1164,7 @@
- the child resource loop and supply those to the checkPrivileges on each child.
-
- @param request: the L{IRequest} for the request in progress.
-- @return: a C{list} of L{Ace}s that child resources of this one will
-- inherit and which will match the currently authenticated principal.
-+ @return: a C{list} of L{Ace}s that child resources of this one will inherit.
- """
-
- # Get the parent ACLs with inheritance and preserve the <inheritable> element.
-@@ -1128,21 +1186,9 @@
- # Adjust ACE for inherit on this resource
- children = list(ace.children)
- children.remove(TwistedACLInheritable())
-- children.append(davxml.Inherited(davxml.HRef.fromString(request.urlForResource(self))))
-+ children.append(davxml.Inherited(davxml.HRef(request.urlForResource(self))))
- aces.append(davxml.ACE(*children))
--
-- # Filter out those that do not have a principal match with the current principal
-- principal = self.currentPrincipal(request)
-- filteredaces = []
-- for ace in aces:
-- if self.matchPrincipal(principal, ace.principal, request):
-- if ace.invert:
-- continue
-- else:
-- if not ace.invert:
-- continue
-- filteredaces.append(ace)
-- yield filteredaces
-+ yield aces
-
- inheritedACEsforChildren = deferredGenerator(inheritedACEsforChildren)
-
-@@ -1152,49 +1198,69 @@
-
- This implementation returns an empty set.
- """
--
- return []
-
-- def findPrincipalForAuthID(self, request, authid):
-+ def principalsForAuthID(self, request, authid):
- """
-+ Return authentication and authorization prinicipal identifiers for the
-+ authentication identifer passed in. In this implementation authn and authz
-+ principals are the same.
-+
- @param request: the L{IRequest} for the request in progress.
- @param authid: a string containing the
- authentication/authorization identifier for the principal
- to lookup.
-- @return: a deferred tuple of C{(principal, principalURI)}
-- where: C{principal} is the L{Principal} that is found;
-- C{principalURI} is the C{str} URI of the principal.
-+ @return: a deferred tuple of two tuples. Each tuple is
-+ C{(principal, principalURI)} where: C{principal} is the L{Principal}
-+ that is found; {principalURI} is the C{str} URI of the principal.
-+ The first tuple corresponds to authentication identifiers,
-+ the second to authorization identifiers.
- It will errback with an HTTPError(responsecode.FORBIDDEN) if
- the principal isn't found.
- """
-- # Try to match principals in each principal collection on the resource
-- collections = waitForDeferred(self.principalCollections(request))
-- yield collections
-- collections = collections.getResult()
-+ authnPrincipal = self.findPrincipalForAuthID(authid)
-
-- for collection in collections:
-- principalURI = joinURL(str(collection), authid)
-+ if authnPrincipal is None:
-+ log.msg("Could not find the principal resource for user id: %s" % (authid,))
-+ raise HTTPError(responsecode.FORBIDDEN)
-
-- principal = waitForDeferred(request.locateResource(principalURI))
-- yield principal
-- principal = principal.getResult()
-+ d = self.authorizationPrincipal(request, authid, authnPrincipal)
-+ d.addCallback(lambda authzPrincipal: (authnPrincipal, authzPrincipal))
-+ return d
-
-- if isPrincipalResource(principal):
-- yield (principal, principalURI)
-- return
-- else:
-- principalCollections = waitForDeferred(self.principalCollections(request))
-- yield principalCollections
-- principalCollections = principalCollections.getResult()
-+ def findPrincipalForAuthID(self, authid):
-+ """
-+ Return authentication and authoirization prinicipal identifiers for the
-+ authentication identifer passed in. In this implementation authn and authz
-+ principals are the same.
-
-- if len(principalCollections) == 0:
-- log.msg("DAV:principal-collection-set property cannot be found on the resource being authorized: %s" % self)
-- else:
-- log.msg("Could not find principal matching user id: %s" % authid)
-- raise HTTPError(responsecode.FORBIDDEN)
-+ @param authid: a string containing the
-+ authentication/authorization identifier for the principal
-+ to lookup.
-+ @return: a tuple of C{(principal, principalURI)} where: C{principal} is the L{Principal}
-+ that is found; {principalURI} is the C{str} URI of the principal.
-+ If not found return None.
-+ """
-+ for collection in self.principalCollections():
-+ principal = collection.principalForUser(authid)
-+ if principal is not None:
-+ return principal
-+ return None
-
-- findPrincipalForAuthID = deferredGenerator(findPrincipalForAuthID)
--
-+ def authorizationPrincipal(self, request, authid, authnPrincipal):
-+ """
-+ Determine the authorization principal for the given request and authentication principal.
-+ This implementation simply uses aht authentication principalk as the authoization principal.
-+
-+ @param request: the L{IRequest} for the request in progress.
-+ @param authid: a string containing the uthentication/authorization identifier
-+ for the principal to lookup.
-+ @param authnPrincipal: the L{IDAVPrincipal} for the authenticated principal
-+ @return: a deferred result C{tuple} of (L{IDAVPrincipal}, C{str}) containing the authorization principal
-+ resource and URI respectively.
-+ """
-+ return succeed(authnPrincipal)
-+
- def samePrincipal(self, principal1, principal2):
- """
- Check whether the two prinicpals are exactly the same in terms of
-@@ -1219,7 +1285,6 @@
- return False
-
- def matchPrincipal(self, principal1, principal2, request):
--
- """
- Check whether the principal1 is a principal in the set defined by
- principal2.
-@@ -1244,6 +1309,9 @@
- if isinstance(principal1, davxml.Unauthenticated):
- yield False
- return
-+ elif isinstance(principal1, davxml.All):
-+ yield False
-+ return
- else:
- yield True
- return
-@@ -1260,10 +1328,7 @@
- yield False
- return
-
-- assert (
-- isinstance(principal1, davxml.HRef),
-- "Not an HRef: %r" % (principal1,)
-- )
-+ assert isinstance(principal1, davxml.HRef), "Not an HRef: %r" % (principal1,)
-
- principal2 = waitForDeferred(self.resolvePrincipal(principal2, request))
- yield principal2
-@@ -1271,7 +1336,6 @@
-
- assert principal2 is not None, "principal2 is None"
-
--
- # Compare two HRefs and do group membership test as well
- if principal1 == principal2:
- yield True
-@@ -1289,6 +1353,7 @@
-
- matchPrincipal = deferredGenerator(matchPrincipal)
-
-+ @deferredGenerator
- def principalIsGroupMember(self, principal1, principal2, request):
- """
- Check whether one principal is a group member of another.
-@@ -1299,18 +1364,21 @@
- @return: L{Deferred} with result C{True} if principal1 is a member of principal2, C{False} otherwise
- """
-
-- def testGroup(group):
-- # Get principal resource for principal2
-- if group and isinstance(group, DAVPrincipalResource):
-- members = group.groupMembers()
-- if principal1 in members:
-- return True
--
-- return False
-+ d = waitForDeferred(request.locateResource(principal2))
-+ yield d
-+ group = d.getResult()
-
-- d = request.locateResource(principal2)
-- d.addCallback(testGroup)
-- return d
-+ # Get principal resource for principal2
-+ if group and isinstance(group, DAVPrincipalResource):
-+ d = waitForDeferred(group.expandedGroupMembers())
-+ yield d
-+ members = d.getResult()
-+ for member in members:
-+ if member.principalURL() == principal1:
-+ yield True
-+ return
-+
-+ yield False
-
- def validPrincipal(self, ace_principal, request):
- """
-@@ -1351,11 +1419,16 @@
- @return C{True} if C{href_principal} is valid, C{False} otherwise.
-
- This implementation tests for a href element that corresponds to
-- a principal resource.
-+ a principal resource and matches the principal-URL.
- """
-- # Must have the principal resource type
-+
-+ # Must have the principal resource type and must match the principal-URL
-+
-+ def _matchPrincipalURL(resource):
-+ return isPrincipalResource(resource) and resource.principalURL() == str(href_principal)
-+
- d = request.locateResource(str(href_principal))
-- d.addCallback(isPrincipalResource)
-+ d.addCallback(_matchPrincipalURL)
- return d
-
- def resolvePrincipal(self, principal, request):
-@@ -1404,8 +1477,7 @@
- try:
- principal = principal.getResult()
- except HTTPError, e:
-- assert (
-- e.response.code == responsecode.NOT_FOUND,
-+ assert e.response.code == responsecode.NOT_FOUND, (
- "Expected %s response from readProperty() exception, not %s"
- % (responsecode.NOT_FOUND, e.response.code)
- )
-@@ -1432,15 +1504,15 @@
- log.err("DAV:self ACE is set on non-principal resource %r" % (self,))
- yield None
- return
-- principal = davxml.HRef.fromString(self.principalURL())
-+ principal = davxml.HRef(self.principalURL())
-
- if isinstance(principal, davxml.HRef):
- yield principal
-+ return
- else:
- yield None
-
-- assert (
-- isinstance(principal, (davxml.All, davxml.Authenticated, davxml.Unauthenticated)),
-+ assert isinstance(principal, (davxml.All, davxml.Authenticated, davxml.Unauthenticated)), (
- "Not a meta-principal: %r" % (principal,)
- )
-
-@@ -1517,6 +1589,280 @@
- 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 not hasattr(request, "quota"):
-+ request.quota = {}
-+ if request.quota.has_key(self):
-+ yield request.quota[self]
-+ return
-+
-+ # Check this resource first
-+ if self.isCollection():
-+ qroot = self.quotaRoot(request)
-+ if qroot is not None:
-+ used = waitForDeferred(self.currentQuotaUse(request))
-+ yield used
-+ used = used.getResult()
-+ available = qroot - used
-+ if available < 0:
-+ available = 0
-+ request.quota[self] = (available, used)
-+ yield request.quota[self]
-+ 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[self] = d.getResult()
-+ else:
-+ request.quota[self] = None
-+
-+ yield request.quota[self]
-+ return
-+
-+ quota = deferredGenerator(quota)
-+
-+ def hasQuota(self, request):
-+ """
-+ Check whether this resource is undre quota control by checking each parent to see if
-+ it has a quota root.
-+
-+ @return: C{True} if under quota control, C{False} if not.
-+ """
-+
-+ # Check this one first
-+ if self.hasQuotaRoot(request):
-+ yield True
-+ return
-+
-+ # Look at each parent
-+ try:
-+ url = request.urlForResource(self)
-+ if url != "/":
-+ parent = waitForDeferred(request.locateResource(parentForURL(url)))
-+ yield parent
-+ parent = parent.getResult()
-+ d = waitForDeferred(parent.hasQuota(request))
-+ yield d
-+ yield d.getResult()
-+ else:
-+ yield False
-+ except NoURLForResourceError:
-+ yield False
-+
-+ hasQuota = deferredGenerator(hasQuota)
-+
-+ def hasQuotaRoot(self, request):
-+ """
-+ @return: a C{True} if this resource has quota root, C{False} otherwise.
-+ """
-+ return self.hasDeadProperty(TwistedQuotaRootProperty)
-+
-+ 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.hasQuotaRoot(request):
-+ 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, or C{None} tp remove quota restriction.
-+ """
-+ assert self.isCollection(), "Only collections can have a quota root"
-+ assert maxsize is None or isinstance(maxsize, int), "maxsize must be an int or None"
-+
-+ if maxsize is not None:
-+ self.writeDeadProperty(TwistedQuotaRootProperty(str(maxsize)))
-+ else:
-+ # Remove both the root and the cached used value
-+ self.removeDeadProperty(TwistedQuotaRootProperty)
-+ self.removeDeadProperty(TwistedQuotaUsedProperty)
-+
-+ 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.hasQuotaRoot(request):
-+ d = waitForDeferred(self.updateQuotaUse(request, adjust))
-+ yield d
-+ d.getResult()
-+ yield None
-+ 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.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: an L{Deferred} with a C{int} result 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.hasQuotaRoot(request), "Quota use only on quota root collection"
-+
-+ # Try to get the cached value property
-+ if self.hasDeadProperty(TwistedQuotaUsedProperty):
-+ return succeed(int(str(self.readDeadProperty(TwistedQuotaUsedProperty))))
-+ else:
-+ # Do brute force size determination and cache the result in the private property
-+ def _defer(result):
-+ self.writeDeadProperty(TwistedQuotaUsedProperty(str(result)))
-+ return result
-+ d = self.quotaSize(request)
-+ d.addCallback(_defer)
-+ return d
-+
-+ 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: an L{Deferred} with a C{int} result 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
-+ def _defer(size):
-+ size += adjust
-+
-+ # Sanity check the resulting size
-+ if size >= 0:
-+ self.writeDeadProperty(TwistedQuotaUsedProperty(str(size)))
-+ else:
-+ # Remove the dead property and re-read to do brute force quota calc
-+ log.msg("Attempt to set quota used to a negative value: %s (adjustment: %s)" % (size, adjust,))
-+ self.removeDeadProperty(TwistedQuotaUsedProperty)
-+ return self.currentQuotaUse(request)
-+
-+ d = self.currentQuotaUse(request)
-+ d.addCallback(_defer)
-+ return d
-+
-+ ##
- # HTTP
- ##
-
-@@ -1525,15 +1871,11 @@
- #litmus = request.headers.getRawHeaders("x-litmus")
- #if litmus: log.msg("*** Litmus test: %s ***" % (litmus,))
-
-- # FIXME: Learn how to use twisted logging facility, wsanchez
-- protocol = "HTTP/%s.%s" % request.clientproto
-- log.msg("%s %s %s" % (request.method, urllib.unquote(request.uri), protocol))
--
- #
- # If this is a collection and the URI doesn't end in "/", redirect.
- #
-- if self.isCollection() and request.uri[-1:] != "/":
-- return RedirectResponse(request.uri + "/")
-+ if self.isCollection() and request.path[-1:] != "/":
-+ return RedirectResponse(request.unparseURL(path=urllib.quote(request.path, safe=':/')+'/'))
-
- def setHeaders(response):
- response = IResponse(response)
-@@ -1567,7 +1909,7 @@
- def findChildren(self, depth, request, callback, privileges=None, inherited_aces=None):
- return succeed(None)
-
--class DAVPrincipalResource (DAVLeafResource):
-+class DAVPrincipalResource (DAVResource):
- """
- Resource representing a WebDAV principal. (RFC 3744, section 2)
- """
-@@ -1577,7 +1919,7 @@
- # WebDAV
- ##
-
-- liveProperties = DAVLeafResource.liveProperties + (
-+ liveProperties = DAVResource.liveProperties + (
- (dav_namespace, "alternate-URI-set"),
- (dav_namespace, "principal-URL" ),
- (dav_namespace, "group-member-set" ),
-@@ -1585,14 +1927,11 @@
- )
-
- def davComplianceClasses(self):
-- return ("1",)
-+ return ("1", "access-control",)
-
- def isCollection(self):
- return False
-
-- def findChildren(self, depth, request, callback, privileges=None, inherited_aces=None):
-- return succeed(None)
--
- def readProperty(self, property, request):
- def defer():
- if type(property) is tuple:
-@@ -1610,10 +1949,20 @@
- return davxml.PrincipalURL(davxml.HRef(self.principalURL()))
-
- if name == "group-member-set":
-- return davxml.GroupMemberSet(*[davxml.HRef(p) for p in self.groupMembers()])
-+ def callback(members):
-+ return davxml.GroupMemberSet(*[davxml.HRef(p.principalURL()) for p in members])
-+
-+ d = self.groupMembers()
-+ d.addCallback(callback)
-+ return d
-
- if name == "group-membership":
-- return davxml.GroupMembership(*[davxml.HRef(g) for g in self.groupMemberships()])
-+ def callback(memberships):
-+ return davxml.GroupMembership(*[davxml.HRef(g.principalURL()) for g in memberships])
-+
-+ d = self.groupMemberships()
-+ d.addCallback(callback)
-+ return d
-
- if name == "resourcetype":
- if self.isCollection():
-@@ -1655,7 +2004,7 @@
- principals. Subclasses should override this method to provide member
- URLs for this resource if appropriate.
- """
-- return ()
-+ return succeed(())
-
- def groupMemberships(self):
- """
-@@ -1666,6 +2015,7 @@
- """
- unimplemented(self)
-
-+ @deferredGenerator
- def principalMatch(self, href):
- """
- Check whether the supplied principal matches this principal or is a
-@@ -1675,10 +2025,33 @@
- """
- uri = str(href)
- if self.principalURL() == uri:
-- return True
-+ yield True
-+ return
- else:
-- return uri in self.groupMembers()
-+ d = waitForDeferred(self.expandedGroupMembers())
-+ yield d
-+ members = d.getResult()
-+ member_uris = [member.principalURL() for member in members]
-+ yield uri in member_uris
-
-+class DAVPrincipalCollectionResource (DAVResource):
-+ """
-+ WebDAV principal collection resource. (RFC 3744, section 5.8)
-+ """
-+ implements(IDAVPrincipalCollectionResource)
-+
-+ def __init__(self, url, principalCollections=()):
-+ """
-+ @param url: This resource's URL.
-+ """
-+ DAVResource.__init__(self, principalCollections=principalCollections)
-+
-+ assert url.endswith("/"), "Collection URL must end in '/'"
-+ self._url = url
-+
-+ def principalCollectionURL(self):
-+ return self._url
-+
- class AccessDeniedError(Exception):
- def __init__(self, errors):
- """
-@@ -1718,6 +2091,37 @@
- davxml.registerElement(TwistedACLInheritable)
- davxml.ACE.allowed_children[(twisted_dav_namespace, "inheritable")] = (0, 1)
-
-+class TwistedGETContentMD5 (davxml.WebDAVTextElement):
-+ """
-+ MD5 hash of the resource content.
-+ """
-+ namespace = twisted_dav_namespace
-+ name = "getcontentmd5"
-+
-+davxml.registerElement(TwistedGETContentMD5)
-+
-+"""
-+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/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.static.patch
===================================================================
--- CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.static.patch 2009-05-01 17:16:27 UTC (rev 4129)
+++ CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.static.patch 2009-05-01 17:19:57 UTC (rev 4130)
@@ -1,161 +0,0 @@
-Index: twisted/web2/dav/static.py
-===================================================================
---- twisted/web2/dav/static.py (revision 19773)
-+++ twisted/web2/dav/static.py (working copy)
-@@ -28,16 +28,17 @@
-
- __all__ = ["DAVFile"]
-
--import os
--
-+from twisted.internet.defer import succeed, deferredGenerator, waitForDeferred
-+from twisted.python.filepath import InsecurePath
- from twisted.python import log
--from twisted.internet.defer import succeed, deferredGenerator, waitForDeferred
--from twisted.web2.static import File
-+from twisted.web2 import http_headers
- from twisted.web2 import responsecode, dirlist
--from twisted.web2.http import RedirectResponse
- from twisted.web2.dav import davxml
- from twisted.web2.dav.resource import DAVResource, davPrivilegeSet
-+from twisted.web2.dav.resource import TwistedGETContentMD5
- from twisted.web2.dav.util import bindMethods
-+from twisted.web2.http import HTTPError, StatusResponse, RedirectResponse
-+from twisted.web2.static import File
-
- try:
- from twisted.web2.dav.xattrprops import xattrPropertyStore as DeadPropertyStore
-@@ -52,9 +53,11 @@
-
- Extends twisted.web2.static.File to handle WebDAV methods.
- """
-- def __init__(self, path,
-- defaultType="text/plain",
-- indexNames=None):
-+ def __init__(
-+ self, path,
-+ defaultType="text/plain", indexNames=None,
-+ principalCollections=()
-+ ):
- """
- @param path: the path of the file backing this resource.
- @param defaultType: the default mime type (as a string) for this
-@@ -62,11 +65,14 @@
- @param indexNames: a sequence of index file names.
- @param acl: an L{IDAVAccessControlList} with the .
- """
-- super(DAVFile, self).__init__(path,
-- defaultType = defaultType,
-- ignoredExts = (),
-- processors = None,
-- indexNames = indexNames)
-+ File.__init__(
-+ self, path,
-+ defaultType = defaultType,
-+ ignoredExts = (),
-+ processors = None,
-+ indexNames = indexNames,
-+ )
-+ DAVResource.__init__(self, principalCollections=principalCollections)
-
- def __repr__(self):
- return "<%s: %s>" % (self.__class__.__name__, self.fp.path)
-@@ -75,6 +81,13 @@
- # WebDAV
- ##
-
-+ def etag(self):
-+ if not self.fp.exists(): return None
-+ if self.hasDeadProperty(TwistedGETContentMD5):
-+ return http_headers.ETag(str(self.readDeadProperty(TwistedGETContentMD5)))
-+ else:
-+ return super(DAVFile, self).etag()
-+
- def davComplianceClasses(self):
- return ("1", "access-control") # Add "2" when we have locking
-
-@@ -87,7 +100,6 @@
- """
- See L{IDAVResource.isCollection}.
- """
-- for child in self.listChildren(): return True
- return self.fp.isdir()
-
- ##
-@@ -98,6 +110,50 @@
- 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: an L{Deferred} with a C{int} result containing the size of the resource.
-+ """
-+ if self.isCollection():
-+ def walktree(top):
-+ """
-+ Recursively descend the directory tree rooted at top,
-+ calling the callback function for each regular file
-+
-+ @param top: L{FilePath} for the directory to walk.
-+ """
-+
-+ total = 0
-+ for f in top.listdir():
-+ child = top.child(f)
-+ if child.isdir():
-+ # It's a directory, recurse into it
-+ result = waitForDeferred(walktree(child))
-+ yield result
-+ total += result.getResult()
-+ elif child.isfile():
-+ # It's a file, call the callback function
-+ total += child.getsize()
-+ else:
-+ # Unknown file type, print a message
-+ pass
-+
-+ yield total
-+
-+ walktree = deferredGenerator(walktree)
-+
-+ return walktree(self.fp)
-+ else:
-+ return succeed(self.fp.getsize())
-+
-+ ##
- # Workarounds for issues with File
- ##
-
-@@ -112,8 +168,12 @@
- See L{IResource}C{.locateChild}.
- """
- # If getChild() finds a child resource, return it
-- child = self.getChild(segments[0])
-- if child is not None: return (child, segments[1:])
-+ try:
-+ child = self.getChild(segments[0])
-+ if child is not None:
-+ return (child, segments[1:])
-+ except InsecurePath:
-+ raise HTTPError(StatusResponse(responsecode.FORBIDDEN, "Invalid URL path"))
-
- # If we're not backed by a directory, we have no children.
- # But check for existance first; we might be a collection resource
-@@ -132,7 +192,9 @@
- return (self.createSimilarFile(self.fp.child(path).path), segments[1:])
-
- def createSimilarFile(self, path):
-- return self.__class__(path, defaultType=self.defaultType, indexNames=self.indexNames[:])
-+ return self.__class__(
-+ path, defaultType=self.defaultType, indexNames=self.indexNames[:],
-+ principalCollections=self.principalCollections())
-
- #
- # Attach method handlers to DAVFile
Deleted: CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.stream.patch
===================================================================
--- CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.stream.patch 2009-05-01 17:16:27 UTC (rev 4129)
+++ CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.stream.patch 2009-05-01 17:19:57 UTC (rev 4130)
@@ -1,84 +0,0 @@
-Index: twisted/web2/dav/stream.py
-===================================================================
---- twisted/web2/dav/stream.py (revision 0)
-+++ twisted/web2/dav/stream.py (revision 0)
-@@ -0,0 +1,79 @@
-+##
-+# Copyright (c) 2005-2007 Apple Inc. All rights reserved.
-+#
-+# Permission is hereby granted, free of charge, to any person obtaining a copy
-+# of this software and associated documentation files (the "Software"), to deal
-+# in the Software without restriction, including without limitation the rights
-+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-+# copies of the Software, and to permit persons to whom the Software is
-+# furnished to do so, subject to the following conditions:
-+#
-+# The above copyright notice and this permission notice shall be included in all
-+# copies or substantial portions of the Software.
-+#
-+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-+# SOFTWARE.
-+#
-+# DRI: Cyrus Daboo, cdaboo at apple.com
-+##
-+
-+"""
-+Class that implements a stream that calculates the MD5 hash of the data
-+as the data is read.
-+"""
-+
-+__all__ = ["MD5StreamWrapper"]
-+
-+from twisted.internet.defer import Deferred
-+from twisted.web2.stream import SimpleStream
-+
-+try:
-+ from hashlib import md5
-+except ImportError:
-+ from md5 import new as md5
-+
-+class MD5StreamWrapper(SimpleStream):
-+
-+ def __init__(self, wrap):
-+
-+ assert wrap is not None, "Must have a stream to wrap."
-+
-+ self.stream = wrap
-+
-+ # Init MD5
-+ self.md5 = md5()
-+
-+ def read(self):
-+ assert self.md5 is not None, "Cannot call read after close."
-+
-+ # Read from wrapped stream first
-+ b = self.stream.read()
-+
-+ if isinstance(b, Deferred):
-+ def _gotData(data):
-+ if data is not None:
-+ self.md5.update(data)
-+ return data
-+ b.addCallback(_gotData)
-+ else:
-+ # Update current MD5 state
-+ if b is not None:
-+ self.md5.update(str(b))
-+
-+ return b
-+
-+ def close(self):
-+ # Close out the MD5 hash
-+ self.md5value = self.md5.hexdigest()
-+ self.md5 = None
-+
-+ SimpleStream.close(self)
-+
-+ def getMD5(self):
-+ assert hasattr(self, "md5value"), "Stream has to be closed first"
-+ return self.md5value
Deleted: CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.test.data.quota_100.patch
===================================================================
--- CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.test.data.quota_100.patch 2009-05-01 17:16:27 UTC (rev 4129)
+++ CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.test.data.quota_100.patch 2009-05-01 17:19:57 UTC (rev 4130)
@@ -1,15 +0,0 @@
-Index: twisted/web2/dav/test/data/quota_100.txt
-===================================================================
---- twisted/web2/dav/test/data/quota_100.txt (revision 0)
-+++ twisted/web2/dav/test/data/quota_100.txt (revision 0)
-@@ -0,0 +1,10 @@
-+123456789
-+123456789
-+123456789
-+123456789
-+123456789
-+123456789
-+123456789
-+123456789
-+123456789
-+123456789
Deleted: CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.test.test_acl.patch
===================================================================
--- CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.test.test_acl.patch 2009-05-01 17:16:27 UTC (rev 4129)
+++ CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.test.test_acl.patch 2009-05-01 17:19:57 UTC (rev 4130)
@@ -1,108 +0,0 @@
-Index: twisted/web2/dav/test/test_acl.py
-===================================================================
---- twisted/web2/dav/test/test_acl.py (revision 19773)
-+++ twisted/web2/dav/test/test_acl.py (working copy)
-@@ -30,6 +30,7 @@
- from twisted.web2.auth import basic
- from twisted.web2.stream import MemoryStream
- from twisted.web2.dav import davxml
-+from twisted.web2.dav.resource import DAVPrincipalCollectionResource
- from twisted.web2.dav.util import davXMLFromStream
- from twisted.web2.dav.auth import TwistedPasswordProperty, IPrincipal, DavRealm, TwistedPropertyChecker, AuthenticationWrapper
-
-@@ -38,6 +39,25 @@
- from twisted.web2.dav.test.util import Site, serialize
- from twisted.web2.dav.test.test_resource import TestResource, TestDAVPrincipalResource
-
-+class TestPrincipalsCollection(DAVPrincipalCollectionResource, TestResource):
-+ def __init__(self, url, children):
-+ DAVPrincipalCollectionResource.__init__(self, url)
-+ TestResource.__init__(self, url, children, principalCollections=(self,))
-+
-+ def principalForUser(self, user):
-+ return self.principalForShortName('users', user)
-+
-+ def principalForAuthID(self, creds):
-+ return self.principalForShortName('users', creds.username)
-+
-+ def principalForShortName(self, type, shortName):
-+ typeResource = self.children.get(type, None)
-+ user = None
-+ if typeResource:
-+ user = typeResource.children.get(shortName, None)
-+
-+ return user
-+
- class ACL(twisted.web2.dav.test.util.TestCase):
- """
- RFC 3744 (WebDAV ACL) tests.
-@@ -46,8 +66,18 @@
- if not hasattr(self, "docroot"):
- self.docroot = self.mktemp()
- os.mkdir(self.docroot)
-- rootresource = self.resource_class(self.docroot)
-
-+ userResource = TestDAVPrincipalResource("/principals/users/user01")
-+ userResource.writeDeadProperty(TwistedPasswordProperty("user01"))
-+
-+ principalCollection = TestPrincipalsCollection(
-+ "/principals/",
-+ children={"users": TestPrincipalsCollection(
-+ "/principals/users/",
-+ children={"user01": userResource})})
-+
-+ rootResource = self.resource_class(self.docroot, principalCollections=(principalCollection,))
-+
- portal = Portal(DavRealm())
- portal.registerChecker(TwistedPropertyChecker())
-
-@@ -56,26 +86,14 @@
- loginInterfaces = (IPrincipal,)
-
- self.site = Site(AuthenticationWrapper(
-- rootresource,
-+ rootResource,
- portal,
- credentialFactories,
- loginInterfaces
- ))
-
-- rootresource.setAccessControlList(self.grant(davxml.All()))
-+ rootResource.setAccessControlList(self.grant(davxml.All()))
-
-- userresource = TestDAVPrincipalResource("/principals/user01")
-- userresource.writeDeadProperty(TwistedPasswordProperty.fromString("user01"))
--
-- rootresource.putChild(
-- "principals",
-- TestResource("/principals", {"user01": userresource})
-- )
--
-- rootresource.writeDeadProperty(
-- davxml.PrincipalCollectionSet(davxml.HRef("/principals/"))
-- )
--
- for name, acl in (
- ("none" , self.grant()),
- ("read" , self.grant(davxml.Read())),
-@@ -361,9 +379,7 @@
- if method == "GET":
- ok = responsecode.OK
- elif method == "REPORT":
-- # BAD_REQUEST in the allowed case, because we're not actually
-- # including the required XML in the request body.
-- ok = responsecode.BAD_REQUEST
-+ ok = responsecode.MULTI_STATUS
- else:
- raise AssertionError("We shouldn't be here. (method = %r)" % (method,))
-
-@@ -377,6 +393,9 @@
- path = os.path.join(self.docroot, name)
-
- request = SimpleRequest(self.site, method, "/" + name)
-+ if method == "REPORT":
-+ request.stream = MemoryStream(davxml.PrincipalPropertySearch().toxml())
-+
- _add_auth_header(request)
-
- def test(response, code=code, path=path):
Deleted: CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.test.test_copy.patch
===================================================================
--- CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.test.test_copy.patch 2009-05-01 17:16:27 UTC (rev 4129)
+++ CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.test.test_copy.patch 2009-05-01 17:19:57 UTC (rev 4130)
@@ -1,24 +0,0 @@
-Index: twisted/web2/dav/test/test_copy.py
-===================================================================
---- twisted/web2/dav/test/test_copy.py (revision 19773)
-+++ twisted/web2/dav/test/test_copy.py (working copy)
-@@ -22,9 +22,9 @@
- # DRI: Wilfredo Sanchez, wsanchez at apple.com
- ##
-
-+from hashlib import md5
- import os
- import urllib
--import md5
-
- import twisted.web2.dav.test.util
- from twisted.web2 import responsecode
-@@ -161,7 +161,7 @@
- yield (request, do_test)
-
- def sumFile(path):
-- m = md5.new()
-+ m = md5()
-
- if os.path.isfile(path):
- f = file(path)
Deleted: CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.test.test_pipeline.patch
===================================================================
--- CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.test.test_pipeline.patch 2009-05-01 17:16:27 UTC (rev 4129)
+++ CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.test.test_pipeline.patch 2009-05-01 17:19:57 UTC (rev 4130)
@@ -1,74 +0,0 @@
-Index: twisted/web2/dav/test/test_pipeline.py
-===================================================================
---- twisted/web2/dav/test/test_pipeline.py (revision 0)
-+++ twisted/web2/dav/test/test_pipeline.py (revision 0)
-@@ -0,0 +1,69 @@
-+##
-+# Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
-+#
-+# Permission is hereby granted, free of charge, to any person obtaining a copy
-+# of this software and associated documentation files (the "Software"), to deal
-+# in the Software without restriction, including without limitation the rights
-+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-+# copies of the Software, and to permit persons to whom the Software is
-+# furnished to do so, subject to the following conditions:
-+#
-+# The above copyright notice and this permission notice shall be included in all
-+# copies or substantial portions of the Software.
-+#
-+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-+# SOFTWARE.
-+#
-+# DRI: Wilfredo Sanchez, wsanchez at apple.com
-+##
-+from twisted.internet import utils
-+from twisted.web2.test import test_server
-+from twisted.web2 import resource
-+from twisted.web2 import http
-+from twisted.web2.test import test_http
-+import sys
-+
-+from twisted.internet.defer import waitForDeferred, deferredGenerator
-+
-+from twisted.python import util
-+
-+class Pipeline(test_server.BaseCase):
-+ """
-+ Pipelined request
-+ """
-+ class TestResource(resource.LeafResource):
-+ def render(self, req):
-+ return http.Response(stream="Host:%s, Path:%s"%(req.host, req.path))
-+
-+ def setUp(self):
-+ self.root = self.TestResource()
-+
-+ def chanrequest(self, root, uri, length, headers, method, version, prepath, content):
-+ self.cr = super(Pipeline, self).chanrequest(root, uri, length, headers, method, version, prepath, content)
-+ return self.cr
-+
-+ def test_root(self):
-+
-+ def _testStreamRead(x):
-+ self.assertTrue(self.cr.request.stream.length == 0)
-+
-+ return self.assertResponse(
-+ (self.root, 'http://host/path', {"content-type":"text/plain",}, "PUT", None, '', "This is some text."),
-+ (405, {}, None)).addCallback(_testStreamRead)
-+
-+class SSLPipeline(test_http.SSLServerTest):
-+
-+ @deferredGenerator
-+ def testAdvancedWorkingness(self):
-+ args = ('-u', util.sibpath(__file__, "tworequest_client.py"), "basic",
-+ str(self.port), self.type)
-+ d = waitForDeferred(utils.getProcessOutputAndValue(sys.executable, args=args))
-+ yield d; out,err,code = d.getResult()
-+
-+ self.assertEquals(code, 0, "Error output:\n%s" % (err,))
-+ self.assertEquals(out, "HTTP/1.1 403 Forbidden\r\nContent-Length: 0\r\n\r\nHTTP/1.1 403 Forbidden\r\nContent-Length: 0\r\n\r\n")
Deleted: CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.test.test_prop.patch
===================================================================
--- CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.test.test_prop.patch 2009-05-01 17:16:27 UTC (rev 4129)
+++ CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.test.test_prop.patch 2009-05-01 17:19:57 UTC (rev 4130)
@@ -1,69 +0,0 @@
-Index: twisted/web2/dav/test/test_prop.py
-===================================================================
---- twisted/web2/dav/test/test_prop.py (revision 19773)
-+++ twisted/web2/dav/test/test_prop.py (working copy)
-@@ -21,6 +21,8 @@
- #
- # DRI: Wilfredo Sanchez, wsanchez at apple.com
- ##
-+from twisted.web2.dav.element.rfc4331 import QuotaUsedBytes
-+from twisted.web2.dav.element.rfc4331 import QuotaAvailableBytes
-
- import random
-
-@@ -37,8 +39,13 @@
- from twisted.web2.dav.test.util import serialize
- import twisted.web2.dav.test.util
-
--live_properties = [lookupElement(qname)() for qname in DAVResource.liveProperties if qname[0] == dav_namespace]
-+# Remove dynamic live properties that exist
-+dynamicLiveProperties = (
-+ (dav_namespace, "quota-available-bytes" ),
-+ (dav_namespace, "quota-used-bytes" ),
-+)
-
-+
- #
- # See whether dead properties are available
- #
-@@ -49,6 +56,10 @@
- """
- PROPFIND, PROPPATCH requests
- """
-+
-+ def liveProperties(self):
-+ return [lookupElement(qname)() for qname in self.resource_class.liveProperties if (qname[0] == dav_namespace) and qname not in dynamicLiveProperties]
-+
- def test_PROPFIND_basic(self):
- """
- PROPFIND request
-@@ -85,7 +96,7 @@
- self.fail("PROPFIND failed (status %s) to locate live properties: %s"
- % (status.code, properties))
-
-- properties_to_find = [p.qname() for p in live_properties]
-+ properties_to_find = [p.qname() for p in self.liveProperties()]
-
- for property in properties:
- qname = property.qname()
-@@ -102,7 +113,7 @@
- else:
- self.fail("No response for URI /")
-
-- query = davxml.PropertyFind(davxml.PropertyContainer(*live_properties))
-+ query = davxml.PropertyFind(davxml.PropertyContainer(*self.liveProperties()))
-
- request = SimpleRequest(self.site, "PROPFIND", "/")
-
-@@ -146,9 +157,9 @@
- % (status.code, properties))
-
- if which.name == "allprop":
-- properties_to_find = [p.qname() for p in live_properties if not p.hidden]
-+ properties_to_find = [p.qname() for p in self.liveProperties() if not p.hidden]
- else:
-- properties_to_find = [p.qname() for p in live_properties]
-+ properties_to_find = [p.qname() for p in self.liveProperties()]
-
- for property in properties:
- qname = property.qname()
Deleted: CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.test.test_quota.patch
===================================================================
--- CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.test.test_quota.patch 2009-05-01 17:16:27 UTC (rev 4129)
+++ CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.test.test_quota.patch 2009-05-01 17:19:57 UTC (rev 4130)
@@ -1,206 +0,0 @@
-Index: twisted/web2/dav/test/test_quota.py
-===================================================================
---- twisted/web2/dav/test/test_quota.py (revision 0)
-+++ twisted/web2/dav/test/test_quota.py (revision 0)
-@@ -0,0 +1,201 @@
-+##
-+# Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
-+#
-+# Permission is hereby granted, free of charge, to any person obtaining a copy
-+# of this software and associated documentation files (the "Software"), to deal
-+# in the Software without restriction, including without limitation the rights
-+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-+# copies of the Software, and to permit persons to whom the Software is
-+# furnished to do so, subject to the following conditions:
-+#
-+# The above copyright notice and this permission notice shall be included in all
-+# copies or substantial portions of the Software.
-+#
-+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-+# SOFTWARE.
-+#
-+# DRI: Wilfredo Sanchez, wsanchez at apple.com
-+##
-+
-+from twisted.web2 import responsecode
-+from twisted.web2.iweb import IResponse
-+from twisted.web2.stream import FileStream
-+
-+import twisted.web2.dav.test.util
-+from twisted.web2.test.test_server import SimpleRequest
-+from twisted.web2.dav.test.util import Site
-+from twisted.web2.dav import davxml
-+import os
-+
-+class QuotaBase(twisted.web2.dav.test.util.TestCase):
-+
-+ def setUp(self):
-+
-+ #super(Quota, self).setUp()
-+ self.docroot = self.mktemp()
-+ os.mkdir(self.docroot)
-+ rootresource = self.resource_class(self.docroot)
-+ rootresource.setAccessControlList(self.grantInherit(davxml.All()))
-+ self.site = Site(rootresource)
-+ self.site.resource.setQuotaRoot(None, 100000)
-+
-+ def checkQuota(self, value):
-+ def _defer(quota):
-+ self.assertEqual(quota, value)
-+
-+ d = self.site.resource.currentQuotaUse(None)
-+ d.addCallback(_defer)
-+ return d
-+
-+class QuotaEmpty(QuotaBase):
-+
-+ def test_Empty_Quota(self):
-+
-+ return self.checkQuota(0)
-+
-+class QuotaPUT(QuotaBase):
-+
-+ def test_Quota_PUT(self):
-+ """
-+ Quota change on PUT
-+ """
-+ dst_uri = "/dst"
-+
-+ def checkResult(response):
-+ response = IResponse(response)
-+
-+ if response.code != responsecode.CREATED:
-+ self.fail("Incorrect response code for PUT (%s != %s)"
-+ % (response.code, responsecode.CREATED))
-+
-+ return self.checkQuota(100)
-+
-+ request = SimpleRequest(self.site, "PUT", dst_uri)
-+ request.stream = FileStream(file(os.path.join(os.path.dirname(__file__), "data", "quota_100.txt"), "rb"))
-+ return self.send(request, checkResult)
-+
-+class QuotaDELETE(QuotaBase):
-+
-+ def test_Quota_DELETE(self):
-+ """
-+ Quota change on DELETE
-+ """
-+ dst_uri = "/dst"
-+
-+ def checkPUTResult(response):
-+ response = IResponse(response)
-+
-+ if response.code != responsecode.CREATED:
-+ self.fail("Incorrect response code for PUT (%s != %s)"
-+ % (response.code, responsecode.CREATED))
-+
-+ def doDelete(_ignore):
-+ def checkDELETEResult(response):
-+ response = IResponse(response)
-+
-+ if response.code != responsecode.NO_CONTENT:
-+ self.fail("Incorrect response code for PUT (%s != %s)"
-+ % (response.code, responsecode.NO_CONTENT))
-+
-+ return self.checkQuota(0)
-+
-+ request = SimpleRequest(self.site, "DELETE", dst_uri)
-+ return self.send(request, checkDELETEResult)
-+
-+ d = self.checkQuota(100)
-+ d.addCallback(doDelete)
-+ return d
-+
-+ request = SimpleRequest(self.site, "PUT", dst_uri)
-+ request.stream = FileStream(file(os.path.join(os.path.dirname(__file__), "data", "quota_100.txt"), "rb"))
-+ return self.send(request, checkPUTResult)
-+
-+class OverQuotaPUT(QuotaBase):
-+
-+ def test_Quota_PUT(self):
-+ """
-+ Quota change on PUT
-+ """
-+ dst_uri = "/dst"
-+
-+ self.site.resource.setQuotaRoot(None, 90)
-+
-+ def checkResult(response):
-+ response = IResponse(response)
-+
-+ if response.code != responsecode.INSUFFICIENT_STORAGE_SPACE:
-+ self.fail("Incorrect response code for PUT (%s != %s)"
-+ % (response.code, responsecode.INSUFFICIENT_STORAGE_SPACE))
-+
-+ return self.checkQuota(0)
-+
-+ request = SimpleRequest(self.site, "PUT", dst_uri)
-+ request.stream = FileStream(file(os.path.join(os.path.dirname(__file__), "data", "quota_100.txt"), "rb"))
-+ return self.send(request, checkResult)
-+
-+class QuotaOKAdjustment(QuotaBase):
-+
-+ def test_Quota_OK_Adjustment(self):
-+ """
-+ Quota adjustment OK
-+ """
-+ dst_uri = "/dst"
-+
-+ def checkPUTResult(response):
-+ response = IResponse(response)
-+
-+ if response.code != responsecode.CREATED:
-+ self.fail("Incorrect response code for PUT (%s != %s)"
-+ % (response.code, responsecode.CREATED))
-+
-+ def doOKAdjustment(_ignore):
-+ def checkAdjustmentResult(_ignore):
-+ return self.checkQuota(10)
-+
-+ d = self.site.resource.quotaSizeAdjust(None, -90)
-+ d.addCallback(checkAdjustmentResult)
-+ return d
-+
-+ d = self.checkQuota(100)
-+ d.addCallback(doOKAdjustment)
-+ return d
-+
-+ request = SimpleRequest(self.site, "PUT", dst_uri)
-+ request.stream = FileStream(file(os.path.join(os.path.dirname(__file__), "data", "quota_100.txt"), "rb"))
-+ return self.send(request, checkPUTResult)
-+
-+class QuotaBadAdjustment(QuotaBase):
-+
-+ def test_Quota_Bad_Adjustment(self):
-+ """
-+ Quota adjustment too much
-+ """
-+ dst_uri = "/dst"
-+
-+ def checkPUTResult(response):
-+ response = IResponse(response)
-+
-+ if response.code != responsecode.CREATED:
-+ self.fail("Incorrect response code for PUT (%s != %s)"
-+ % (response.code, responsecode.CREATED))
-+
-+ def doBadAdjustment(_ignore):
-+ def checkAdjustmentResult(_ignore):
-+ return self.checkQuota(100)
-+
-+ d = self.site.resource.quotaSizeAdjust(None, -200)
-+ d.addCallback(checkAdjustmentResult)
-+ return d
-+
-+ d = self.checkQuota(100)
-+ d.addCallback(doBadAdjustment)
-+ return d
-+
-+ request = SimpleRequest(self.site, "PUT", dst_uri)
-+ request.stream = FileStream(file(os.path.join(os.path.dirname(__file__), "data", "quota_100.txt"), "rb"))
-+ return self.send(request, checkPUTResult)
Deleted: CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.test.test_resource.patch
===================================================================
--- CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.test.test_resource.patch 2009-05-01 17:16:27 UTC (rev 4129)
+++ CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.test.test_resource.patch 2009-05-01 17:19:57 UTC (rev 4130)
@@ -1,102 +0,0 @@
-Index: twisted/web2/dav/test/test_resource.py
-===================================================================
---- twisted/web2/dav/test/test_resource.py (revision 19773)
-+++ twisted/web2/dav/test/test_resource.py (working copy)
-@@ -192,13 +192,10 @@
- class AccessTests(TestCase):
- def setUp(self):
- gooduser = TestDAVPrincipalResource('/users/gooduser')
-+ gooduser.writeDeadProperty(TwistedPasswordProperty('goodpass'))
-
-- gooduser.writeDeadProperty(
-- TwistedPasswordProperty.fromString('goodpass'))
--
- baduser = TestDAVPrincipalResource('/users/baduser')
-- baduser.writeDeadProperty(
-- TwistedPasswordProperty.fromString('badpass'))
-+ baduser.writeDeadProperty(TwistedPasswordProperty('badpass'))
-
- protected = TestResource('/protected')
- protected.setAccessControlList(davxml.ACL(
-@@ -282,7 +279,8 @@
- # Has auth; should allow
-
- request = SimpleRequest(site, "GET", "/")
-- request.user = davxml.Principal(davxml.HRef("/users/d00d"))
-+ request.authnUser = davxml.Principal(davxml.HRef("/users/d00d"))
-+ request.authzUser = davxml.Principal(davxml.HRef("/users/d00d"))
- d = request.locateResource('/')
- d.addCallback(_checkPrivileges)
- d.addCallback(expectOK)
-@@ -301,6 +299,8 @@
-
- return self.checkSecurity(request)
-
-+ test_authorize.todo = "Needs refactoring"
-+
- def test_badUsernameOrPassword(self):
- request = SimpleRequest(self.site, 'GET', '/protected')
-
-@@ -316,6 +316,8 @@
-
- return d
-
-+ test_badUsernameOrPassword.todo = "Needs refactoring."
-+
- def test_lacksPrivileges(self):
- request = SimpleRequest(self.site, 'GET', '/protected')
-
-@@ -348,12 +350,12 @@
- davxml.Grant(davxml.Privilege(davxml.All())),
- davxml.Protected()))
-
-- def __init__(self, uri=None, children=None):
-+ def __init__(self, uri=None, children=None, principalCollections=()):
- """
- @param uri: A string respresenting the URI of the given resource
- @param children: a dictionary of names to Resources
- """
--
-+ DAVResource.__init__(self, principalCollections=principalCollections)
- self.children = children
- self.uri = uri
-
-@@ -380,8 +382,8 @@
- return succeed(davPrivilegeSet)
-
- def currentPrincipal(self, request):
-- if hasattr(request, "user"):
-- return request.user
-+ if hasattr(request, "authzUser"):
-+ return request.authzUser
- else:
- return davxml.Principal(davxml.Unauthenticated())
-
-@@ -399,18 +401,21 @@
-
- def accessControlList(self, request, **kwargs):
- return succeed(self.acl)
--
-
- class AuthAllResource (TestResource):
-- """Give Authenticated principals all privileges deny everything else
- """
-+ Give Authenticated principals all privileges and deny everyone else.
-+ """
- acl = davxml.ACL(
- davxml.ACE(
- davxml.Principal(davxml.Authenticated()),
- davxml.Grant(davxml.Privilege(davxml.All())),
-- davxml.Protected()))
--
-+ davxml.Protected()
-+ )
-+ )
-
- class TestDAVPrincipalResource(DAVPrincipalResource, TestResource):
-- """Get deadProperties from TestResource
-- """
-+ # Get dead properties from TestResource
-+
-+ def principalURL(self):
-+ return self.uri
Deleted: CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.test.test_static.patch
===================================================================
--- CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.test.test_static.patch 2009-05-01 17:16:27 UTC (rev 4129)
+++ CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.test.test_static.patch 2009-05-01 17:19:57 UTC (rev 4130)
@@ -1,10 +0,0 @@
-Index: twisted/web2/dav/test/test_static.py
-===================================================================
---- twisted/web2/dav/test/test_static.py (revision 19773)
-+++ twisted/web2/dav/test/test_static.py (working copy)
-@@ -60,3 +60,5 @@
- d.addCallback(assertListing)
-
- return d
-+
-+ test_renderPrivileges.todo = "We changed the rules here; test needs an update"
Deleted: CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.test.test_stream.patch
===================================================================
--- CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.test.test_stream.patch 2009-05-01 17:16:27 UTC (rev 4129)
+++ CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.test.test_stream.patch 2009-05-01 17:19:57 UTC (rev 4130)
@@ -1,56 +0,0 @@
-Index: twisted/web2/dav/test/test_stream.py
-===================================================================
---- twisted/web2/dav/test/test_stream.py (revision 0)
-+++ twisted/web2/dav/test/test_stream.py (revision 0)
-@@ -0,0 +1,51 @@
-+##
-+# Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
-+#
-+# Permission is hereby granted, free of charge, to any person obtaining a copy
-+# of this software and associated documentation files (the "Software"), to deal
-+# in the Software without restriction, including without limitation the rights
-+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-+# copies of the Software, and to permit persons to whom the Software is
-+# furnished to do so, subject to the following conditions:
-+#
-+# The above copyright notice and this permission notice shall be included in all
-+# copies or substantial portions of the Software.
-+#
-+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-+# SOFTWARE.
-+##
-+
-+from twisted.trial import unittest
-+from twisted.web2.stream import MemoryStream
-+from twisted.web2.dav.stream import MD5StreamWrapper
-+import md5
-+
-+class Stream(unittest.TestCase):
-+ """
-+ MD5StreamWrapper tests.
-+ """
-+ def test_simple(self):
-+ """
-+ Simple test
-+ """
-+
-+ data = """I am sorry Dave, I can't do that.
-+--HAL 9000
-+"""
-+
-+ datastream = MemoryStream(data)
-+ stream = MD5StreamWrapper(datastream)
-+
-+ while stream.read() is not None:
-+ pass
-+ stream.close()
-+
-+ m = md5.new()
-+ m.update(data)
-+
-+ self.assertEqual(m.hexdigest(), stream.getMD5())
Deleted: CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.test.test_xml.patch
===================================================================
--- CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.test.test_xml.patch 2009-05-01 17:16:27 UTC (rev 4129)
+++ CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.test.test_xml.patch 2009-05-01 17:19:57 UTC (rev 4130)
@@ -1,88 +0,0 @@
-Index: twisted/web2/dav/test/test_xml.py
-===================================================================
---- twisted/web2/dav/test/test_xml.py (revision 0)
-+++ twisted/web2/dav/test/test_xml.py (revision 0)
-@@ -0,0 +1,83 @@
-+##
-+# Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
-+#
-+# Permission is hereby granted, free of charge, to any person obtaining a copy
-+# of this software and associated documentation files (the "Software"), to deal
-+# in the Software without restriction, including without limitation the rights
-+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-+# copies of the Software, and to permit persons to whom the Software is
-+# furnished to do so, subject to the following conditions:
-+#
-+# The above copyright notice and this permission notice shall be included in all
-+# copies or substantial portions of the Software.
-+#
-+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-+# SOFTWARE.
-+##
-+
-+from twisted.trial import unittest
-+from twisted.web2.dav import davxml
-+
-+class XML(unittest.TestCase):
-+ """
-+ XML tests.
-+ """
-+ def test_parse(self):
-+ """
-+ Simple parsing
-+ """
-+ doc = davxml.WebDAVDocument.fromString(
-+ """<?xml version="1.0" encoding="utf-8" ?>"""
-+ """<D:multistatus xmlns:D="DAV:">"""
-+ """ <D:response>"""
-+ """ <D:href>http://webdav.sb.aol.com/webdav/secret</D:href>"""
-+ """ <D:status>HTTP/1.1 403 Forbidden</D:status>"""
-+ """ </D:response>"""
-+ """</D:multistatus>"""
-+ )
-+ self.assertEquals(
-+ doc,
-+ davxml.WebDAVDocument(
-+ davxml.MultiStatus(
-+ davxml.Response(
-+ davxml.HRef("http://webdav.sb.aol.com/webdav/secret"),
-+ davxml.Status("HTTP/1.1 403 Forbidden"),
-+ )
-+ )
-+ )
-+ )
-+
-+ def test_serialize_unserialize(self):
-+ """
-+ Serialization and unserialization results in equivalent document.
-+ """
-+ doc = davxml.WebDAVDocument(
-+ davxml.MultiStatus(
-+ davxml.Response(
-+ davxml.HRef("http://webdav.sb.aol.com/webdav/secret"),
-+ davxml.Status("HTTP/1.1 403 Forbidden"),
-+ )
-+ )
-+ )
-+ self.assertEquals(doc, davxml.WebDAVDocument.fromString(doc.toxml()))
-+
-+ def test_unknownElement(self):
-+ """
-+ Serialization and unserialization of unknown element.
-+ """
-+ doc = davxml.WebDAVDocument.fromString(
-+ """<?xml version="1.0" encoding="utf-8" ?>"""
-+ """<T:foo xmlns:T="http://twistedmatrix.com/"/>"""
-+ )
-+
-+ foo = davxml.WebDAVUnknownElement()
-+ foo.namespace = "http://twistedmatrix.com/"
-+ foo.name = "foo"
-+
-+ self.assertEquals(doc, davxml.WebDAVDocument(foo))
-+ self.assertEquals(doc, davxml.WebDAVDocument.fromString(doc.toxml()))
Deleted: CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.test.tworequest_client.patch
===================================================================
--- CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.test.tworequest_client.patch 2009-05-01 17:16:27 UTC (rev 4129)
+++ CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.test.tworequest_client.patch 2009-05-01 17:19:57 UTC (rev 4130)
@@ -1,52 +0,0 @@
-Index: twisted/web2/dav/test/tworequest_client.py
-===================================================================
---- twisted/web2/dav/test/tworequest_client.py (revision 0)
-+++ twisted/web2/dav/test/tworequest_client.py (revision 0)
-@@ -0,0 +1,47 @@
-+import socket, sys
-+
-+test_type = sys.argv[1]
-+port = int(sys.argv[2])
-+socket_type = sys.argv[3]
-+
-+s = socket.socket(socket.AF_INET)
-+s.connect(("127.0.0.1", port))
-+s.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, 40000)
-+
-+if socket_type == 'ssl':
-+ s2 = socket.ssl(s)
-+ send=s2.write
-+ recv=s2.read
-+else:
-+ send=s.send
-+ recv=s.recv
-+
-+print >> sys.stderr, ">> Making %s request to port %d" % (socket_type, port)
-+
-+send("PUT /forbidden HTTP/1.1\r\n")
-+send("Host: localhost\r\n")
-+
-+print >> sys.stderr, ">> Sending lots of data"
-+send("Content-Length: 100\r\n\r\n")
-+send("X"*100)
-+
-+send("PUT /forbidden HTTP/1.1\r\n")
-+send("Host: localhost\r\n")
-+
-+print >> sys.stderr, ">> Sending lots of data"
-+send("Content-Length: 100\r\n\r\n")
-+send("X"*100)
-+
-+#import time
-+#time.sleep(5)
-+print >> sys.stderr, ">> Getting data"
-+data=''
-+while len(data) < 299999:
-+ try:
-+ x=recv(10000)
-+ except:
-+ break
-+ if x == '':
-+ break
-+ data+=x
-+sys.stdout.write(data)
Deleted: CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.test.util.patch
===================================================================
--- CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.test.util.patch 2009-05-01 17:16:27 UTC (rev 4129)
+++ CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.test.util.patch 2009-05-01 17:19:57 UTC (rev 4130)
@@ -1,20 +0,0 @@
-Index: twisted/web2/dav/test/util.py
-===================================================================
---- twisted/web2/dav/test/util.py (revision 19773)
-+++ twisted/web2/dav/test/util.py (working copy)
-@@ -184,10 +184,11 @@
- d.addCallback(lambda resource: resource.renderHTTP(request))
- d.addCallback(request._cbFinishRender)
-
-- if type(callback) is tuple:
-- d.addCallbacks(*callback)
-- else:
-- d.addCallback(callback)
-+ if callback:
-+ if type(callback) is tuple:
-+ d.addCallbacks(*callback)
-+ else:
-+ d.addCallback(callback)
-
- return d
-
Deleted: CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.util.patch
===================================================================
--- CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.util.patch 2009-05-01 17:16:27 UTC (rev 4129)
+++ CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.util.patch 2009-05-01 17:19:57 UTC (rev 4130)
@@ -1,23 +0,0 @@
-Index: twisted/web2/dav/util.py
-===================================================================
---- twisted/web2/dav/util.py (revision 19773)
-+++ twisted/web2/dav/util.py (working copy)
-@@ -37,6 +37,7 @@
- "normalizeURL",
- "joinURL",
- "parentForURL",
-+ "unimplemented",
- "bindMethods",
- ]
-
-@@ -76,7 +77,9 @@
-
- def parse(xml):
- try:
-- return davxml.WebDAVDocument.fromString(xml)
-+ doc = davxml.WebDAVDocument.fromString(xml)
-+ doc.root_element.validate()
-+ return doc
- except ValueError:
- log.err("Bad XML:\n%s" % (xml,))
- raise
Deleted: CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.xattrprops.patch
===================================================================
--- CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.xattrprops.patch 2009-05-01 17:16:27 UTC (rev 4129)
+++ CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.dav.xattrprops.patch 2009-05-01 17:19:57 UTC (rev 4130)
@@ -1,169 +0,0 @@
-Index: twisted/web2/dav/xattrprops.py
-===================================================================
---- twisted/web2/dav/xattrprops.py (revision 19773)
-+++ twisted/web2/dav/xattrprops.py (working copy)
-@@ -33,15 +33,24 @@
-
- import urllib
- import sys
-+import zlib
-+from time import sleep
-+from random import random
-+from errno import EAGAIN
-+from zlib import compress, decompress
-+from cPickle import loads as unpickle, PicklingError, UnpicklingError
-
- import xattr
-
- if getattr(xattr, 'xattr', None) is None:
- raise ImportError("wrong xattr package imported")
-
-+from twisted.python import log
-+from twisted.python.failure import Failure
- from twisted.web2 import responsecode
- from twisted.web2.http import HTTPError, StatusResponse
- from twisted.web2.dav import davxml
-+from twisted.web2.dav.http import statusForFailure
-
- class xattrPropertyStore (object):
- """
-@@ -66,16 +75,8 @@
- deadPropertyXattrPrefix = "user."
-
- def _encode(clazz, name):
-- #
-- # FIXME: The xattr API in Mac OS 10.4.2 breaks if you have "/" in an
-- # attribute name (radar://4202440). We'll quote the strings to get rid
-- # of "/" characters for now.
-- #
-- result = list("{%s}%s" % name)
-- for i in range(len(result)):
-- c = result[i]
-- if c in "%/": result[i] = "%%%02X" % (ord(c),)
-- r = clazz.deadPropertyXattrPrefix + ''.join(result)
-+ result = urllib.quote("{%s}%s" % name, safe='{}:')
-+ r = clazz.deadPropertyXattrPrefix + result
- return r
-
- def _decode(clazz, name):
-@@ -97,19 +98,83 @@
-
- def get(self, qname):
- try:
-- value = self.attrs[self._encode(qname)]
-+ data = self.attrs[self._encode(qname)]
- except KeyError:
- raise HTTPError(StatusResponse(
- responsecode.NOT_FOUND,
- "No such property: {%s}%s" % qname
- ))
-+ except Exception, e:
-+ raise HTTPError(StatusResponse(
-+ statusForFailure(Failure()),
-+ "Unable to read property: {%s}%s" % qname
-+ ))
-
-- doc = davxml.WebDAVDocument.fromString(value)
-+ #
-+ # Serialize XML data to an xattr. The storage format has
-+ # changed over time:
-+ #
-+ # 1- Started with XML
-+ # 2- Started compressing the XML due to limits on xattr size
-+ # 3- Switched to pickle which is faster, still compressing
-+ # 4- Back to compressed XML for interoperability, size
-+ #
-+ # We only write the current format, but we also read the old
-+ # ones for compatibility.
-+ #
-+ legacy = False
-
-- return doc.root_element
-+ try:
-+ data = decompress(data)
-+ except zlib.error:
-+ legacy = True
-
-+ try:
-+ doc = davxml.WebDAVDocument.fromString(data)
-+ result = doc.root_element
-+ except ValueError:
-+ legacy = True
-+
-+ try:
-+ result = unpickle(data)
-+ except UnpicklingError:
-+ msg = ("Invalid property value stored on server: {%s}%s %s"
-+ % (qname[0], qname[1], data))
-+ log.err(msg)
-+ raise HTTPError(StatusResponse(responsecode.INTERNAL_SERVER_ERROR, msg))
-+
-+ if legacy:
-+ # Try to upgrade the property to the current format
-+ try:
-+ log.msg("Upgrading property %r on resource %r"
-+ % (qname, self.resource.fp.path))
-+ self.set(result)
-+ except Exception, e:
-+ #
-+ # Hrm, that failed. No need to re-raise here, since
-+ # we can do what we were asked to do, but let's
-+ # complain about it.
-+ #
-+ log.err("Error while upgrading property %r on resource %r: %s"
-+ % (qname, self.resource.fp.path, e))
-+
-+ return result
-+
- def set(self, property):
-- self.attrs[self._encode(property.qname())] = property.toxml()
-+ for n in range(20):
-+ data = compress(property.toxml())
-+ try:
-+ self.attrs[self._encode(property.qname())] = data
-+ except Exception, e:
-+ if e.errno == EAGAIN and n < 19:
-+ sleep(random() / 10) # OMG Brutal Hax
-+ else:
-+ raise HTTPError(StatusResponse(
-+ statusForFailure(Failure()),
-+ "Unable to write property: %s" % (property.sname(),)
-+ ))
-+ else:
-+ break
-
- # Update the resource because we've modified it
- self.resource.fp.restat()
-@@ -121,15 +186,31 @@
- # RFC 2518 Section 12.13.1 says that removal of
- # non-existing property is not an error.
- pass
-+ except Exception, e:
-+ raise HTTPError(StatusResponse(
-+ statusForFailure(Failure()),
-+ "Unable to delete property: {%s}%s" % qname
-+ ))
-
- def contains(self, qname):
- try:
- return self._encode(qname) in self.attrs
- except TypeError:
- return False
-+ except Exception, e:
-+ raise HTTPError(StatusResponse(
-+ statusForFailure(Failure()),
-+ "Unable to read properties"
-+ ))
-
- def list(self):
- prefix = self.deadPropertyXattrPrefix
- prefix_len = len(prefix)
-
-- return [ self._decode(name) for name in self.attrs if name.startswith(prefix) ]
-+ try:
-+ return [ self._decode(name) for name in self.attrs if name.startswith(prefix) ]
-+ except Exception, e:
-+ raise HTTPError(StatusResponse(
-+ statusForFailure(Failure()),
-+ "Unable to list properties"
-+ ))
Deleted: CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.http.patch
===================================================================
--- CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.http.patch 2009-05-01 17:16:27 UTC (rev 4129)
+++ CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.http.patch 2009-05-01 17:19:57 UTC (rev 4130)
@@ -1,57 +0,0 @@
-Index: twisted/web2/http.py
-===================================================================
---- twisted/web2/http.py (revision 19773)
-+++ twisted/web2/http.py (working copy)
-@@ -26,7 +26,7 @@
- from twisted.web2 import http_headers
- from twisted.web2 import iweb
- from twisted.web2 import stream
--from twisted.web2.stream import IByteStream
-+from twisted.web2.stream import IByteStream, readAndDiscard
-
- defaultPortForScheme = {'http': 80, 'https':443, 'ftp':21}
-
-@@ -66,9 +66,9 @@
- object.
- @type codeOrResponse: C{int} or L{http.Response}
- """
-- Exception.__init__(self)
-- self.response = iweb.IResponse(codeOrResponse)
-- self.args = str(self.response)
-+ response = iweb.IResponse(codeOrResponse)
-+ Exception.__init__(self, str(response))
-+ self.response = response
-
- def __repr__(self):
- return "<%s %s>" % (self.__class__.__name__, self.response)
-@@ -408,9 +408,22 @@
- def _sendContinue(self):
- self.chanRequest.writeIntermediateResponse(responsecode.CONTINUE)
-
-- def _finished(self, x):
-+ def _reallyFinished(self, x):
- """We are finished writing data."""
- self.chanRequest.finish()
-+
-+ def _finished(self, x):
-+ """
-+ We are finished writing data.
-+ But we need to check that we have also finished reading all data as we
-+ might have sent a, for example, 401 response before we read any data.
-+ To make sure that the stream/producer sequencing works properly we need
-+ to discard the remaining data in the request.
-+ """
-+ if self.stream.length != 0:
-+ return readAndDiscard(self.stream).addCallback(self._reallyFinished).addErrback(self._error)
-+ else:
-+ self._reallyFinished(x)
-
- def _error(self, reason):
- if reason.check(error.ConnectionLost):
-@@ -471,5 +484,5 @@
- else:
- components.registerAdapter(compat.OldResourceAdapter, resource.IResource, iweb.IOldNevowResource)
-
--__all__ = ['HTTPError', 'NotModifiedResponse', 'Request', 'Response', 'checkIfRange', 'checkPreconditions', 'defaultPortForScheme', 'parseVersion', 'splitHostPort']
-+__all__ = ['HTTPError', 'NotModifiedResponse', 'Request', 'Response', 'StatusResponse', 'RedirectResponse', 'checkIfRange', 'checkPreconditions', 'defaultPortForScheme', 'parseVersion', 'splitHostPort']
-
Deleted: CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.log.patch
===================================================================
--- CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.log.patch 2009-05-01 17:16:27 UTC (rev 4129)
+++ CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.log.patch 2009-05-01 17:19:57 UTC (rev 4130)
@@ -1,13 +0,0 @@
-Index: twisted/web2/log.py
-===================================================================
---- twisted/web2/log.py (revision 19773)
-+++ twisted/web2/log.py (working copy)
-@@ -88,7 +88,7 @@
- class LogWrapperResource(resource.WrapperResource):
- def hook(self, request):
- # Insert logger
-- request.addResponseFilter(logFilter, atEnd=True)
-+ request.addResponseFilter(logFilter, atEnd=True, onlyOnce=True)
-
- monthname = [None, 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
- 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
Deleted: CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.server.patch
===================================================================
--- CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.server.patch 2009-05-01 17:16:27 UTC (rev 4129)
+++ CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.server.patch 2009-05-01 17:19:57 UTC (rev 4130)
@@ -1,129 +0,0 @@
-Index: twisted/web2/server.py
-===================================================================
---- twisted/web2/server.py (revision 19773)
-+++ twisted/web2/server.py (working copy)
-@@ -26,6 +26,7 @@
- from twisted.web2 import http_headers
- from twisted.web2.filter.range import rangefilter
- from twisted.web2 import error
-+from twisted.web2.dav.util import joinURL
-
- from twisted.web2 import version as web2_version
- from twisted import __version__ as twisted_version
-@@ -143,6 +144,9 @@
- error.defaultErrorHandler, defaultHeadersFilter]
-
- def __init__(self, *args, **kw):
-+
-+ self.initTime = time.time()
-+
- if kw.has_key('site'):
- self.site = kw['site']
- del kw['site']
-@@ -150,17 +154,36 @@
- self._initialprepath = kw['prepathuri']
- del kw['prepathuri']
-
-+ self._resourcesByURL = {}
-+ self._urlsByResource = {}
-+
- # Copy response filters from the class
- self.responseFilters = self.responseFilters[:]
- self.files = {}
- self.resources = []
- http.Request.__init__(self, *args, **kw)
-+ try:
-+ self.serverInstance = self.chanRequest.channel.transport.server.port
-+ except AttributeError:
-+ self.serverInstance = "Unknown"
-
-- def addResponseFilter(self, f, atEnd=False):
-+ def addResponseFilter(self, filter, atEnd=False, onlyOnce=False):
-+ """
-+ Add a response filter to this request.
-+ Response filters are applied to the response to this request in order.
-+ @param filter: a callable which takes an response argument and returns
-+ a response object.
-+ @param atEnd: if C{True}, C{filter} is added at the end of the list of
-+ response filters; if C{False}, it is added to the beginning.
-+ @param onlyOnce: if C{True}, C{filter} is not added to the list of
-+ response filters if it already in the list.
-+ """
-+ if onlyOnce and filter in self.responseFilters:
-+ return
- if atEnd:
-- self.responseFilters.append(f)
-+ self.responseFilters.append(filter)
- else:
-- self.responseFilters.insert(0, f)
-+ self.responseFilters.insert(0, filter)
-
- def unparseURL(self, scheme=None, host=None, port=None,
- path=None, params=None, querystring=None, fragment=None):
-@@ -265,6 +288,7 @@
-
- d = defer.Deferred()
- d.addCallback(self._getChild, self.site.resource, self.postpath)
-+ d.addCallback(self._rememberResource, "/" + "/".join(quote(s) for s in self.postpath))
- d.addCallback(lambda res, req: res.renderHTTP(req), self)
- d.addCallback(self._cbFinishRender)
- d.addErrback(self._processingFailed)
-@@ -321,7 +345,6 @@
- if newpath is StopTraversal:
- # We need to rethink how to do this.
- #if newres is res:
-- self._rememberResource(res, url)
- return res
- #else:
- # raise ValueError("locateChild must not return StopTraversal with a resource other than self.")
-@@ -337,7 +360,6 @@
- self.prepath.append(self.postpath.pop(0))
-
- child = self._getChild(None, newres, newpath, updatepaths=updatepaths)
-- self._rememberResource(child, url)
-
- return child
-
-@@ -347,6 +369,7 @@
- """
- Remember the URL of a visited resource.
- """
-+ self._resourcesByURL[url] = resource
- self._urlsByResource[resource] = url
- return resource
-
-@@ -386,7 +409,8 @@
- The contained response will have a status code of
- L{responsecode.BAD_REQUEST}.
- """
-- if url is None: return None
-+ if url is None:
-+ return defer.succeed(None)
-
- #
- # Parse the URL
-@@ -407,9 +431,13 @@
- "URL is not on this site (%s://%s/): %s" % (scheme, self.headers.getHeader("host"), url)
- ))
-
-- segments = path.split("/")
-+ # Look for cached value
-+ cached = self._resourcesByURL.get(path, None)
-+ if cached is not None:
-+ return defer.succeed(cached)
-+
-+ segments = unquote(path).split("/")
- assert segments[0] == "", "URL path didn't begin with '/': %s" % (path,)
-- segments = map(unquote, segments[1:])
-
- def notFound(f):
- f.trap(http.HTTPError)
-@@ -417,7 +445,7 @@
- return f
- return None
-
-- d = defer.maybeDeferred(self._getChild, None, self.site.resource, segments, updatepaths=False)
-+ d = defer.maybeDeferred(self._getChild, None, self.site.resource, segments[1:], updatepaths=False)
- d.addCallback(self._rememberResource, path)
- d.addErrback(notFound)
- return d
Deleted: CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.static.patch
===================================================================
--- CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.static.patch 2009-05-01 17:16:27 UTC (rev 4129)
+++ CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.static.patch 2009-05-01 17:19:57 UTC (rev 4130)
@@ -1,33 +0,0 @@
-Index: twisted/web2/static.py
-===================================================================
---- twisted/web2/static.py (revision 19773)
-+++ twisted/web2/static.py (working copy)
-@@ -9,7 +9,6 @@
- # System Imports
- import os, time, stat
- import tempfile
--import md5
-
- # Sibling Imports
- from twisted.web2 import http_headers, resource
-@@ -200,7 +199,10 @@
- super(File, self).__init__()
-
- self.putChildren = {}
-- self.fp = filepath.FilePath(path)
-+ if isinstance(path, filepath.FilePath):
-+ self.fp = path
-+ else:
-+ self.fp = filepath.FilePath(path)
- # Remove the dots from the path to split
- self.defaultType = defaultType
- self.ignoredExts = list(ignoredExts)
-@@ -383,7 +385,7 @@
- return responsecode.NOT_FOUND
-
- if self.fp.isdir():
-- if req.uri[-1] != "/":
-+ if req.path[-1] != "/":
- # Redirect to include trailing '/' in URI
- return http.RedirectResponse(req.unparseURL(path=req.path+'/'))
- else:
Deleted: CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.test.test_http.patch
===================================================================
--- CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.test.test_http.patch 2009-05-01 17:16:27 UTC (rev 4129)
+++ CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.test.test_http.patch 2009-05-01 17:19:57 UTC (rev 4130)
@@ -1,23 +0,0 @@
-Index: twisted/web2/test/test_http.py
-===================================================================
---- twisted/web2/test/test_http.py (revision 19773)
-+++ twisted/web2/test/test_http.py (working copy)
-@@ -324,6 +324,9 @@
- def connectionLost(self, reason):
- self.cmds.append(('connectionLost', reason))
-
-+ def _finished(self, x):
-+ self._reallyFinished(x)
-+
- class TestResponse(object):
- implements(iweb.IResponse)
-
-@@ -1017,6 +1020,8 @@
- response = TestResponse()
- if self.uri == "/error":
- response.code=402
-+ elif self.uri == "/forbidden":
-+ response.code=403
- else:
- response.code=404
- response.write("URI %s unrecognized." % self.uri)
Deleted: CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.test.test_httpauth.patch
===================================================================
--- CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.test.test_httpauth.patch 2009-05-01 17:16:27 UTC (rev 4129)
+++ CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.web2.test.test_httpauth.patch 2009-05-01 17:19:57 UTC (rev 4130)
@@ -1,243 +0,0 @@
-Index: twisted/web2/test/test_httpauth.py
-===================================================================
---- twisted/web2/test/test_httpauth.py (revision 19773)
-+++ twisted/web2/test/test_httpauth.py (working copy)
-@@ -1,3 +1,4 @@
-+from twisted.internet.defer import inlineCallbacks
- import md5
- from twisted.internet import address
- from twisted.trial import unittest
-@@ -41,22 +42,25 @@
- self.username = 'dreid'
- self.password = 'S3CuR1Ty'
-
-+ @inlineCallbacks
- def testUsernamePassword(self):
- response = base64.encodestring('%s:%s' % (
- self.username,
- self.password))
-
-- creds = self.credentialFactory.decode(response, _trivial_GET)
-+ creds = (yield self.credentialFactory.decode(response, _trivial_GET))
- self.failUnless(creds.checkPassword(self.password))
-
-+ @inlineCallbacks
- def testIncorrectPassword(self):
- response = base64.encodestring('%s:%s' % (
- self.username,
- 'incorrectPassword'))
-
-- creds = self.credentialFactory.decode(response, _trivial_GET)
-+ creds = (yield self.credentialFactory.decode(response, _trivial_GET))
- self.failIf(creds.checkPassword(self.password))
-
-+ @inlineCallbacks
- def testIncorrectPadding(self):
- response = base64.encodestring('%s:%s' % (
- self.username,
-@@ -64,7 +68,7 @@
-
- response = response.strip('=')
-
-- creds = self.credentialFactory.decode(response, _trivial_GET)
-+ creds = (yield self.credentialFactory.decode(response, _trivial_GET))
- self.failUnless(creds.checkPassword(self.password))
-
- def testInvalidCredentials(self):
-@@ -135,6 +139,7 @@
- )
- return expected
-
-+ @inlineCallbacks
- def test_getChallenge(self):
- """
- Test that all the required fields exist in the challenge,
-@@ -142,42 +147,44 @@
- DigestCredentialFactory
- """
-
-- challenge = self.credentialFactory.getChallenge(clientAddress)
-+ challenge = (yield self.credentialFactory.getChallenge(clientAddress))
- self.assertEquals(challenge['qop'], 'auth')
- self.assertEquals(challenge['realm'], 'test realm')
- self.assertEquals(challenge['algorithm'], 'md5')
- self.assertTrue(challenge.has_key("nonce"))
- self.assertTrue(challenge.has_key("opaque"))
-
-+ @inlineCallbacks
- def test_response(self):
- """
- Test that we can decode a valid response to our challenge
- """
-
-- challenge = self.credentialFactory.getChallenge(clientAddress)
-+ challenge = (yield self.credentialFactory.getChallenge(clientAddress))
-
- clientResponse = authRequest1 % (
- challenge['nonce'],
- self.getDigestResponse(challenge, "00000001"),
- challenge['opaque'])
-
-- creds = self.credentialFactory.decode(clientResponse, _trivial_GET)
-+ creds = (yield self.credentialFactory.decode(clientResponse, _trivial_GET))
- self.failUnless(creds.checkPassword('password'))
-
-+ @inlineCallbacks
- def test_multiResponse(self):
- """
- Test that multiple responses to to a single challenge are handled
- successfully.
- """
-
-- challenge = self.credentialFactory.getChallenge(clientAddress)
-+ challenge = (yield self.credentialFactory.getChallenge(clientAddress))
-
- clientResponse = authRequest1 % (
- challenge['nonce'],
- self.getDigestResponse(challenge, "00000001"),
- challenge['opaque'])
-
-- creds = self.credentialFactory.decode(clientResponse, _trivial_GET)
-+ creds = (yield self.credentialFactory.decode(clientResponse, _trivial_GET))
- self.failUnless(creds.checkPassword('password'))
-
- clientResponse = authRequest2 % (
-@@ -185,24 +192,25 @@
- self.getDigestResponse(challenge, "00000002"),
- challenge['opaque'])
-
-- creds = self.credentialFactory.decode(clientResponse, _trivial_GET)
-+ creds = (yield self.credentialFactory.decode(clientResponse, _trivial_GET))
- self.failUnless(creds.checkPassword('password'))
-
-+ @inlineCallbacks
- def test_failsWithDifferentMethod(self):
- """
- Test that the response fails if made for a different request method
- than it is being issued for.
- """
-
-- challenge = self.credentialFactory.getChallenge(clientAddress)
-+ challenge = (yield self.credentialFactory.getChallenge(clientAddress))
-
- clientResponse = authRequest1 % (
- challenge['nonce'],
- self.getDigestResponse(challenge, "00000001"),
- challenge['opaque'])
-
-- creds = self.credentialFactory.decode(clientResponse,
-- SimpleRequest(None, 'POST', '/'))
-+ creds = (yield self.credentialFactory.decode(clientResponse,
-+ SimpleRequest(None, 'POST', '/')))
- self.failIf(creds.checkPassword('password'))
-
- def test_noUsername(self):
-@@ -247,20 +255,21 @@
- _trivial_GET)
- self.assertEquals(str(e), "Invalid response, no opaque given.")
-
-+ @inlineCallbacks
- def test_checkHash(self):
- """
- Check that given a hash of the form 'username:realm:password'
- we can verify the digest challenge
- """
-
-- challenge = self.credentialFactory.getChallenge(clientAddress)
-+ challenge = (yield self.credentialFactory.getChallenge(clientAddress))
-
- clientResponse = authRequest1 % (
- challenge['nonce'],
- self.getDigestResponse(challenge, "00000001"),
- challenge['opaque'])
-
-- creds = self.credentialFactory.decode(clientResponse, _trivial_GET)
-+ creds = (yield self.credentialFactory.decode(clientResponse, _trivial_GET))
-
- self.failUnless(creds.checkHash(
- md5.md5('username:test realm:password').hexdigest()))
-@@ -268,6 +277,7 @@
- self.failIf(creds.checkHash(
- md5.md5('username:test realm:bogus').hexdigest()))
-
-+ @inlineCallbacks
- def test_invalidOpaque(self):
- """
- Test that login fails when the opaque does not contain all the required
-@@ -276,7 +286,7 @@
-
- credentialFactory = FakeDigestCredentialFactory('md5', 'test realm')
-
-- challenge = credentialFactory.getChallenge(clientAddress)
-+ challenge = (yield credentialFactory.getChallenge(clientAddress))
-
- self.assertRaises(
- error.LoginFailed,
-@@ -302,6 +312,7 @@
- challenge['nonce'],
- clientAddress.host)
-
-+ @inlineCallbacks
- def test_incompatibleNonce(self):
- """
- Test that login fails when the given nonce from the response, does not
-@@ -310,7 +321,7 @@
-
- credentialFactory = FakeDigestCredentialFactory('md5', 'test realm')
-
-- challenge = credentialFactory.getChallenge(clientAddress)
-+ challenge = (yield credentialFactory.getChallenge(clientAddress))
-
- badNonceOpaque = credentialFactory.generateOpaque(
- '1234567890',
-@@ -330,6 +341,7 @@
- '',
- clientAddress.host)
-
-+ @inlineCallbacks
- def test_incompatibleClientIp(self):
- """
- Test that the login fails when the request comes from a client ip
-@@ -338,7 +350,7 @@
-
- credentialFactory = FakeDigestCredentialFactory('md5', 'test realm')
-
-- challenge = credentialFactory.getChallenge(clientAddress)
-+ challenge = (yield credentialFactory.getChallenge(clientAddress))
-
- badNonceOpaque = credentialFactory.generateOpaque(
- challenge['nonce'],
-@@ -351,6 +363,7 @@
- challenge['nonce'],
- clientAddress.host)
-
-+ @inlineCallbacks
- def test_oldNonce(self):
- """
- Test that the login fails when the given opaque is older than
-@@ -359,7 +372,7 @@
-
- credentialFactory = FakeDigestCredentialFactory('md5', 'test realm')
-
-- challenge = credentialFactory.getChallenge(clientAddress)
-+ challenge = (yield credentialFactory.getChallenge(clientAddress))
-
- key = '%s,%s,%s' % (challenge['nonce'],
- clientAddress.host,
-@@ -376,6 +389,7 @@
- challenge['nonce'],
- clientAddress.host)
-
-+ @inlineCallbacks
- def test_mismatchedOpaqueChecksum(self):
- """
- Test that login fails when the opaque checksum fails verification
-@@ -383,7 +397,7 @@
-
- credentialFactory = FakeDigestCredentialFactory('md5', 'test realm')
-
-- challenge = credentialFactory.getChallenge(clientAddress)
-+ challenge = (yield credentialFactory.getChallenge(clientAddress))
-
-
- key = '%s,%s,%s' % (challenge['nonce'],
Deleted: CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.words.protocols.jabber.sasl_mechanisms.patch
===================================================================
--- CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.words.protocols.jabber.sasl_mechanisms.patch 2009-05-01 17:16:27 UTC (rev 4129)
+++ CalendarServer/branches/exarkun/update-twisted-3816-3/lib-patches/Twisted/twisted.words.protocols.jabber.sasl_mechanisms.patch 2009-05-01 17:19:57 UTC (rev 4130)
@@ -1,86 +0,0 @@
-Index: twisted/words/protocols/jabber/sasl_mechanisms.py
-===================================================================
---- twisted/words/protocols/jabber/sasl_mechanisms.py (revision 19773)
-+++ twisted/words/protocols/jabber/sasl_mechanisms.py (working copy)
-@@ -7,8 +7,13 @@
- Protocol agnostic implementations of SASL authentication mechanisms.
- """
-
--import md5, binascii, random, time, os
-+import binascii, random, time, os
-
-+try:
-+ from hashlib import md5
-+except ImportError:
-+ from md5 import new as md5
-+
- from zope.interface import Interface, Attribute, implements
-
- class ISASLMechanism(Interface):
-@@ -108,16 +113,43 @@
- @return: challenge directives and their values.
- @rtype: L{dict} of L{str} to L{str}.
- """
-- directive_list = challenge.split(',')
-- directives = {}
-- for directive in directive_list:
-- name, value = directive.split('=')
-- value = value.replace("'","")
-- value = value.replace('"','')
-- directives[name] = value
-- return directives
-+ s = challenge
-+ paramDict = {}
-+ cur = 0
-+ remainingParams = True
-+ while remainingParams:
-+ # Parse a param. We can't just split on commas, because there can
-+ # be some commas inside (quoted) param values, e.g.:
-+ # qop="auth,auth-int"
-
-+ middle = s.index("=", cur)
-+ name = s[cur:middle].lstrip()
-+ middle += 1
-+ if s[middle] == '"':
-+ middle += 1
-+ end = s.index('"', middle)
-+ value = s[middle:end]
-+ cur = s.find(',', end) + 1
-+ if cur == 0:
-+ remainingParams = False
-+ else:
-+ end = s.find(',', middle)
-+ if end == -1:
-+ value = s[middle:].rstrip()
-+ remainingParams = False
-+ else:
-+ value = s[middle:end].rstrip()
-+ cur = end + 1
-+ paramDict[name] = value
-
-+ for param in ('qop', 'cipher'):
-+ if param in paramDict:
-+ paramDict[param] = paramDict[param].split(',')
-+
-+ return paramDict
-+
-+
-+
- def _unparse(self, directives):
- """
- Create message string from directives.
-@@ -153,7 +185,7 @@
- """
-
- def H(s):
-- return md5.new(s).digest()
-+ return md5(s).digest()
-
- def HEX(n):
- return binascii.b2a_hex(n)
-@@ -196,4 +228,4 @@
-
-
- def _gen_nonce(self):
-- return md5.new("%s:%s:%s" % (str(random.random()) , str(time.gmtime()),str(os.getpid()))).hexdigest()
-+ return md5("%s:%s:%s" % (str(random.random()) , str(time.gmtime()),str(os.getpid()))).hexdigest()
Modified: CalendarServer/branches/exarkun/update-twisted-3816-3/run
===================================================================
--- CalendarServer/branches/exarkun/update-twisted-3816-3/run 2009-05-01 17:16:27 UTC (rev 4129)
+++ CalendarServer/branches/exarkun/update-twisted-3816-3/run 2009-05-01 17:19:57 UTC (rev 4130)
@@ -104,7 +104,7 @@
'R') reactor="-R ${OPTARG}"; ;;
't') service_type="${OPTARG}"; ;;
'K') read_key="${OPTARG}"; ;;
- 'S') profile="-p ${OPTARG}"; ;;
+ 'S') profile="--profiler cprofile -p ${OPTARG}"; ;;
'g') do_get="true" ; do_setup="false"; do_run="false"; ;;
's') do_get="true" ; do_setup="true" ; do_run="false"; ;;
'p') do_get="false"; do_setup="false"; do_run="false"; print_path="true"; ;;
@@ -655,8 +655,8 @@
proto="svn";
;;
esac;
-svn_uri="${proto}://svn.twistedmatrix.com/svn/Twisted/branches/dav-acl-1608-4";
-svn_get "Twisted" "${twisted}" "${svn_uri}" 19773;
+svn_uri="${proto}://svn.twistedmatrix.com/svn/Twisted/branches/dav-take-two-3081-4";
+svn_get "Twisted" "${twisted}" "${svn_uri}" 26741;
# No py_build step, since we tend to do edit Twisted, we want the sources in
# PYTHONPATH, not a build directory.
Modified: CalendarServer/branches/exarkun/update-twisted-3816-3/twistedcaldav/notify.py
===================================================================
--- CalendarServer/branches/exarkun/update-twisted-3816-3/twistedcaldav/notify.py 2009-05-01 17:16:27 UTC (rev 4129)
+++ CalendarServer/branches/exarkun/update-twisted-3816-3/twistedcaldav/notify.py 2009-05-01 17:19:57 UTC (rev 4130)
@@ -720,7 +720,8 @@
return
try:
- iq = IQ(self.xmlStream, type='get')
+ # XXX This codepath is not unit tested
+ iq = IQ(self.xmlStream, 'get')
child = iq.addElement('pubsub',
defaultUri=self.pubsubNS+"#owner")
child = child.addElement('configure')
@@ -755,7 +756,7 @@
formElement = configureElement.firstChildElement()
if formElement['type'] == 'form':
# We've found the form; start building a response
- filledIq = IQ(self.xmlStream, type='set')
+ filledIq = IQ(self.xmlStream, 'set')
filledPubSub = filledIq.addElement('pubsub',
defaultUri=self.pubsubNS+"#owner")
filledConfigure = filledPubSub.addElement('configure')
@@ -784,7 +785,8 @@
valueElement.addContent(value)
# filledForm.addChild(field)
if configMatches:
- cancelIq = IQ(self.xmlStream, type='set')
+ # XXX This codepath is not unit tested
+ cancelIq = IQ(self.xmlStream, 'set')
cancelPubSub = cancelIq.addElement('pubsub',
defaultUri=self.pubsubNS+"#owner")
cancelConfig = cancelPubSub.addElement('configure')
@@ -892,7 +894,7 @@
def requestRoster(self):
if self.doRoster:
self.roster = {}
- rosterIq = IQ(self.xmlStream, type='get')
+ rosterIq = IQ(self.xmlStream, 'get')
rosterIq.addElement("query", "jabber:iq:roster")
d = rosterIq.send()
d.addCallback(self.handleRoster)
@@ -950,7 +952,8 @@
self.xmlStream.send(response)
# remove from roster as well
- removal = IQ(self.xmlStream, type='set')
+ # XXX This codepath is not unit tested
+ removal = IQ(self.xmlStream, 'set')
query = removal.addElement("query", "jabber:iq:roster")
query.addElement("item")
query.item["jid"] = iq["from"]
Modified: CalendarServer/branches/exarkun/update-twisted-3816-3/twistedcaldav/test/test_index.py
===================================================================
--- CalendarServer/branches/exarkun/update-twisted-3816-3/twistedcaldav/test/test_index.py 2009-05-01 17:16:27 UTC (rev 4129)
+++ CalendarServer/branches/exarkun/update-twisted-3816-3/twistedcaldav/test/test_index.py 2009-05-01 17:19:57 UTC (rev 4130)
@@ -19,7 +19,8 @@
import twistedcaldav.test.util
from twistedcaldav.test.util import InMemoryMemcacheProtocol
from twistedcaldav.index import ReservationError, MemcachedUIDReserver
-from twisted.web2.test.test_http import deferLater
+from twisted.internet import reactor
+from twisted.internet.task import deferLater
class SQLIndexTests (twistedcaldav.test.util.TestCase):
"""
@@ -80,7 +81,7 @@
d.addCallback(lambda _: self.db.reserveUID(uid))
d.addCallback(lambda _: self.db.isReservedUID(uid))
d.addCallback(self.assertTrue)
- d.addCallback(lambda _: deferLater(2))
+ d.addCallback(lambda _: deferLater(reactor, 2, lambda: None))
d.addCallback(lambda _: self.db.isReservedUID(uid))
d.addCallback(self.assertFalse)
d.addBoth(_finally)
Modified: CalendarServer/branches/exarkun/update-twisted-3816-3/twistedcaldav/test/test_upgrade.py
===================================================================
--- CalendarServer/branches/exarkun/update-twisted-3816-3/twistedcaldav/test/test_upgrade.py 2009-05-01 17:16:27 UTC (rev 4129)
+++ CalendarServer/branches/exarkun/update-twisted-3816-3/twistedcaldav/test/test_upgrade.py 2009-05-01 17:19:57 UTC (rev 4130)
@@ -188,7 +188,7 @@
# Verify these values do require updating:
#
- expected = "<?xml version='1.0' encoding='UTF-8'?>\r\n<calendar-free-busy-set xmlns='urn:ietf:params:xml:ns:caldav'>\r\n <href xmlns='DAV:'>/calendars/__uids__/6423F94A-6B76-4A3A-815B-D52CFD77935D/calendar/</href>\r\n</calendar-free-busy-set>\r\n"
+ expected = "<?xml version='1.0' encoding='UTF-8'?><calendar-free-busy-set xmlns='urn:ietf:params:xml:ns:caldav'>\r\n <href xmlns='DAV:'>/calendars/__uids__/6423F94A-6B76-4A3A-815B-D52CFD77935D/calendar/</href>\r\n</calendar-free-busy-set>"
# Uncompressed XML
value = "<?xml version='1.0' encoding='UTF-8'?>\r\n<calendar-free-busy-set xmlns='urn:ietf:params:xml:ns:caldav'>\r\n <href xmlns='DAV:'>/calendars/users/wsanchez/calendar</href>\r\n</calendar-free-busy-set>\r\n"
@@ -314,7 +314,7 @@
{
"@xattrs" :
{
- freeBusyAttr : zlib.compress("<?xml version='1.0' encoding='UTF-8'?>\r\n<calendar-free-busy-set xmlns='urn:ietf:params:xml:ns:caldav'>\r\n <href xmlns='DAV:'>/calendars/__uids__/6423F94A-6B76-4A3A-815B-D52CFD77935D/calendar/</href>\r\n</calendar-free-busy-set>\r\n"),
+ freeBusyAttr : zlib.compress("<?xml version='1.0' encoding='UTF-8'?><calendar-free-busy-set xmlns='urn:ietf:params:xml:ns:caldav'>\r\n <href xmlns='DAV:'>/calendars/__uids__/6423F94A-6B76-4A3A-815B-D52CFD77935D/calendar/</href>\r\n</calendar-free-busy-set>"),
},
},
},
@@ -430,7 +430,7 @@
{
"@xattrs" :
{
- freeBusyAttr : zlib.compress("<?xml version='1.0' encoding='UTF-8'?>\r\n<calendar-free-busy-set xmlns='urn:ietf:params:xml:ns:caldav'>\r\n <href xmlns='DAV:'>/calendars/__uids__/6423F94A-6B76-4A3A-815B-D52CFD77935D/calendar/</href>\r\n</calendar-free-busy-set>\r\n"),
+ freeBusyAttr : zlib.compress("<?xml version='1.0' encoding='UTF-8'?><calendar-free-busy-set xmlns='urn:ietf:params:xml:ns:caldav'>\r\n <href xmlns='DAV:'>/calendars/__uids__/6423F94A-6B76-4A3A-815B-D52CFD77935D/calendar/</href>\r\n</calendar-free-busy-set>"),
},
},
},
@@ -550,7 +550,7 @@
{
"@xattrs" :
{
- freeBusyAttr : zlib.compress("<?xml version='1.0' encoding='UTF-8'?>\r\n<calendar-free-busy-set xmlns='urn:ietf:params:xml:ns:caldav'>\r\n <href xmlns='DAV:'>/calendars/__uids__/6423F94A-6B76-4A3A-815B-D52CFD77935D/calendar/</href>\r\n</calendar-free-busy-set>\r\n"),
+ freeBusyAttr : zlib.compress("<?xml version='1.0' encoding='UTF-8'?><calendar-free-busy-set xmlns='urn:ietf:params:xml:ns:caldav'>\r\n <href xmlns='DAV:'>/calendars/__uids__/6423F94A-6B76-4A3A-815B-D52CFD77935D/calendar/</href>\r\n</calendar-free-busy-set>"),
},
},
},
Modified: CalendarServer/branches/exarkun/update-twisted-3816-3/twistedcaldav/test/util.py
===================================================================
--- CalendarServer/branches/exarkun/update-twisted-3816-3/twistedcaldav/test/util.py 2009-05-01 17:16:27 UTC (rev 4129)
+++ CalendarServer/branches/exarkun/update-twisted-3816-3/twistedcaldav/test/util.py 2009-05-01 17:19:57 UTC (rev 4130)
@@ -117,6 +117,7 @@
try:
if xattr.getxattr(childPath, attr) != value:
print "Xattr mismatch:", childPath, attr
+ print (xattr.getxattr(childPath, attr), " != ", value)
return False
except:
return False
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20090501/8204b811/attachment-0001.html>
More information about the calendarserver-changes
mailing list