import os import urllib import time import re from cPickle import load, dump from webob import Request, Response, html_escape from webob import exc class Commenter(object): def __init__(self, app, storage_dir): self.app = app self.storage_dir = storage_dir if not os.path.exists(storage_dir): os.makedirs(storage_dir) def __call__(self, environ, start_response): req = Request(environ) if req.path_info_peek() == ".comments": return self.process_comment(req)(environ, start_response) # This is the base path of *this* middleware: base_url = req.application_url resp = req.get_response(self.app) if resp.content_type != "text/html" or resp.status_code != 200: # Not an HTML response, we don't want to # do anything to it return resp(environ, start_response) # Make sure the content isn't gzipped: resp.decode_content() comments = self.get_data(req.url) body = resp.body body = self.add_to_end(body, self.format_comments(comments)) body = self.add_to_end(body, self.submit_form(base_url, req)) resp.body = body return resp(environ, start_response) def get_data(self, url): # Double-quoting makes the filename safe filename = self.url_filename(url) if not os.path.exists(filename): return [] else: f = open(filename, "rb") data = load(f) f.close() return data def save_data(self, url, data): filename = self.url_filename(url) f = open(filename, "wb") dump(data, f) f.close() def url_filename(self, url): return os.path.join(self.storage_dir, urllib.quote(url, "")) _end_body_re = re.compile(r"", re.I | re.S) def add_to_end(self, html, extra_html): """ Adds extra_html to the end of the html page (before ) """ match = self._end_body_re.search(html) if not match: return html + extra_html else: return html[: match.start()] + extra_html + html[match.start() :] def format_comments(self, comments): if not comments: return "" text = [] text.append("
") text.append( '

Comments (%s):

' % len(comments) ) for comment in comments: text.append( '

%s at %s:

' % ( html_escape(comment["homepage"]), html_escape(comment["name"]), time.strftime("%c", comment["time"]), ) ) # Susceptible to XSS attacks!: text.append(comment["comments"]) return "".join(text) def submit_form(self, base_path, req): return """

Leave a comment:

Name:
URL:
Comments:

""" % ( base_path, html_escape(req.url), ) def process_comment(self, req): try: url = req.params["url"] name = req.params["name"] homepage = req.params["homepage"] comments = req.params["comments"] except KeyError, e: resp = exc.HTTPBadRequest("Missing parameter: %s" % e) return resp data = self.get_data(url) data.append( dict(name=name, homepage=homepage, comments=comments, time=time.gmtime()) ) self.save_data(url, data) resp = exc.HTTPSeeOther(location=url + "#comment-area") return resp if __name__ == "__main__": import optparse parser = optparse.OptionParser(usage="%prog --port=PORT BASE_DIRECTORY") parser.add_option( "-p", "--port", default="8080", dest="port", type="int", help="Port to serve on (default 8080)", ) parser.add_option( "--comment-data", default="./comments", dest="comment_data", help="Place to put comment data into (default ./comments/)", ) options, args = parser.parse_args() if not args: parser.error("You must give a BASE_DIRECTORY") base_dir = args[0] from paste.urlparser import StaticURLParser app = StaticURLParser(base_dir) app = Commenter(app, options.comment_data) from wsgiref.simple_server import make_server httpd = make_server("localhost", options.port, app) print("Serving on http://localhost:%s" % options.port) try: httpd.serve_forever() except KeyboardInterrupt: print("^C")