callcgi: Fixed possible deadlock problem on aborted requests.
[ashd.git] / python3 / serve-ssi
1 #!/usr/bin/python3
2
3 import sys, os, io, logging
4 import ashd.ssi, ashd.wsgiutil
5
6 def simpleerror(out, code, title, msg):
7     html = """<?xml version="1.0" encoding="US-ASCII"?>
8 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
9 <html xmlns="http://www.w3.org/1999/xhtml" lang="en-US" xml:lang="en-US">
10 <head>
11 <title>%s</title>
12 </head>
13 <body>
14 <h1>%s</h1>
15 <p>%s</p>
16 </body>
17 </html>
18 """ % (title, title, ashd.wsgiutil.htmlquote(msg))
19     out.write("HTTP/1.1 %d %s\n" % (code, title))
20     out.write("Content-Type: text/html\n")
21     out.write("Content-Length: %d\n" % len(html))
22     out.write("\n")
23     out.write(html)
24
25 if len(sys.argv) < 4:
26     sys.stderr.write("usage: serve-ssi METHOD URL REST\n")
27     sys.exit(1)
28 method, url, rest = sys.argv[1:]
29 path = os.getenv("REQ_X_ASH_FILE")
30 if path is None:
31     simpleerror(sys.stdout, 500, "Server Error", "The server is erroneously configured.")
32     sys.stderr.write("serve-ssi: must be called with the X-Ash-File header\n")
33     sys.exit(1)
34 if rest != "":
35     simpleerror(sys.stdout, 404, "Not Found", "The resource specified by the URL does not exist.")
36     sys.exit(0)
37
38 class encwrap(io.TextIOWrapper):
39     def close(self):
40         pass
41
42 logging.basicConfig(format="serve-ssi: %(message)s")
43 try:
44     try:
45         f = ashd.ssi.getfile(path)
46     except Exception as e:
47         sys.stderr.write("server-ssi: %s\n" % e)
48         simpleerror(sys.stdout, 500, "Server Error", "The server could not access its data.")
49         sys.exit(1)
50     sys.stdout.write("HTTP/1.1 200 OK\n")
51     sys.stdout.write("Content-Type: text/html; charset=UTF-8\n")
52     sys.stdout.write("\n")
53     sys.stdout.flush()
54     wrap = encwrap(sys.stdout.buffer, encoding="utf8")
55     f.process(ashd.ssi.context(wrap, f))
56     wrap.flush()
57 except IOError:
58     # This is for catching EPIPE, when the client has closed the
59     # connection. This shouldn't *really* be necessary since the
60     # process should terminate with SIGPIPE, but apparently Python
61     # ignores that.
62     sys.exit(1)