Webpy is a tiny web framework. I use it a lot for my web-services applications.

In general, I let my web server (lighttpd) to handle virtual hosting. But as you may know, I am working on a CDN solution on top of Google App Engine, named CirruxCache. In that case, while I have absolutely no control on the server configuration, I need to handle virtual hosting from the code.

Webpy maps urls by iterating through a tuple. So my solution is quite simple: wrapping the tuple to override the __iter__ function according to an environment variable (HTTP_HOST).

Let's take this basic webpy example, without vhosting:

import web
 
urls = ('/(.*)', 'hello')
 
class hello(object):
    def GET(self, name):
        if not name:
            name = 'World'
        return 'Hello, %s' % name
 
if __name__ == "__main__":
   app = web.application(urls, globals()) 
   app.run()

Let's add the VhostMapper class:

import web
 
urls = {
      'default' : ('/(.*)', 'hello'),
      'my-vhost.domain.tld' : ('/(.*)', 'helloVhost')
      }
 
class hello(object):
    def GET(self, name):
        if not name:
            name = 'World'
        return 'Hello, %s !' % name
 
class helloVhost(object):
    def GET(self, name):
        return 'Hello %s' % web.ctx.environ['HTTP_HOST']
 
class VhostMapper(object):
    def __iter__(self):
        url = urls['default']
        if 'HTTP_HOST' in web.ctx.environ:
            vhost = web.ctx.environ['HTTP_HOST']
            if vhost in urls:
                url = urls[vhost]
        return iter(url)
 
if __name__ == "__main__":
   app = web.application(VhostMapper(), globals()) 
   app.run()

Finally, you can use curl or wget to test your vhosts:

$> curl -H "Host: my-vhost.domain.tld" http://localhost:8080/

It is not so early to announce that the next version of CirruxCache will handle virtual hosting :)

I am sure this simple hack can be easily reproduced to use virtual hosting in some other Rest frameworks.