[albatross-users] New version of the standalone http server

Matt Goodall matt at pollenation.net
Thu Jul 3 11:40:45 EST 2003


Hi all,

Attached is an updated version of the standalone server with the
following changes:

      * Fixed to support forms containing input fields with a "list"
        attribute. It only ever returned the first value in the get or
        post data before.
      * Added the current working directory to the path so that the
        httpd.py script can live anywhere.
      * changed the filename to al-httpd. An even better name might be
        al-simple-server.

Cheers, Matt

-- 
Matt Goodall, Pollenation Internet Ltd
w: http://www.pollenation.net
e: matt at pollenation.net
-------------- next part --------------
#!/usr/bin/env python

import BaseHTTPServer
import cgi
import os
import sys
from cStringIO import StringIO
from urlparse import urlsplit

class Request:

    """BaseHTTPServer request adaptor"""

    def __init__(self, req):

        self._req = req
        self._status = 200;
        self._fields = []
        self.headers_out = {}
        self.data = StringIO()

        if self._req.command == 'GET':
            self._fields = self.parse_get_fields()
        elif self._req.command == 'POST':
            self._fields = self.parse_post_fields()
        else:
            pass

    def parse_get_fields(self):
        """Extract fields from query string"""
        qs = urlsplit(self._req.requestline.split()[1])[3]
        if not qs:
            return {}
        return cgi.parse_qs(qs)

    def parse_post_fields(self):
        """Extract fields from posted data"""
        fields = {}
        content_type = self._req.headers.get('content-type')
        if content_type:
            key, pdict = cgi.parse_header(content_type)
            if key == 'application/x-www-form-urlencoded':
                cl = int(self._req.headers['content-length'])
                fields = cgi.parse_qs(self._req.rfile.read(cl), 1)
            elif key == 'multipart/form-data':
                fields = cgi.parse_multipart(self.content, pdict)
            else:
                pass
        return fields

    def get_header(self, name):
        return self._req.headers.get(name)
        
    def write_header(self, name, value):
        self.headers_out[name] = value

    def end_headers(self):
        pass

    def has_field(self, name):
        return self._fields.has_key(name)

    def field_value(self, name):
        
        # Get the field
        field = self._fields[name]
        
        # Field is always a list. If there is only one item in it then return
        # the item and let Albatross take care of input fields with the list
        # attribute
        if len(field) == 1:
            return field[0]
        else:
            return field

    def field_names(self):
        return self._fields.keys()

    def get_uri(self):
        serverName = self._req.server.server_name
        serverPort = self._req.server.server_port
        path = self._req.path
        uri = 'http://%s:%d%s' % (serverName, serverPort, path)
        return uri

    def get_servername(self):
        servername = self._req.server.server_name
        port = self._req.server.server_port
        return '%s:%d' % (servername, port)

    def write_content(self, data):
        self.data.write(data)

    def redirect(self, loc):
        self.write_header('Location', loc)
        self.write_header('Status', '301 Moved Permanently')
        self._status = 301
        self.end_headers()

    def set_status(self, status):
        self._status = status

    def status(self):
        return self._status


class RequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):

    """
    Handle HTTP request, routing them through to the Albatross
    application
    """

    def do_GET(self):
        self.process_request()

    def do_POST(self):
        self.process_request()

    def process_request(self):
        self.log_request()
        req = Request(self)
        self.server.app.run(req)
        self.send_response(req.status())
        for name, value in req.headers_out.items():
            self.send_header(name, value)
        self.end_headers()
        if req.status() == 200:
            self.wfile.write(req.data.getvalue())


class HTTPServer(BaseHTTPServer.HTTPServer):

    """Simple, standalone HTTP server for Albatross applications."""

    def __init__(self, app, port):
        BaseHTTPServer.HTTPServer.__init__(self, ('', port), RequestHandler)
        self.app = app


if __name__ == '__main__':

    # Append the current working directory to the path
    sys.path.append(os.getcwd())

    # Parse the command line
    appClass = sys.argv[1]
    port = int(sys.argv[2])

    # Load the application's module and create an application instance
    module = __import__(appClass[:appClass.rindex('.')])
    app = getattr(module,appClass[appClass.rindex('.')+1:])()

    # Create the HTTP server
    httpd = HTTPServer(app, port)

    # Handle requests
    httpd.serve_forever()


More information about the Albatross-users mailing list