from urllib import unquote from paste import httpexceptions from paste.request import parse_formvars from rhubarbtart import response from sigerror import call_with_sig_error def resolve(root_obj, environ, start_response): if root_obj is None: raise TypeError("resolve() cannot be called with a root_obj of None") node = root_obj script_name = environ.get('SCRIPT_NAME', '').split('/')[1:] path_info = environ.get('PATH_INFO', '').split('/')[1:] using_index = False while 1: if getattr(node, 'respond', None): node = getattr(node, 'respond') break elif not path_info or path_info == ['']: # Node is not callable, but maybe its index is... if not using_index and getattr(node, 'index', None): if path_info != ['']: uri = (environ.get('SCRIPT_NAME', '') + environ.get('PATH_INFO', '') + '/') if environ.get('QUERY_STRING'): uri += '?' + environ['QUERY_STRING'] raise httpexceptions.HTTPFound.relative_redirect(uri, environ) node = node.index # index doesn't need the '' argument, since it is assumed: script_name.append(path_info.pop()) using_index = True elif not using_index and getattr(node, 'default', None): node = node.default else: exc = httpexceptions.HTTPForbidden('object not callable: %r' % node) return exc.wsgi_application(environ, start_response) else: name = path_info.pop(0) script_name.append(name) if not name: continue objname = name.replace('.', '_') old_node = node node = getattr(old_node, objname, None) if node is None: node = getattr(old_node, 'default', None) if node is not None: path_info.insert(0, script_name.pop()) if node is None: raise httpexceptions.HTTPNotFound('%s attribute of %r not found' % (objname, old_node)) if is_terminal_node(node): break wsgi_application = getattr(node, "wsgi_application", None) if wsgi_application: if isinstance(wsgi_application, int): wsgihandler = node else: wsgihandler = wsgi_application environ['SCRIPT_NAME'] = '/'.join([''] + script_name) environ['PATH_INFO'] = '/'.join([''] + path_info) return wsgihandler(environ, start_response) if not is_permitted(node): raise httpexceptions.HTTPNotFound('cannot view %r' % node) formvars = parse_formvars(environ) or {} path_info = [unquote(path) for path in path_info if path != ''] if hasattr(formvars, 'mixed'): formvars = formvars.mixed() response.body = call_with_sig_error(node, *path_info, **formvars) headers = response.headeritems() start_response(response.status, headers) return response.body_iter() def is_terminal_node(node): return getattr(node, 'wsgi_application', None) or callable(node) def is_permitted(node): return (getattr(node, 'wsgi_application', None) or getattr(node, 'exposed', False) or getattr(getattr(node, '__call__', None), 'exposed', False))