diff options
Diffstat (limited to 'common/httpserver.py')
-rw-r--r-- | common/httpserver.py | 192 |
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 |