[Zope-Checkins] CVS: Zope/lib/python/ZPublisher - BaseRequest.py:1.39.20.2
Shane Hathaway
shane@digicool.com
Wed, 3 Oct 2001 17:57:48 -0400
Update of /cvs-repository/Zope/lib/python/ZPublisher
In directory cvs.zope.org:/tmp/cvs-serv22204
Modified Files:
Tag: ComponentArchitecture-branch
BaseRequest.py
Log Message:
Factored traverse() into several methods so I can read and modify it
without hurting my head. ;-)
=== Zope/lib/python/ZPublisher/BaseRequest.py 1.39.20.1 => 1.39.20.2 ===
for k,v in kw.items(): self.__dict__[k]=v
+
+class StopTraversal (Exception):
+ """
+ """
+
+
_marker=[]
class BaseRequest:
"""Provide basic ZPublisher request management
@@ -120,6 +126,7 @@
"""
maybe_webdav_client = 1
+ _no_acquire = 0
# While the following assignment is not strictly necessary, it
# prevents alot of unnecessary searches because, without it,
@@ -227,18 +234,7 @@
__repr__=__str__
-
- def traverse(self, path, response=None, validated_hook=None):
- """Traverse the object space
-
- The REQUEST must already have a PARENTS item with at least one
- object in it. This is typically the root object.
- """
- request=self
- request_get=request.get
- if response is None: response=self.response
- debug_mode=response.debug_mode
-
+ def _splitPath(self, path):
# Cleanup the path list
if path[:1]=='/': path=path[1:]
if path[-1:]=='/': path=path[:-1]
@@ -247,51 +243,208 @@
# Make sure that certain things that dont make sense
# cannot be traversed.
if item in ('REQUEST', 'aq_self', 'aq_base'):
- return response.notFoundError(path)
+ return self.response.notFoundError(path)
if not item or item=='.':
continue
elif item == '..':
del clean[-1]
else: clean.append(item)
- path=clean
-
- # How did this request come in? (HTTP GET, PUT, POST, etc.)
- method=req_method=upper(request_get('REQUEST_METHOD', 'GET'))
-
- no_acquire_flag=0
- checked_default = 0
+ return clean
- # Set the default method
- if method=='GET' or method=='POST':
- method='index_html'
- else:
+ def _setRequestMethod(self):
+ # How did this request come in? (HTTP GET, PUT, POST, etc.)
+ self._request_method = m = upper(self.get('REQUEST_METHOD', 'GET'))
+ # If it's not GET or POST and might be a WebDAV request, don't acquire.
+ if m != 'GET' and m != 'POST':
if self.maybe_webdav_client:
- # Probably a WebDAV client.
- no_acquire_flag=1
- URL=request['URL']
-
- parents=request['PARENTS']
- object=parents[-1]
- del parents[:]
+ self._no_acquire = 1
- roles = getattr(object, '__roles__', UNSPECIFIED_ROLES)
-
+ def _initialTraverse(self, object):
# if the top object has a __bobo_traverse__ method, then use it
# to possibly traverse to an alternate top-level object.
+ roles = getattr(object, '__roles__', UNSPECIFIED_ROLES)
if hasattr(object,'__bobo_traverse__'):
try:
- object=object.__bobo_traverse__(request)
- roles =getattr(object, '__roles__', UNSPECIFIED_ROLES)
- except: pass
-
- if not path and not method:
- return response.forbiddenError(self['URL'])
-
+ object = object.__bobo_traverse__(self)
+ roles = getattr(object, '__roles__', UNSPECIFIED_ROLES)
+ except: pass
# Traverse the URL to find the object:
- if hasattr(object, '__of__'):
+ if hasattr(object, '__of__'):
# Try to bind the top-level object to the request
# This is how you get 'self.REQUEST'
- object=object.__of__(RequestContainer(REQUEST=request))
+ object=object.__of__(RequestContainer(REQUEST=self))
+ return object, roles
+
+ def _addDefaultView(self, object, path):
+ """
+ returns (object, entry_name)
+ """
+ psteps = None
+ default = getattr(object, '__browser_default__', None)
+ if default is not None:
+ o, add_steps = default(self)
+ if add_steps:
+ if len(add_steps) > 1:
+ path.extend(add_steps[1:])
+ return o, add_steps[0]
+ default = self._request_method
+ if default == 'GET' or default == 'POST':
+ default = 'index_html'
+ if default and getattr(object, default, None) is not None:
+ return object, default
+ return object, None
+
+ def _traverseName(self, object, entry_name):
+ """
+ Returns object, roles.
+ """
+ got = 0
+ if entry_name[:1]=='_':
+ if self.response.debug_mode:
+ raise StopTraversal, self.response.debugError(
+ "Object name begins with an underscore at: %s"
+ % self['URL'])
+ else:
+ raise StopTraversal, self.response.forbiddenError(entry_name)
+
+ if hasattr(object,'__bobo_traverse__'):
+ subobject=object.__bobo_traverse__(self, entry_name)
+ if type(subobject) is type(()) and len(subobject) > 1:
+ # Add additional parents into the path
+ parents = self['PARENTS']
+ parents[-1:] = subobject[:-1]
+ object, subobject = subobject[-2:]
+ else:
+ try:
+
+ # Note - no_acquire_flag is necessary to support
+ # things like DAV. We have to make sure
+ # that the target object is not acquired
+ # if the request_method is other than GET
+ # or POST. Otherwise, you could never use
+ # PUT to add a new object named 'test' if
+ # an object 'test' existed above it in the
+ # heirarchy -- you'd always get the
+ # existing object :(
+
+ if (self._no_acquire and len(self.path) == 0 and
+ hasattr(object, 'aq_base')):
+ if hasattr(object.aq_base, entry_name):
+ subobject=getattr(object, entry_name)
+ else: raise AttributeError, entry_name
+ else: subobject=getattr(object, entry_name)
+ except AttributeError:
+ got=1
+ try: subobject=object[entry_name]
+ except (KeyError, IndexError,
+ TypeError, AttributeError):
+ if self.response.debug_mode:
+ raise StopTraversal, self.response.debugError(
+ "Cannot locate object at: %s" % self['URL'])
+ else:
+ raise StopTraversal, self.response.notFoundError(
+ self['URL'])
+
+ try:
+ try: doc=subobject.__doc__
+ except: doc=getattr(object, entry_name+'__doc__')
+ if not doc: raise AttributeError, entry_name
+ except:
+ raise StopTraversal, self.response.debugError(
+ "Missing doc string at: %s" % self['URL'])
+
+ roles = getattr(subobject, '__roles__', UNSPECIFIED_ROLES)
+ if roles is UNSPECIFIED_ROLES and not got:
+ # We got the subobject as an attribute, not an item,
+ # so we should check "next to it" for __roles__.
+ roles = getattr(object, entry_name+'__roles__', UNSPECIFIED_ROLES)
+
+ return subobject, roles
+
+ def _checkAuthorization(self, object, parents, roles, validated_hook):
+ user=groups=None
+ i=0
+
+ last_parent_index=len(parents)
+ if hasattr(object, '__allow_groups__'):
+ groups=object.__allow_groups__
+ inext=0
+ else:
+ inext=None
+ for i in range(last_parent_index):
+ if hasattr(parents[i],'__allow_groups__'):
+ groups=parents[i].__allow_groups__
+ inext=i+1
+ break
+
+ if inext is not None:
+ i=inext
+
+ if hasattr(groups, 'validate'): v=groups.validate
+ else: v=old_validation
+
+ auth=self._auth
+
+ if v is old_validation and roles is UNSPECIFIED_ROLES:
+ # No roles, so if we have a named group, get roles from
+ # group keys
+ if hasattr(groups,'keys'): roles=groups.keys()
+ else:
+ try: groups=groups()
+ except: pass
+ try: roles=groups.keys()
+ except: pass
+
+ if groups is None:
+ # Public group, hack structures to get it to validate
+ roles=None
+ auth=''
+
+ if v is old_validation:
+ user=old_validation(groups, self, auth, roles)
+ elif roles is UNSPECIFIED_ROLES: user=v(self, auth)
+ else: user=v(self, auth, roles)
+
+ while user is None and i < last_parent_index:
+ parent=parents[i]
+ i=i+1
+ if hasattr(parent, '__allow_groups__'):
+ groups=parent.__allow_groups__
+ else: continue
+ if hasattr(groups,'validate'): v=groups.validate
+ else: v=old_validation
+ if v is old_validation:
+ user=old_validation(groups, self, auth, roles)
+ elif roles is UNSPECIFIED_ROLES: user=v(self, auth)
+ else: user=v(self, auth, roles)
+
+ if user is None and roles != UNSPECIFIED_ROLES:
+ self.response.unauthorized()
+
+ if user is not None:
+ if validated_hook is not None: validated_hook(self, user)
+ self['AUTHENTICATED_USER']=user
+ self['AUTHENTICATION_PATH']=join(self.steps[:-i],'/')
+
+
+ def traverse(self, path_str, validated_hook=None):
+ """Traverse the object space
+
+ The REQUEST must already have a PARENTS item with at least one
+ object in it. This is typically the root object.
+ """
+ request = self
+ checked_default = 0
+ path = self._splitPath(path_str)
+ self._setRequestMethod()
+ if not path and not self._request_method:
+ return self.response.forbiddenError(self['URL'])
+
+ parents=request['PARENTS']
+ object=parents[-1]
+ del parents[:]
+
+ object, roles = self._initialTraverse(object)
parents.append(object)
steps=self.steps
@@ -305,108 +458,46 @@
# We build parents in the wrong order, so we
# need to make sure we reverse it when we're doe.
while 1:
- bpth = getattr(object, '__before_publishing_traverse__', None)
- if bpth is not None:
- bpth(object, self)
+ hook = getattr(object, '__before_publishing_traverse__', None)
+ if hook is not None:
+ hook(object, self)
- path = request.path = request['TraversalRequestNameStack']
- # Check for method:
+ path = self.path = self['TraversalRequestNameStack']
if path:
entry_name = path.pop()
else:
- # Finished the URL. Now publish a default view.
- psteps = None
+ entry_name = None
if not checked_default:
+ object, entry_name = self._addDefaultView(object, path)
checked_default = 1
- default = getattr(object, '__browser_default__', None)
- if default is not None:
- object, psteps = default(request)
- if psteps:
- request._hacked_path=1
- entry_name = psteps[0]
- path.extend(psteps[1:])
- method = None # Don't hack the path again.
- if not psteps:
- if (method and hasattr(object,method)
- and entry_name != method
- and getattr(object, method) is not None):
- request._hacked_path=1
- entry_name = method
- else:
- if (hasattr(object, '__call__') and
- hasattr(object.__call__,'__roles__')):
- roles=object.__call__.__roles__
- if request._hacked_path:
- i=rfind(URL,'/')
- if i > 0: response.setBase(URL[:i])
- break
- if not entry_name: continue
+ if entry_name:
+ self._hacked_path = 1
+ if not entry_name:
+ # Finished traversal.
+ if (hasattr(object, '__call__') and
+ hasattr(object.__call__,'__roles__')):
+ roles=object.__call__.__roles__
+ if self._hacked_path:
+ URL = self['URL']
+ i=rfind(URL,'/')
+ if i > 0: self.response.setBase(URL[:i])
+ break
+
+ if object is None:
+ # Finished traversal.
+ break
+ if not entry_name:
+ continue
step = quote(entry_name)
_steps.append(step)
- request['URL'] = URL = '%s/%s' % (request['URL'], step)
- got = 0
- if entry_name[:1]=='_':
- if debug_mode:
- return response.debugError(
- "Object name begins with an underscore at: %s" % URL)
- else: return response.forbiddenError(entry_name)
-
- if hasattr(object,'__bobo_traverse__'):
- subobject=object.__bobo_traverse__(request,entry_name)
- if type(subobject) is type(()) and len(subobject) > 1:
- # Add additional parents into the path
- parents[-1:] = subobject[:-1]
- object, subobject = subobject[-2:]
- else:
- try:
+ request['URL'] = '%s/%s' % (request['URL'], step)
- # Note - no_acquire_flag is necessary to support
- # things like DAV. We have to make sure
- # that the target object is not acquired
- # if the request_method is other than GET
- # or POST. Otherwise, you could never use
- # PUT to add a new object named 'test' if
- # an object 'test' existed above it in the
- # heirarchy -- you'd always get the
- # existing object :(
-
- if (no_acquire_flag and len(path) == 0 and
- hasattr(object, 'aq_base')):
- if hasattr(object.aq_base, entry_name):
- subobject=getattr(object, entry_name)
- else: raise AttributeError, entry_name
- else: subobject=getattr(object, entry_name)
- except AttributeError:
- got=1
- try: subobject=object[entry_name]
- except (KeyError, IndexError,
- TypeError, AttributeError):
- if debug_mode:
- return response.debugError(
- "Cannot locate object at: %s" % URL)
- else:
- return response.notFoundError(URL)
-
try:
- try: doc=subobject.__doc__
- except: doc=getattr(object, entry_name+'__doc__')
- if not doc: raise AttributeError, entry_name
- except:
- if debug_mode:
- return response.debugError(
- "Missing doc string at: %s" % URL)
- else: return response.notFoundError("%s" % URL)
-
- r = getattr(subobject, '__roles__', UNSPECIFIED_ROLES)
- if r is not UNSPECIFIED_ROLES:
- roles = r
- elif not got:
- # We got the subobject as an attribute, not an item,
- # so we should check "next to it" for __roles__.
- roles = getattr(object, entry_name+'__roles__', roles)
-
- # Promote subobject to object
- object=subobject
+ object, r = self._traverseName(object, entry_name)
+ if r is not UNSPECIFIED_ROLES:
+ roles = r
+ except StopTraversal, v:
+ return v
parents.append(object)
steps.append(entry_name)
@@ -416,75 +507,8 @@
request['PUBLISHED'] = parents.pop(0)
# Do authorization checks
- user=groups=None
- i=0
+ self._checkAuthorization(object, parents, roles, validated_hook)
- if 1: # Always perform authentication.
-
- last_parent_index=len(parents)
- if hasattr(object, '__allow_groups__'):
- groups=object.__allow_groups__
- inext=0
- else:
- inext=None
- for i in range(last_parent_index):
- if hasattr(parents[i],'__allow_groups__'):
- groups=parents[i].__allow_groups__
- inext=i+1
- break
-
- if inext is not None:
- i=inext
-
- if hasattr(groups, 'validate'): v=groups.validate
- else: v=old_validation
-
- auth=request._auth
-
- if v is old_validation and roles is UNSPECIFIED_ROLES:
- # No roles, so if we have a named group, get roles from
- # group keys
- if hasattr(groups,'keys'): roles=groups.keys()
- else:
- try: groups=groups()
- except: pass
- try: roles=groups.keys()
- except: pass
-
- if groups is None:
- # Public group, hack structures to get it to validate
- roles=None
- auth=''
-
- if v is old_validation:
- user=old_validation(groups, request, auth, roles)
- elif roles is UNSPECIFIED_ROLES: user=v(request, auth)
- else: user=v(request, auth, roles)
-
- while user is None and i < last_parent_index:
- parent=parents[i]
- i=i+1
- if hasattr(parent, '__allow_groups__'):
- groups=parent.__allow_groups__
- else: continue
- if hasattr(groups,'validate'): v=groups.validate
- else: v=old_validation
- if v is old_validation:
- user=old_validation(groups, request, auth, roles)
- elif roles is UNSPECIFIED_ROLES: user=v(request, auth)
- else: user=v(request, auth, roles)
-
- if user is None and roles != UNSPECIFIED_ROLES:
- response.unauthorized()
-
- if user is not None:
- if validated_hook is not None: validated_hook(self, user)
- request['AUTHENTICATED_USER']=user
- request['AUTHENTICATION_PATH']=join(steps[:-i],'/')
-
- # Remove http request method from the URL.
- request['URL']=URL
-
return object
retry_count=0