Wednesday, May 30, 2012

How to Pass Some Arguments to BaseHTTPRequestHandler in Python

Let's say we have an argument, which is a function that we want to pass to BaseHTTRequestHandler to handle a request and return an appropriate response based the request. By looking at HTTPServer class definition, it may not be really obvious how to do it.

It's actually pretty simple and straightforward how to do it. First we need to subclass HTTPServer and override the constructor that takes in our own new arguments. From the RequestHandler class, there'll be a property named server that gives us access to the HTTPServer instance. And since we've subclassed HTTPServer class, we can define as many properties as we want that those properties will be accessible in the server property of the HTTPRequestHandler. The example is shown below.

#!/usr/bin/env python

import logging
from BaseHTTPServer import HTTPServer
from BaseHTTPServer import BaseHTTPRequestHandler

class HttpServerHandler(BaseHTTPRequestHandler):
    def do_POST(self):
        content_length = int(self.headers.getheader("Content-Length"))
        request = self.rfile.read(content_length)
        logging.info("Request: %s" % request)
        # BaseHTTPRequestHandler has a property called server and because
        # we create MyHTTPServer, it has a handler property
        response = self.server.handler(request)
        logging.info("Response: %s" % response)
        self.send_response(200)
        self.end_headers()
        self.wfile.write(response)
    
class MyHTTPServer(HTTPServer):
    """this class is necessary to allow passing custom request handler into
       the RequestHandlerClass"""
    def __init__(self, server_address, RequestHandlerClass, handler):
        HTTPServer.__init__(self, server_address, RequestHandlerClass)
        self.handler = handler
            
class HttpServer:
    def __init__(self, name, host, port, handler):
        self.name = name
        self.host = host
        self.port = port
        self.handler = handler
        self.server = None
        
    def start(self):
        logging.info('Starting %s at %s:%d' % (self.name, self.host, self.port))
        # we need use MyHttpServer here
        self.server = MyHTTPServer((self.host, self.port), HttpServerHandler,
                                   self.handler)
        self.server.serve_forever()
    
    def stop(self):
        if self.server:
            logging.info('Stopping %s at %s:%d' % (self.name, self.host,
                                                   self.port))
            self.server.shutdown()

def server_handler(request):
    if request == "foo":
        return "bar"
    elif request == "bar":
        return "foo"
    else:
        return "foobar"

if __name__ == "__main__":
    logging.basicConfig(format='%(asctime)s [%(levelname)s] %(message)s', 
                        level=logging.INFO)
    server = HttpServer("test server", "localhost", 9999, server_handler)
    server.start()

2 comments: