Search code examples
pythonregexstaticdispatchercherrypy

Cherrypy Custom Dispatcher with Static Files


I have written my own custom dispatcher that uses regular expressions to map routes, however, I can no longer host static files in /static. Here is the dispatcher and the config:

class Dispatcher(object):
def __init__(self):
    self.urls = {}

def __call__(self, path_info):
    print('Dispatcher called: ' + path_info)

    func = self.find_handler(path_info)
    cherrypy.serving.request.handler = func

def find_handler(self, path_info):
    request = cherrypy.serving.request
    request.config = cherrypy.config.copy()

    for url in self.urls:
        args = re.findall(url, path_info)

        if len(args) > 0:
            # in the case that the route is just a URL, we don't want
            # an extra argument in the method function
            try:
                args.remove(path_info)
            except ValueError:
                pass

            controller = self.urls[url]
            method = request.method.lower()

            return cherrypy._cpdispatch.LateParamPageHandler(getattr(controller, method), *args)

    return cherrypy.NotFound()

def connect(self, url, controller):
    if not url.endswith("$"):
        url += "$"

    self.urls[url] = controller

And the config:

config = {
        'global': {
            'server.socket_host': '0.0.0.0',
            'server.socket_port': port,
        },

        '/static': {
            'tools.staticdir.on': True,
            'tools.staticdir.dir': os.path.join(os.getcwd(), 'static'),
        },

        '/': {
            'request.dispatch': self.dispatcher,
        }
    }

If I use the standard dispatcher, static files work as they should, however if I use my own, they no longer work. Having done debugging in the dispatcher, static files go through the dispatcher, even though I have specific that only in '/' does the dispatcher get used.


Solution

  • I'm not familiar with cherrypy, but it seems obvious: everything in /static is also in /, so it is anyone's guess which config entry it will use. I would hope that "more specific has priority", but according to your description, this is not the case. Looking at the documentation also doesn't help, there's no mention of ambiguous path handling.

    You would think that changing the order might help, but since this is a dictionary, the order isn't preserved.

    It seems that cherrypy is unable to do this. If it has a default dispatcher which is overloaded with others, that could solve the problem. Another option is that your custom dispatcher can call the static one if it detects the path.

    Finally, the documentation talks about "mounting an application to a path". If you do this, you may want to change the order. If you don't do this, it might be done automatically, and doing it manually may solve your problem.

    Not all of this may make sense, since as I wrote I'm not familiar with cherrypy, but I hope it helps you a bit anyway.