115
121
# process_cgi_line: Reads a single line of CGI output and processes it.
116
122
# Prints to req, and also does fancy HTML warnings if Content-Type
119
cgiflags.got_cgi_header = False
120
cgiflags.started_cgi_body = False
121
cgiflags.wrote_html_warning = False
122
def process_cgi_line(line):
123
# FIXME? Issue with binary files (processing per-line?)
124
if cgiflags.started_cgi_body:
125
# FIXME: HTML escape text if wrote_html_warning
129
if line.strip() == "" and cgiflags.got_cgi_header:
130
cgiflags.started_cgi_body = True
131
elif line.startswith("Content-Type:"):
132
req.content_type = line[13:].strip()
133
cgiflags.got_cgi_header = True
134
elif line.startswith("Location:"):
136
cgiflags.got_cgi_header = True
137
elif line.startswith("Status:"):
139
cgiflags.got_cgi_header = True
140
elif cgiflags.got_cgi_header:
143
req.write("Invalid header")
146
# Assume the user is not printing headers and give a warning
148
# User program did not print header.
149
# Make a fancy HTML warning for them.
150
req.content_type = "text/html"
151
req.write("""<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
124
cgiflags = CGIFlags()
126
# Read from the process's stdout into req
127
data = pid.stdout.read(CGI_BLOCK_SIZE)
129
process_cgi_output(req, data, cgiflags)
130
data = pid.stdout.read(CGI_BLOCK_SIZE)
132
# If we wrote an HTML warning header, write the footer
133
if cgiflags.wrote_html_warning:
139
def process_cgi_output(req, data, cgiflags):
140
"""Processes a chunk of CGI output. data is a string of arbitrary length;
141
some arbitrary chunk of output written by the CGI script."""
142
if cgiflags.started_cgi_body:
143
# FIXME: HTML escape text if wrote_html_warning
146
# Break data into lines of CGI header data.
147
linebuf = cgiflags.linebuf + data
148
# First see if we can split all header data
149
split = linebuf.split('\r\n\r\n', 1)
151
# Allow UNIX newlines instead
152
split = linebuf.split('\n\n', 1)
154
# Haven't seen all headers yet. Buffer and come back later.
155
cgiflags.linebuf = linebuf
160
cgiflags.linebuf = ""
161
cgiflags.started_cgi_body = True
162
# Process all the header lines
163
split = headers.split('\r\n', 1)
165
split = headers.split('\n', 1)
167
process_cgi_header_line(req, split[0], cgiflags)
168
if len(split) == 1: break
170
split = headers.split('\r\n', 1)
172
split = headers.split('\n', 1)
174
# Call myself to flush out the extra bit of data we read
175
process_cgi_output(req, data, cgiflags)
177
def process_cgi_header_line(req, line, cgiflags):
178
"""Process a line of CGI header data. line is a string representing a
179
complete line of text, stripped and without the newline.
180
Will set cgiflags.started_cgi_body when it detects an empty line, so the
181
caller should realise this and change to byte stream output mode.
184
if line.strip() == "" and cgiflags.got_cgi_header:
185
cgiflags.started_cgi_body = True
186
elif line.startswith("Content-Type:"):
187
req.content_type = line[13:].strip()
188
cgiflags.got_cgi_header = True
189
elif line.startswith("Location:"):
191
cgiflags.got_cgi_header = True
192
elif line.startswith("Status:"):
194
cgiflags.got_cgi_header = True
195
elif cgiflags.got_cgi_header:
198
req.write("Invalid header")
201
# Assume the user is not printing headers and give a warning
203
# User program did not print header.
204
# Make a fancy HTML warning for them.
205
req.content_type = "text/html"
206
write_html_warning(req,
207
"""You did not print a "Content-Type" header.
208
CGI requires you to print some content type. You may wish to try:</p>
209
<pre style="margin-left: 1em">Content-Type: text/html</pre>""", cgiflags)
210
cgiflags.got_cgi_header = True
211
cgiflags.started_cgi_body = True
214
def write_html_warning(req, text, cgiflags):
215
"""Prints an HTML warning about invalid CGI interaction on the part of the
216
user. text may contain HTML markup."""
217
req.write("""<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
152
218
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
153
219
<html xmlns="http://www.w3.org/1999/xhtml">
158
224
<body style="margin: 0; padding: 0; font-family: sans-serif;">
159
225
<div style="background-color: #faa; border-bottom: 1px solid black;
161
<p><strong>Warning</strong>: You did not print a "Content-Type" header.
162
CGI requires you to print some content type. You may wish to try:</p>
163
<pre style="margin-left: 1em">Content-Type: text/html</pre>
227
<p><strong>Warning</strong>: %s
165
229
<div style="margin: 8px;">
168
cgiflags.got_cgi_header = True
169
cgiflags.wrote_html_warning = True
170
cgiflags.started_cgi_body = True
173
# Read from the process's stdout into req
174
for line in pid.stdout:
175
process_cgi_line(line)
177
# If we wrote an HTML warning header, write the footer
178
if cgiflags.wrote_html_warning:
184
# TODO: Replace mytest with cgi trampoline handler script
232
cgiflags.wrote_html_warning = True
185
235
location_cgi_python = os.path.join(conf.ivle_install_dir,
186
236
"bin/trampoline")