[Zope-Checkins] SVN: Zope/branches/2.9/lib/python/Products/Five/ for alecm:

david whitfield Morriss whit at longnow.org
Tue Feb 21 20:20:09 EST 2006


Log message for revision 41744:
  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).
  
  

Changed:
  U   Zope/branches/2.9/lib/python/Products/Five/browser/tests/test_traversable.py
  U   Zope/branches/2.9/lib/python/Products/Five/traversable.py

-=-
Modified: Zope/branches/2.9/lib/python/Products/Five/browser/tests/test_traversable.py
===================================================================
--- Zope/branches/2.9/lib/python/Products/Five/browser/tests/test_traversable.py	2006-02-21 21:37:05 UTC (rev 41743)
+++ Zope/branches/2.9/lib/python/Products/Five/browser/tests/test_traversable.py	2006-02-22 01:20:07 UTC (rev 41744)
@@ -64,6 +64,9 @@
       ... <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,7 +102,64 @@
       ...
       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:
 
       >>> from zope.app.testing.placelesssetup import tearDown

Modified: Zope/branches/2.9/lib/python/Products/Five/traversable.py
===================================================================
--- Zope/branches/2.9/lib/python/Products/Five/traversable.py	2006-02-21 21:37:05 UTC (rev 41743)
+++ Zope/branches/2.9/lib/python/Products/Five/traversable.py	2006-02-22 01:20:07 UTC (rev 41744)
@@ -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.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 @@
         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):
@@ -86,14 +90,36 @@
                 AttributeError, KeyError, NotFound):
             pass
         try:
-            return getattr(self, name)
-        except AttributeError:
+            return self.__fallback_traverse__(REQUEST, name)
+        except NotImplementedError:
             pass
-        try:
-            return self[name]
-        except (AttributeError, KeyError):
-            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
 
 
@@ -112,3 +138,5 @@
             return getMultiAdapter((context, REQUEST), Interface, name)
         except ComponentLookupError:
             pass
+        
+        



More information about the Zope-Checkins mailing list