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(): ...@@ -64,6 +64,9 @@ def test_traversable():
... <five:traversable ... <five:traversable
... class="Products.Five.browser.tests.test_traversable.SimpleClass" ... class="Products.Five.browser.tests.test_traversable.SimpleClass"
... /> ... />
... <five:traversable
... class="Products.Five.tests.testing.FiveTraversableFolder"
... />
... ...
... <browser:page ... <browser:page
... for="Products.Five.tests.testing.fancycontent.IFancyContent" ... for="Products.Five.tests.testing.fancycontent.IFancyContent"
...@@ -99,6 +102,63 @@ def test_traversable(): ...@@ -99,6 +102,63 @@ def test_traversable():
... ...
Fancy, fancy 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: Clean up:
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
$Id: traversable.py 19283 2005-10-31 17:43:51Z philikon $ $Id: traversable.py 19283 2005-10-31 17:43:51Z philikon $
""" """
from zExceptions import NotFound from zExceptions import NotFound
from ZPublisher import xmlrpc
from zope.component import getMultiAdapter, ComponentLookupError from zope.component import getMultiAdapter, ComponentLookupError
from zope.interface import implements, Interface from zope.interface import implements, Interface
...@@ -29,8 +30,11 @@ from zope.app.publication.browser import setDefaultSkin ...@@ -29,8 +30,11 @@ from zope.app.publication.browser import setDefaultSkin
from zope.app.interface import queryType from zope.app.interface import queryType
from AccessControl import getSecurityManager from AccessControl import getSecurityManager
from Acquisition import aq_base
from Products.Five.security import newInteraction from Products.Five.security import newInteraction
from webdav.NullResource import NullResource
_marker = object _marker = object
class FakeRequest(dict): class FakeRequest(dict):
...@@ -56,7 +60,7 @@ class Traversable: ...@@ -56,7 +60,7 @@ class Traversable:
Just raise a AttributeError to indicate traversal has failed Just raise a AttributeError to indicate traversal has failed
and let Zope do it's job. and let Zope do it's job.
""" """
raise AttributeError, name raise NotImplementedError
__fallback_traverse__.__five_method__ = True __fallback_traverse__.__five_method__ = True
def __bobo_traverse__(self, REQUEST, name): def __bobo_traverse__(self, REQUEST, name):
...@@ -86,14 +90,36 @@ class Traversable: ...@@ -86,14 +90,36 @@ class Traversable:
AttributeError, KeyError, NotFound): AttributeError, KeyError, NotFound):
pass pass
try: try:
return getattr(self, name) return self.__fallback_traverse__(REQUEST, name)
except AttributeError: except NotImplementedError:
pass
try:
return self[name]
except (AttributeError, KeyError):
pass pass
return self.__fallback_traverse__(REQUEST, name) # 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:
pass
try:
return self[name]
except (AttributeError, KeyError):
pass
raise AttributeError, name
__bobo_traverse__.__five_method__ = True __bobo_traverse__.__five_method__ = True
...@@ -112,3 +138,5 @@ class FiveTraversable(DefaultTraversable): ...@@ -112,3 +138,5 @@ class FiveTraversable(DefaultTraversable):
return getMultiAdapter((context, REQUEST), Interface, name) return getMultiAdapter((context, REQUEST), Interface, name)
except ComponentLookupError: except ComponentLookupError:
pass 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