summaryrefslogtreecommitdiff
path: root/common/httpserver.py
diff options
context:
space:
mode:
Diffstat (limited to 'common/httpserver.py')
-rw-r--r--common/httpserver.py192
1 files changed, 192 insertions, 0 deletions
diff --git a/common/httpserver.py b/common/httpserver.py
new file mode 100644
index 0000000..a39f854
--- /dev/null
+++ b/common/httpserver.py
@@ -0,0 +1,192 @@
+from __future__ import generators
+from __future__ import nested_scopes
+import BaseHTTPServer
+from SimpleHTTPServer import SimpleHTTPRequestHandler
+import urlparse, cgi, htmlentitydefs
+import sys, os, time
+from cStringIO import StringIO
+
+
+class Translator:
+ """For use with format strings.
+
+ 'formatstring % translator' will evaluate all %(xxx)s expressions
+ found in the format string in the given globals/locals.
+
+ Multiline expressions are assumed to be one or several complete
+ statements; they are executed and whatever they print is inserted back
+ into the format string."""
+
+ def __init__(self, globals, locals):
+ self.globals = globals
+ self.locals = locals
+
+ def __getitem__(self, expr):
+ if '\n' in expr:
+ if not expr.endswith('\n'):
+ expr += '\n'
+ prevstdout = sys.stdout
+ try:
+ sys.stdout = f = StringIO()
+ exec expr in self.globals, self.locals
+ finally:
+ sys.stdout = prevstdout
+ return f.getvalue()
+ else:
+ return eval(expr, self.globals, self.locals)
+
+class TranslatorIO:
+ "Lazy version of Translator."
+
+ def __init__(self, fmt, d):
+ self.gen = self.generate(fmt, d)
+
+ def read(self, ignored=None):
+ for text in self.gen:
+ if text:
+ return text
+ return ''
+
+ def close(self):
+ self.gen = ()
+
+ def generate(self, fmt, d):
+ t = Translator(d, d)
+ for data in fmt.split('\x0c'):
+ yield data % t
+
+
+# HTML quoting
+
+text_to_html = {}
+for key, value in htmlentitydefs.entitydefs.items():
+ text_to_html[value] = '&' + key + ';'
+
+def htmlquote(s):
+ return ''.join([text_to_html.get(c, c) for c in s])
+
+
+# HTTP Request Handler
+
+pathloaders = {}
+
+def canonicalpath(url):
+ if url.startswith('/'):
+ url = url[1:]
+ return url.lower()
+
+def register(url, loader):
+ pathloaders[canonicalpath(url)] = loader
+
+def is_registered(url):
+ return canonicalpath(url) in pathloaders
+
+def load(filename, mimetype=None, locals=None):
+ if mimetype and mimetype.startswith('text/'):
+ mode = 'r'
+ else:
+ mode = 'rb'
+ f = open(filename, mode)
+ if locals is not None:
+ data = f.read()
+ f.close()
+ #data = data.replace('%"', '%%"')
+ d = globals().copy()
+ d.update(locals)
+ f = TranslatorIO(data, d)
+ return f, mimetype
+
+def fileloader(filename, mimetype=None):
+ def loader(**options):
+ return load(filename, mimetype)
+ return loader
+
+class HTTPRequestError(Exception):
+ pass
+
+class MiniHandler(SimpleHTTPRequestHandler):
+
+ def send_head(self, query=''):
+ addr, host, path, query1, fragment = urlparse.urlsplit(self.path)
+ path = canonicalpath(path)
+ if path not in pathloaders:
+ if path + '/' in pathloaders:
+ return self.redirect(path + '/')
+ self.send_error(404)
+ return None
+ kwds = {}
+ for q in [query1, query]:
+ if q:
+ kwds.update(cgi.parse_qs(q))
+ loader = pathloaders[path]
+ try:
+ hdr = self.headers
+ hdr['remote host'] = self.client_address[0]
+ f, ctype = loader(headers=hdr, **kwds)
+ except IOError, e:
+ self.send_error(404, "I/O error: " + str(e))
+ return None
+ except HTTPRequestError, e:
+ self.send_error(500, str(e))
+ return None
+ except:
+ f = StringIO()
+ import traceback
+ traceback.print_exc(file=f)
+ data = htmlquote(f.getvalue())
+ data = data.replace('\n', '<br>\n')
+ self.send_error(500)
+ return StringIO('<hr><p>'+data+'</p>')
+ if ctype is None:
+ ctype = self.guess_type(self.translate_path(self.path))
+ elif f is None:
+ return self.redirect(ctype)
+
+ self.send_response(200)
+ self.send_header("Content-type", ctype)
+ self.end_headers()
+ return f
+
+ def redirect(self, url):
+ self.send_response(302)
+ self.send_header("Content-type", 'text/html')
+ self.send_header("Location", url)
+ self.end_headers()
+ return StringIO('''<html><head></head><body>
+Please <a href="%s">click here</a> to continue.
+</body></html>
+''' % url)
+
+ def do_POST(self):
+ try:
+ nbytes = int(self.headers.getheader('content-length'))
+ except:
+ nbytes = 0
+ query = self.rfile.read(nbytes).strip()
+ f = self.send_head(query)
+ if f:
+ self.copyfile(f, self.wfile)
+ f.close()
+
+ def parse_request(self):
+ if self.raw_requestline == '':
+ return False
+ else:
+ return SimpleHTTPRequestHandler.parse_request(self)
+
+ def address_string(self):
+ """Override to avoid DNS lookups"""
+ return "%s:%d" % self.client_address
+
+ def finish(self):
+ SimpleHTTPRequestHandler.finish(self)
+ self.connection.close()
+ while actions_when_finished:
+ actions_when_finished.pop(0)()
+
+actions_when_finished = []
+
+def my_host():
+ import gamesrv
+ port = gamesrv.socketports[gamesrv.openhttpsocket()]
+ return '127.0.0.1:%d' % port