for alecm:

Changed Traversable to call the original __bobo_traverse__ method before 
attempting to use attribute access to find the desired object.  This ensures 
that the monkeypatched object retains the same behavior as the original 
object during traversal.  Also, added checks to see if the request is a 
WebDAV request in which case attribute lookup is performed without 
acquisition (see BaseRequest.traverse for why this is important).
parent e9ebf4b7
......@@ -64,6 +64,9 @@ def test_traversable():
... <five:traversable
... class="Products.Five.browser.tests.test_traversable.SimpleClass"
... />
... <five:traversable
... class="Products.Five.tests.testing.FiveTraversableFolder"
... />
...
... <browser:page
... for="Products.Five.tests.testing.fancycontent.IFancyContent"
......@@ -99,6 +102,63 @@ def test_traversable():
...
Fancy, fancy
Without five traversable, if there had been an attrubute something-else,
the __bobo_traverse__ method would have still been used instead of the
atribute, let's make sure we preserve that behavior.
>>> self.folder.fancy.an_attribute = 'This is an attribute'
>>> print http(r'''
... GET /test_folder_1_/fancy/an_attribute HTTP/1.1
... ''')
HTTP/1.1 200 OK
...
an_attribute
If we use WebDAV to get an object no acquisition should be performed,
otherwise content creation will break:
>>> from Products.Five.tests.testing import manage_addFiveTraversableFolder
>>> manage_addFiveTraversableFolder(self.folder, 'traversable_folder', 'Traversable')
Let's verify that we can get our object properties via WebDAV:
>>> print http(r'''
... PROPFIND /test_folder_1_/fancy HTTP/1.1
... Content-Type: text/xml; charset="utf-8"
... Depth: 0
...
... <?xml version="1.0" encoding="utf-8"?>
... <DAV:propfind xmlns:DAV="DAV:"
... xmlns:zope="http://www.zope.org/propsets/default">
... <DAV:prop><zope:title/></DAV:prop>
... </DAV:propfind>
... ''')
HTTP/1.1 200 OK
...
PROPFIND
And that a normal http request will acquire the object:
>>> print http(r'''
... GET /test_folder_1_/traversable_folder/fancy HTTP/1.1
... ''')
HTTP/1.1 200 OK
...
<FancyContent at >
But that a WebDAV request will not:
>>> print http(r'''
... PROPFIND /test_folder_1_/traversable_folder/fancy HTTP/1.1
... Content-Type: text/xml; charset="utf-8"
... Depth: 0
...
... <?xml version="1.0" encoding="utf-8"?>
... <DAV:propfind xmlns:DAV="DAV:"
... xmlns:zope="http://www.zope.org/propsets/default">
... <DAV:prop><zope:title/></DAV:prop>
... </DAV:propfind>
... ''')
HTTP/1.1 404 Not Found
...
Clean up:
......
......@@ -16,6 +16,7 @@
$Id: traversable.py 19283 2005-10-31 17:43:51Z philikon $
"""
from zExceptions import NotFound
from ZPublisher import xmlrpc
from zope.component import getMultiAdapter, ComponentLookupError
from zope.interface import implements, Interface
......@@ -29,8 +30,11 @@ from zope.app.publication.browser import setDefaultSkin
from zope.app.interface import queryType
from AccessControl import getSecurityManager
from Acquisition import aq_base
from Products.Five.security import newInteraction
from webdav.NullResource import NullResource
_marker = object
class FakeRequest(dict):
......@@ -56,7 +60,7 @@ class Traversable:
Just raise a AttributeError to indicate traversal has failed
and let Zope do it's job.
"""
raise AttributeError, name
raise NotImplementedError
__fallback_traverse__.__five_method__ = True
def __bobo_traverse__(self, REQUEST, name):
......@@ -85,6 +89,27 @@ class Traversable:
except (ComponentLookupError, LookupError,
AttributeError, KeyError, NotFound):
pass
try:
return self.__fallback_traverse__(REQUEST, name)
except NotImplementedError:
pass
# This should at least make a half hearted attempt to care for
# potential WebDAV issues, in particular we should not perform
# acquisition for webdav requests, and should return a NullResource
# when appropriate.
method = REQUEST.get('REQUEST_METHOD', 'GET').upper()
if (len(REQUEST.get('TraversalRequestNameStack', ())) == 0 and
not (method in ('GET', 'HEAD', 'POST') and not
isinstance(REQUEST.RESPONSE, xmlrpc.Response))):
if getattr(aq_base(self), name, None) is not None:
return getattr(self, name)
else:
# XXX: This may be unnecessary as Zope itself doesn't do it,
# but it shouldn't be harmful
if (method in ('PUT', 'MKCOL') and not
isinstance(RESPONSE, xmlrpc.Response)):
return NullResource(self, name, REQUEST).__of__(self)
else:
try:
return getattr(self, name)
except AttributeError:
......@@ -93,7 +118,8 @@ class Traversable:
return self[name]
except (AttributeError, KeyError):
pass
return self.__fallback_traverse__(REQUEST, name)
raise AttributeError, name
__bobo_traverse__.__five_method__ = True
......@@ -112,3 +138,5 @@ class FiveTraversable(DefaultTraversable):
return getMultiAdapter((context, REQUEST), Interface, name)
except ComponentLookupError:
pass
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