#!/usr/bin/env python

import os

import datetime

import BaseHTTPServer 
import SocketServer

# hard-coded configurtion
WWW = '/tmp/www/'
PORT = 8080
MIME = {
            '.html' : 'text/html',
            '.css'  : 'text/css',
            '.png'  : 'image/png',
            '.jpg'  : 'image/jpeg',
            '.gif'  : 'image/gif'
        }

# This is the 'select()' module---except we aren't showing it here
# or actually implementing it properly
class LisoPrototype(BaseHTTPServer.HTTPServer):
    pass

# This is the HTTP/1.1 parsing module---except we don't show parsing
# only forming responses with the proper headers etc.
class LisoHandlerPrototype(BaseHTTPServer.BaseHTTPRequestHandler):
    def return404(self):
        self.send_error(404, 'Not Found')

    def return411(self):
        self.send_error(411, 'Length Required')

    def return500(self):
        self.send_error(500, 'Not Found')

    def return505(self):
        self.send_error(505, 'HTTP Version not supported')

    def check_HTTP_version(self):
        version = self.request_version.split('/')
        version = version[1].split('.')
        if version[0] != '1' or version[1] != '1':
            self.return505()
            return None

    def do_GET(self):
        self.check_HTTP_version()
        # understand requested object/URI
        URI = self.path
        full_path = os.path.normpath(WWW + URI)
        
        if os.path.isdir(full_path):
            full_path = os.path.join(full_path, 'index.html')
        
        if not os.path.exists(full_path):
            self.return404()
            return

        message_body = ''
        basename,extension = os.path.splitext(full_path)

        # read in full file
        try:
            datestring = os.path.getmtime(full_path)
            with open(full_path, 'r') as f:
                message_body = f.read()
        except IOError:
            self.return_500()
            return

        # format datestring
        datestring = datetime.datetime.utcfromtimestamp(datestring)
        datestring = datestring.strftime('%a, %d %b %Y %H:%M:%S %Z')

        # get proper mimetype
        try:
            mimetype = MIME[extension.lower()]
        except KeyError:
            mimetype = 'application/octet-stream'

        # send response; Server and Date headers auto-generated
        self.send_response(200, 'OK')
        self.send_header('Connection', 'close')
        self.send_header('Content-Type', mimetype)
        self.send_header('Content-Length', len(message_body))
        self.send_header('Last-Modified', datestring)
        self.end_headers()
        self.wfile.write(message_body)
        self.close_connection = 1 # hack for multi-connection browsers
        # the server above us is dumb; that's why this hack is needed

    def do_HEAD(self):
        self.check_HTTP_version()
        # understand requested object/URI
        URI = self.path
        full_path = os.path.normpath(WWW + URI)
        
        if os.path.isdir(full_path):
            full_path = os.path.join(full_path, 'index.html')
        
        if not os.path.exists(full_path):
            self.return404()

        message_body = ''
        basename,extension = os.path.splitext(full_path)
        
        # get stats
        datestring = os.path.getmtime(full_path)
        fsize = os.path.getsize(full_path)

        # format datestring
        datestring = datetime.datetime.utcfromtimestamp(datestring)
        datestring = datestring.strftime('%a, %d %b %Y %H:%M:%S %Z')

        # get proper mimetype
        try:
            mimetype = MIME[extension.lower()]
        except KeyError:
            mimetype = 'application/octet-stream'

        # send response; Server and Date headers auto-generated
        self.send_response(200, 'OK')
        self.send_header('Connection', 'close')
        self.send_header('Content-Type', mimetype)
        self.send_header('Content-Length', fsize)
        self.send_header('Last-Modified', datestring)
        self.end_headers()
        self.close_connection = 1

    def do_POST(self):
        self.check_HTTP_version()
        if 'Content-length' not in self.headers:
                return411()
                return
        self.send_response(200, 'OK')
        self.send_header('Connection', 'close')
        self.end_headers()
        self.close_connection = 1

def run():
    handler = LisoHandlerPrototype

    # set version strings for auto-generated Server header amd response
    handler.server_version = 'Liso/1.0'
    handler.sys_version = ''
    handler.protocol_version = 'HTTP/1.1'

    # server startup
    server_address = ('0.0.0.0', PORT)
    httpd = LisoPrototype(server_address, handler)
    httpd.serve_forever()

if __name__ == '__main__':
    run()
