Commit c1f7b585 authored by Chris McDonough's avatar Chris McDonough

DAV: litmus' cond_put_unlocked test (#22) exposed a bug in

        webdav.Resource.dav__simpleifhandler.  If the resource is not
        locked, and a DAV request contains an If header, no token can
        possibly match and we must return a 412 Precondition Failed
        instead of 204 No Content.
parent cc5474b0
...@@ -97,6 +97,12 @@ Zope Changes ...@@ -97,6 +97,12 @@ Zope Changes
Bugs Fixed Bugs Fixed
- DAV: litmus' cond_put_unlocked test (#22) exposed a bug in
webdav.Resource.dav__simpleifhandler. If the resource is not
locked, and a DAV request contains an If header, no token can
possibly match and we must return a 412 Precondition Failed
instead of 204 No Content.
- DAV: litmus' cond_put_corrupt_token test (#18) exposed a bug - DAV: litmus' cond_put_corrupt_token test (#18) exposed a bug
in webdav.Resource.dav__simpleifhandler. If the resource is in webdav.Resource.dav__simpleifhandler. If the resource is
locked at all, and a DAV request contains an If header, and locked at all, and a DAV request contains an If header, and
......
...@@ -152,5 +152,9 @@ InitializeClass(LockableItem) ...@@ -152,5 +152,9 @@ InitializeClass(LockableItem)
def wl_isLocked(ob): def wl_isLocked(ob):
""" Returns true if the object is locked, returns 0 if the object """ Returns true if the object is locked, returns 0 if the object
is not locked or does not implement the WriteLockInterface """ is not locked or does not implement the WriteLockInterface """
return wl_isLockable(ob) and ob.wl_isLocked()
def wl_isLockable(ob):
return (IWriteLock.providedBy(ob) or return (IWriteLock.providedBy(ob) or
WriteLockInterface.isImplementedBy(ob)) and ob.wl_isLocked() WriteLockInterface.isImplementedBy(ob))
...@@ -113,11 +113,26 @@ class Resource(ExtensionClass.Base, Lockable.LockableItem): ...@@ -113,11 +113,26 @@ class Resource(ExtensionClass.Base, Lockable.LockableItem):
def dav__simpleifhandler(self, request, response, method='PUT', def dav__simpleifhandler(self, request, response, method='PUT',
col=0, url=None, refresh=0): col=0, url=None, refresh=0):
ifhdr = request.get_header('If', None) ifhdr = request.get_header('If', None)
if Lockable.wl_isLocked(self) and (not ifhdr):
raise Locked, "Resource is locked."
if not ifhdr: return None lockable = Lockable.wl_isLockable(self)
if not Lockable.wl_isLocked(self): return None if not lockable:
# degenerate case, we shouldnt have even called this method.
return None
locked = self.wl_isLocked()
if locked and (not ifhdr):
raise Locked('Resource is locked.')
if not ifhdr:
return None
if (not locked):
# we have an if header but the resource isn't locked, we
# can shortcut checking the tags in the if header; no token
# can possibly match
raise PreconditionFailed(
'Resource not locked but If header specified')
# Since we're a simple if handler, and since some clients don't # Since we're a simple if handler, and since some clients don't
# pass in the port information in the resource part of an If # pass in the port information in the resource part of an If
......
...@@ -17,7 +17,6 @@ class TestLockItem(unittest.TestCase): ...@@ -17,7 +17,6 @@ class TestLockItem(unittest.TestCase):
verifyClass(ILockItem, LockItem) verifyClass(ILockItem, LockItem)
def test_suite(): def test_suite():
return unittest.TestSuite(( return unittest.TestSuite((
unittest.makeSuite(TestLockItem), unittest.makeSuite(TestLockItem),
......
import unittest
class TestUtilFunctions(unittest.TestCase):
def test_wl_isLocked(self):
from webdav.Lockable import wl_isLocked
unlockable = UnlockableResource()
self.failIf(wl_isLocked(unlockable))
lockable_unlocked = LockableResource(locked=False)
self.failIf(wl_isLocked(lockable_unlocked))
lockable_locked = LockableResource(locked=True)
self.failUnless(wl_isLocked(lockable_locked))
def test_wl_isLockable(self):
from webdav.Lockable import wl_isLockable
unlockable = UnlockableResource()
self.failIf(wl_isLockable(unlockable))
lockable = LockableResource(locked=False)
self.failUnless(wl_isLockable(lockable))
from webdav.interfaces import IWriteLock
from zope.interface import implements
class LockableResource:
implements(IWriteLock)
def __init__(self, locked):
self.locked = locked
def wl_isLocked(self):
return self.locked
class UnlockableResource:
pass
def test_suite():
return unittest.TestSuite((
unittest.makeSuite(TestUtilFunctions),
))
if __name__ == '__main__':
unittest.main(defaultTest='test_suite')
...@@ -56,6 +56,26 @@ class TestResource(unittest.TestCase): ...@@ -56,6 +56,26 @@ class TestResource(unittest.TestCase):
from webdav.common import Locked from webdav.common import Locked
self.assertRaises(Locked, inst.MOVE, request, response) self.assertRaises(Locked, inst.MOVE, request, response)
def test_dav__simpleifhandler_fail_cond_put_unlocked(self):
"""
DAV: litmus' cond_put_unlocked test (#22) exposed a bug in
webdav.Resource.dav__simpleifhandler. If the resource is not
locked, and a DAV request contains an If header, no token can
possibly match and we must return a 412 Precondition Failed
instead of 204 No Content.
"""
ifhdr = 'If: (<locktoken:foo>)'
request = DummyRequest({'URL':'http://example.com/foo/PUT'},
{'If':ifhdr})
response = DummyResponse()
inst = self._makeOne()
from zope.interface import directlyProvides
from webdav.interfaces import IWriteLock
directlyProvides(inst, IWriteLock)
from webdav.common import PreconditionFailed
self.assertRaises(PreconditionFailed, inst.dav__simpleifhandler,
request, response)
def test_dav__simpleifhandler_cond_put_corrupt_token(self): def test_dav__simpleifhandler_cond_put_corrupt_token(self):
""" """
DAV: litmus' cond_put_corrupt_token test (#18) exposed a bug DAV: litmus' cond_put_corrupt_token test (#18) exposed a bug
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment