From 0b6f220fc8ac58b6404e2d45eed52629d549860f Mon Sep 17 00:00:00 2001 From: Fredrik Tolf Date: Sat, 14 Jul 2012 21:59:39 +0200 Subject: [PATCH] python: Rewrote SSI handler as a reusable module, and in Python3. --- python/serve-ssi | 172 ---------------------------------------------------- python/setup.py | 2 +- python3/ashd/ssi.py | 146 ++++++++++++++++++++++++++++++++++++++++++++ python3/serve-ssi | 62 +++++++++++++++++++ python3/setup.py | 2 +- 5 files changed, 210 insertions(+), 174 deletions(-) delete mode 100755 python/serve-ssi create mode 100644 python3/ashd/ssi.py create mode 100755 python3/serve-ssi diff --git a/python/serve-ssi b/python/serve-ssi deleted file mode 100755 index abdb701..0000000 --- a/python/serve-ssi +++ /dev/null @@ -1,172 +0,0 @@ -#!/usr/bin/python - -# This program is quite incomplete. I might complete it with more -# features as I need them. It will probably never be entirely -# compliant with Apache's version due to architectural differences. - -import sys, os, time - -def htmlquote(text): - ret = "" - for c in text: - if c == '&': - ret += "&" - elif c == '<': - ret += "<" - elif c == '>': - ret += ">" - elif c == '"': - ret += """ - else: - ret += c - return ret - -def simpleerror(out, code, title, msg): - html = """ - - - -%s - - -

%s

-

%s

- - -""" % (title, title, htmlquote(msg)) - out.write("HTTP/1.1 %d %s\n" % (code, title)) - out.write("Content-Type: text/html\n") - out.write("Content-Length: %d\n" % len(html)) - out.write("\n") - out.write(html) - -ssivars = {} - -def parsecmd(line, p): - try: - while line[p].isspace(): p += 1 - cmd = "" - while not line[p].isspace(): - cmd += line[p] - p += 1 - pars = {} - while True: - while line[p].isspace(): p += 1 - if line[p:p + 3] == "-->": - return cmd, pars, p + 3 - key = "" - while line[p].isalnum(): - key += line[p] - p += 1 - if key == "": - return None, {}, p - while line[p].isspace(): p += 1 - if line[p] != '=': - continue - p += 1 - while line[p].isspace(): p += 1 - q = line[p] - if q != '"' and q != "'" and q != '`': - continue - val = "" - p += 1 - while line[p] != q: - val += line[p] - p += 1 - p += 1 - pars[key] = val - except IndexError: - return None, {}, len(line) - -class ssifile(object): - def __init__(self, s, url, path): - self.s = s - self.url = url - self.path = path - - def close(self): - self.s.close(); - - def initvars(self, vars): - now = time.time() - vars["DOCUMENT_NAME"] = os.path.basename(self.path) - vars["DATE_GMT"] = time.asctime(time.gmtime(now)) - vars["DATE_LOCAL"] = time.asctime(time.localtime(now)) - vars["LAST_MODIFIED"] = time.asctime(time.localtime(os.stat(self.path).st_mtime)) - - def includefile(self, path): - path = os.path.join(os.path.dirname(self.path), path) - try: - f = ssifile(open(path), url, path) - except Exception: - sys.stderr.write("serve-ssi: included file not found: %s\n" % path) - return - try: - f.process() - finally: - f.close - - def docmd(self, cmd, pars): - if cmd == "include": - if "file" in pars: - self.includefile(pars["file"]) - elif "virtual" in pars: - # XXX: For now, just include the file as-is. Change - # when necessary. - self.includefile(pars["virtual"]) - elif cmd == "echo": - enc = htmlquote - if "encoding" in pars: - if pars["encoding"] == "entity": - enc = htmlquote - if "var" in pars: - if pars["var"] in ssivars: - sys.stdout.write(enc(ssivars[pars["var"]])) - else: - sys.stderr.write("serve-ssi: unknown SSI command: %s\n" % cmd) - - def process(self): - for line in self.s: - p = 0 - while True: - p2 = line.find("": + return cmd, pars, p + 3 + key = "" + while text[p].isalnum(): + key += text[p] + p += 1 + if key == "": + return None, {}, p + while text[p].isspace(): p += 1 + if text[p] != '=': + continue + p += 1 + while text[p].isspace(): p += 1 + q = text[p] + if q != '"' and q != "'" and q != '`': + continue + val = "" + p += 1 + while text[p] != q: + val += text[p] + p += 1 + p += 1 + pars[key] = val + except IndexError: + return None, {}, len(text) + +class context(object): + def __init__(self, out, root): + self.out = out + self.vars = {} + now = time.time() + self.vars["DOCUMENT_NAME"] = os.path.basename(root.path) + self.vars["DATE_GMT"] = time.asctime(time.gmtime(now)) + self.vars["DATE_LOCAL"] = time.asctime(time.localtime(now)) + self.vars["LAST_MODIFIED"] = time.asctime(time.localtime(root.mtime)) + +class ssifile(object): + def __init__(self, path): + self.path = path + self.mtime = os.stat(self.path).st_mtime + with open(path) as fp: + self.parts = self.parse(fp.read()) + + def text(self, text, ctx): + ctx.out.write(text) + + def echo(self, var, enc, ctx): + if var in ctx.vars: + ctx.out.write(enc(ctx.vars[var])) + + def include(self, path, ctx): + try: + nest = getfile(os.path.join(os.path.dirname(self.path), path)) + except Exception: + log.warning("%s: could not find included file %s" % (self.path, path)) + return + nest.process(ctx) + + def process(self, ctx): + for part in self.parts: + part(ctx) + + def resolvecmd(self, cmd, pars): + if cmd == "include": + if "file" in pars: + return functools.partial(self.include, pars["file"]) + elif "virtual" in pars: + # XXX: For now, just include the file as-is. Change + # when necessary. + return functools.partial(self.include, pars["virtual"]) + else: + log.warning("%s: invalid `include' directive" % self.path) + return None + elif cmd == "echo": + if not "var" in pars: + log.warning("%s: invalid `echo' directive" % self.path) + return None + enc = wsgiutil.htmlquote + if "encoding" in pars: + if pars["encoding"] == "entity": + enc = wsgiutil.htmlquote + return functools.partial(self.echo, pars["var"], enc) + else: + log.warning("%s: unknown SSI command `%s'" % (self.path, cmd)) + return None + + def parse(self, text): + ret = [] + p = 0 + while True: + p2 = text.find("