blob: 97486b1e86df7fe764508eadd22c3417308cba98 [file] [edit]
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"</body.*?>", re.I | re.S)
def add_to_end(self, html, extra_html):
"""
Adds extra_html to the end of the html page (before </body>)
"""
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("<hr>")
text.append(
'<h2><a name="comment-area"></a>Comments (%s):</h2>' % len(comments)
)
for comment in comments:
text.append(
'<h3><a href="%s">%s</a> at %s:</h3>'
% (
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 """<h2>Leave a comment:</h2>
<form action="%s/.comments" method="POST">
<input type="hidden" name="url" value="%s">
<table width="100%%">
<tr><td>Name:</td>
<td><input type="text" name="name" style="width: 100%%"></td></tr>
<tr><td>URL:</td>
<td><input type="text" name="homepage" style="width: 100%%"></td></tr>
</table>
Comments:<br>
<textarea name="comments" rows=10 style="width: 100%%"></textarea><br>
<input type="submit" value="Submit comment">
</form>
""" % (
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")