--- /dev/null
+#!/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 = """<?xml version="1.0" encoding="US-ASCII"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en-US" xml:lang="en-US">
+<head>
+<title>%s</title>
+</head>
+<body>
+<h1>%s</h1>
+<p>%s</p>
+</body>
+</html>
+""" % (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("<!--#", p)
+ if p2 < 0:
+ sys.stdout.write(line[p:])
+ break
+ sys.stdout.write(line[p:p2])
+ cmd, pars, p = parsecmd(line, p2 + 5)
+ if cmd is not None:
+ self.docmd(cmd, pars)
+
+if len(sys.argv) < 4:
+ sys.stderr.write("usage: serve-ssi METHOD URL REST\n")
+ sys.exit(1)
+method, url, rest = sys.argv[1:]
+path = os.getenv("REQ_X_ASH_FILE")
+if path is None:
+ sys.stderr.write("serve-ssi: must be called with the X-Ash-File header\n")
+ sys.exit(1)
+if rest != "":
+ simpleerror(sys.stdout, 404, "Not Found", "The resource specified by the URL does not exist.")
+ sys.exit(0)
+
+try:
+ f = ssifile(open(path), url, path)
+except Exception:
+ simpleerror(sys.stdout, 500, "Server Error", "The server could not access its data.")
+ sys.exit(1)
+try:
+ sys.stdout.write("HTTP/1.1 200 OK\n")
+ sys.stdout.write("Content-Type: text/html\n")
+ sys.stdout.write("\n")
+ f.initvars(ssivars)
+ f.process()
+finally:
+ f.close()
+