1#!/usr/bin/python
2import cgi
3import mimetypes
4import os
5import posixpath
6import re
7
8from mako import exceptions
9from mako.lookup import TemplateLookup
10
11root = "./"
12port = 8000
13
14lookup = TemplateLookup(
15    directories=[root + "templates", root + "htdocs"],
16    filesystem_checks=True,
17    module_directory="./modules",
18    # even better would be to use 'charset' in start_response
19    output_encoding="ascii",
20    encoding_errors="replace",
21)
22
23
24def serve(environ, start_response):
25    """serves requests using the WSGI callable interface."""
26    fieldstorage = cgi.FieldStorage(
27        fp=environ["wsgi.input"], environ=environ, keep_blank_values=True
28    )
29    d = dict([(k, getfield(fieldstorage[k])) for k in fieldstorage])
30
31    uri = environ.get("PATH_INFO", "/")
32    if not uri:
33        uri = "/index.html"
34    else:
35        uri = re.sub(r"^/$", "/index.html", uri)
36
37    if re.match(r".*\.html$", uri):
38        try:
39            template = lookup.get_template(uri)
40        except exceptions.TopLevelLookupException:
41            start_response("404 Not Found", [])
42            return [str.encode("Cant find template '%s'" % uri)]
43
44        start_response("200 OK", [("Content-type", "text/html")])
45
46        try:
47            return [template.render(**d)]
48        except:
49            return [exceptions.html_error_template().render()]
50    else:
51        u = re.sub(r"^\/+", "", uri)
52        filename = os.path.join(root, u)
53        if os.path.isfile(filename):
54            start_response("200 OK", [("Content-type", guess_type(uri))])
55            return [open(filename, "rb").read()]
56        else:
57            start_response("404 Not Found", [])
58            return [str.encode("File not found: '%s'" % filename)]
59
60
61def getfield(f):
62    """convert values from cgi.Field objects to plain values."""
63    if isinstance(f, list):
64        return [getfield(x) for x in f]
65    else:
66        return f.value
67
68
69extensions_map = mimetypes.types_map.copy()
70
71
72def guess_type(path):
73    """return a mimetype for the given path based on file extension."""
74    base, ext = posixpath.splitext(path)
75    if ext in extensions_map:
76        return extensions_map[ext]
77    ext = ext.lower()
78    if ext in extensions_map:
79        return extensions_map[ext]
80    else:
81        return "text/html"
82
83
84if __name__ == "__main__":
85    import wsgiref.simple_server
86
87    server = wsgiref.simple_server.make_server("", port, serve)
88    print("Server listening on port %d" % port)
89    server.serve_forever()
90