'Return the appropriate page handler, plus any virtual path.
This will return two objects. The first will be a callable,
which can be used to generate page output. Any parameters from
the query string or request body will be sent to that callable
as keyword arguments.
The callable is found by traversing the application\'s tree,
starting from cherrypy.request.app.root, and matching path
components to successive objects in the tree. For example, the
URL "/path/to/handler" might return root.path.to.handler.
The second object returned will be a list of names which are
\'virtual path\' components: parts of the URL which are dynamic,
and were not used when looking up the handler.
These virtual path components are passed to the handler as
positional arguments.'

def find_handler(self, path):

    request = cherrypy.serving.request
    app = request.app
    root = app.root
    dispatch_name = self.dispatch_method_name
    fullpath = ([x for x in path.strip('/').split('/') if x] + ['index'])
    fullpath_len = len(fullpath)
    segleft = fullpath_len
    nodeconf = {}
    if hasattr(root, '_cp_config'):
        nodeconf.update(root._cp_config)
    if ('/' in app.config):
        nodeconf.update(app.config['/'])
    object_trail = [['root', root, nodeconf, segleft]]
    node = root
    iternames = fullpath[:]
    while iternames:
        name = iternames[0]
        objname = name.translate(self.translate)
        nodeconf = {}
        subnode = getattr(node, objname, None)
        pre_len = len(iternames)
        if (subnode is None):
            dispatch = getattr(node, dispatch_name, None)
            if (dispatch and hasattr(dispatch, '__call__') and (not getattr(dispatch, 'exposed', False)) and (pre_len > 1)):
                index_name = iternames.pop()
                subnode = dispatch(vpath=iternames)
                iternames.append(index_name)
            else:
                iternames.pop(0)
        else:
            iternames.pop(0)
        segleft = len(iternames)
        if (segleft > pre_len):
            raise cherrypy.CherryPyException((('A    vpath    segment    was    added.        Custom    dispatchers    may    only    ' + 'remove    elements.        While    trying    to    process    ') + '{0}    in    {1}'.format(name, fullpath)))
        elif (segleft == pre_len):
            iternames.pop(0)
            segleft -= 1
        node = subnode
        if (node is not None):
            if hasattr(node, '_cp_config'):
                nodeconf.update(node._cp_config)
        existing_len = (fullpath_len - pre_len)
        if (existing_len != 0):
            curpath = ('/' + '/'.join(fullpath[0:existing_len]))
        else:
            curpath = ''
        new_segs = fullpath[(fullpath_len - pre_len):(fullpath_len - segleft)]
        for seg in new_segs:
            curpath += ('/' + seg)
            if (curpath in app.config):
                nodeconf.update(app.config[curpath])
        object_trail.append([name, node, nodeconf, segleft])
    def set_conf():
        'Collapse    all    object_trail    config    into    cherrypy.request.config.'
        base = cherrypy.config.copy()
        for (name, obj, conf, segleft) in object_trail:
            base.update(conf)
            if ('tools.staticdir.dir' in conf):
                base['tools.staticdir.section'] = ('/' + '/'.join(fullpath[0:(fullpath_len - segleft)]))
        return base
    num_candidates = (len(object_trail) - 1)
    for i in range(num_candidates, (-1), (-1)):
        (name, candidate, nodeconf, segleft) = object_trail[i]
        if (candidate is None):
            continue
        if hasattr(candidate, 'default'):
            defhandler = candidate.default
            if getattr(defhandler, 'exposed', False):
                conf = getattr(defhandler, '_cp_config', {})
                object_trail.insert((i + 1), ['default', defhandler, conf, segleft])
                request.config = set_conf()
                request.is_index = path.endswith('/')
                return (defhandler, fullpath[(fullpath_len - segleft):(-1)])
        if getattr(candidate, 'exposed', False):
            request.config = set_conf()
            if (i == num_candidates):
                request.is_index = True
            else:
                request.is_index = False
            return (candidate, fullpath[(fullpath_len - segleft):(-1)])
    request.config = set_conf()
    return (None, [])
