root/py/httpmon.py/

from socket import *
import re, os, mimetypes

def chunkify(string, length):
        data = []
        pos = 0

        curr = ''

        while pos < len(string):
                data.append(string[pos:pos + length])
                pos += length

        return data

class HTTPmon:
        '''HTTP(Dae)mon'''
        
        def __init__(self, host, port, root, commands):
                self.host = host
                self.port = port
                self.docroot = root
                self.commands = commands

                self.sock = socket(AF_INET, SOCK_STREAM)
                self.sock.bind((host, port))

                self.sock.listen(5)

                while 1:
                        (self.client, self.addr) = self.sock.accept()
                        data = self.client.recv(1048576)

                        for cmd, act in self.commands.items():
                                match = re.match(cmd, data)
                                if match is not None:
                                        arglist = []
                                        for group in match.groups():
                                                arglist.append(group)

                                        actd = map(getattr(self, act), arglist)[0]
                                        getattr(self, actd[0])(actd[1:])

                                        self.client.close()

        def getreq(self, (req)):
                data = req
                mime = None

                req = self.docroot + req

                try:
                        data = file(req).read()
                        status = 'ok'
                        mime = mimetypes.guess_type(req)
                except IOError:
                        try:
                                data = self.lsdir(req + '/')
                                mime = None
                                status = 'ok'
                        except:
                                mime = 'text/plain'
                                status = '_404'

                return (status, data, mime)

        def lsdir(self, dir):
                data = 'Directory index of %s\n' % re.sub('[/]{2,}', '/', dir.replace(self.docroot, ''))
                files = []
                longest = 0

                for elm in os.listdir(dir):
                        files.append((elm, os.path.getsize(dir + elm)))
                        if len(elm) > longest: longest = len(elm)

                for elm in files:
                        name = elm[0].ljust(longest + 10)
                        data += '\n%s%s bytes' % (name, elm[1])

                return data

        def ok(self, (content, mime)):
                chunks = '\n'.join(['%s\n%s' % (str(hex(len(chunk))), chunk) for chunk in chunkify(content, 100)])
                self.client.send('''HTTP/1.1 200 OK\nContent-Type: %s\nTransfer-Encoding: chunked\n\n%s\n''' % ((mime and mime[0] or 'text/plain'), chunks))

        def _404(self, (elm, mime)):
                self.client.send('''HTTP/1.1 404 Not Found\nContent-Type: text/plain\n\nFile %s not found\n\nHTTPmon server on %s:%d''' % (elm, self.host, self.port))

if __name__ == '__main__':
        commands = {'GET (.+) HTTP/.+\n': 'getreq'}
        HTTPmon('localhost', 88, '~/public_html', commands)