92 lines
3.1 KiB
Python
92 lines
3.1 KiB
Python
from webob import exc
|
|
|
|
from secure import handle_security, cross_boundary
|
|
from util import iscontroller
|
|
|
|
__all__ = ['lookup_controller', 'find_object']
|
|
|
|
|
|
class NonCanonicalPath(Exception):
|
|
def __init__(self, controller, remainder):
|
|
self.controller = controller
|
|
self.remainder = remainder
|
|
|
|
|
|
def lookup_controller(obj, url_path):
|
|
remainder = url_path
|
|
notfound_handlers = []
|
|
|
|
while True:
|
|
try:
|
|
obj, remainder = find_object(obj, remainder, notfound_handlers)
|
|
handle_security(obj)
|
|
return obj, remainder
|
|
except exc.HTTPNotFound:
|
|
while notfound_handlers:
|
|
name, obj, remainder = notfound_handlers.pop()
|
|
if name == '_default':
|
|
# Notfound handler is, in fact, a controller, so stop
|
|
# traversal
|
|
return obj, remainder
|
|
else:
|
|
# Notfound handler is an internal redirect, so continue
|
|
# traversal
|
|
try:
|
|
result = obj(*remainder)
|
|
if result:
|
|
prev_obj = obj
|
|
obj, remainder = result
|
|
# crossing controller boundary
|
|
cross_boundary(prev_obj, obj)
|
|
break
|
|
except TypeError, te:
|
|
import warnings
|
|
msg = 'Got exception calling lookup(): %s (%s)'
|
|
warnings.warn(
|
|
msg % (te, te.args),
|
|
RuntimeWarning
|
|
)
|
|
else:
|
|
raise exc.HTTPNotFound
|
|
|
|
|
|
def find_object(obj, remainder, notfound_handlers):
|
|
prev_obj = None
|
|
while True:
|
|
if obj is None:
|
|
raise exc.HTTPNotFound
|
|
if iscontroller(obj):
|
|
return obj, remainder
|
|
|
|
# are we traversing to another controller
|
|
cross_boundary(prev_obj, obj)
|
|
|
|
if remainder and remainder[0] == '':
|
|
index = getattr(obj, 'index', None)
|
|
if iscontroller(index):
|
|
return index, remainder[1:]
|
|
elif not remainder:
|
|
# the URL has hit an index method without a trailing slash
|
|
index = getattr(obj, 'index', None)
|
|
if iscontroller(index):
|
|
raise NonCanonicalPath(index, remainder[1:])
|
|
default = getattr(obj, '_default', None)
|
|
if iscontroller(default):
|
|
notfound_handlers.append(('_default', default, remainder))
|
|
|
|
lookup = getattr(obj, '_lookup', None)
|
|
if iscontroller(lookup):
|
|
notfound_handlers.append(('_lookup', lookup, remainder))
|
|
|
|
route = getattr(obj, '_route', None)
|
|
if iscontroller(route):
|
|
next, next_remainder = route(remainder)
|
|
cross_boundary(route, next)
|
|
return next, next_remainder
|
|
|
|
if not remainder:
|
|
raise exc.HTTPNotFound
|
|
next, remainder = remainder[0], remainder[1:]
|
|
prev_obj = obj
|
|
obj = getattr(obj, next, None)
|