blob: 0184472a531d505179f91b05651ab99c5eab5ca8 [file] [log] [blame]
Guido van Rossum152f9d91997-02-18 16:55:33 +00001#! /usr/local/bin/python
Guido van Rossum1c9daa81995-09-18 21:52:37 +00002
Guido van Rossum72755611996-03-06 07:20:06 +00003"""Support module for CGI (Common Gateway Interface) scripts.
Guido van Rossum1c9daa81995-09-18 21:52:37 +00004
Guido van Rossum7aee3841996-03-07 18:00:44 +00005This module defines a number of utilities for use by CGI scripts
6written in Python.
Guido van Rossum72755611996-03-06 07:20:06 +00007"""
8
Jeremy Hyltonc253d9a2000-08-03 20:57:44 +00009# XXX Perhaps there should be a slimmed version that doesn't contain
10# all those backwards compatible and debugging classes and functions?
Guido van Rossum98d9fd32000-02-28 15:12:25 +000011
12# History
13# -------
14#
15# Michael McLay started this module. Steve Majewski changed the
16# interface to SvFormContentDict and FormContentDict. The multipart
17# parsing was inspired by code submitted by Andreas Paepcke. Guido van
18# Rossum rewrote, reformatted and documented the module and is currently
19# responsible for its maintenance.
20#
21
Guido van Rossum5f322481997-04-11 18:20:42 +000022__version__ = "2.2"
Guido van Rossum0147db01996-03-09 03:16:04 +000023
Guido van Rossum72755611996-03-06 07:20:06 +000024
25# Imports
26# =======
27
28import string
Guido van Rossum72755611996-03-06 07:20:06 +000029import sys
30import os
Guido van Rossuma5e9fb61997-08-12 18:18:13 +000031import urllib
Guido van Rossuma5e9fb61997-08-12 18:18:13 +000032import mimetools
33import rfc822
34from StringIO import StringIO
Guido van Rossum72755611996-03-06 07:20:06 +000035
Guido van Rossumc204c701996-09-05 19:07:11 +000036
37# Logging support
38# ===============
39
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000040logfile = "" # Filename to log to, if not empty
41logfp = None # File object to log to, if not None
Guido van Rossumc204c701996-09-05 19:07:11 +000042
43def initlog(*allargs):
44 """Write a log message, if there is a log file.
45
46 Even though this function is called initlog(), you should always
47 use log(); log is a variable that is set either to initlog
48 (initially), to dolog (once the log file has been opened), or to
49 nolog (when logging is disabled).
50
51 The first argument is a format string; the remaining arguments (if
52 any) are arguments to the % operator, so e.g.
53 log("%s: %s", "a", "b")
54 will write "a: b" to the log file, followed by a newline.
55
56 If the global logfp is not None, it should be a file object to
57 which log data is written.
58
59 If the global logfp is None, the global logfile may be a string
60 giving a filename to open, in append mode. This file should be
61 world writable!!! If the file can't be opened, logging is
62 silently disabled (since there is no safe place where we could
63 send an error message).
64
65 """
66 global logfp, log
67 if logfile and not logfp:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000068 try:
69 logfp = open(logfile, "a")
70 except IOError:
71 pass
Guido van Rossumc204c701996-09-05 19:07:11 +000072 if not logfp:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000073 log = nolog
Guido van Rossumc204c701996-09-05 19:07:11 +000074 else:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000075 log = dolog
Guido van Rossumc204c701996-09-05 19:07:11 +000076 apply(log, allargs)
77
78def dolog(fmt, *args):
79 """Write a log message to the log file. See initlog() for docs."""
80 logfp.write(fmt%args + "\n")
81
82def nolog(*allargs):
83 """Dummy function, assigned to log when logging is disabled."""
84 pass
85
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000086log = initlog # The current logging function
Guido van Rossumc204c701996-09-05 19:07:11 +000087
88
Guido van Rossum72755611996-03-06 07:20:06 +000089# Parsing functions
90# =================
91
Guido van Rossumad164711997-05-13 19:03:23 +000092# Maximum input we will accept when REQUEST_METHOD is POST
93# 0 ==> unlimited input
94maxlen = 0
95
Guido van Rossume08c04c1996-11-11 19:29:11 +000096def parse(fp=None, environ=os.environ, keep_blank_values=0, strict_parsing=0):
Guido van Rossum773ab271996-07-23 03:46:24 +000097 """Parse a query in the environment or from a file (default stdin)
98
99 Arguments, all optional:
100
101 fp : file pointer; default: sys.stdin
102
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000103 environ : environment dictionary; default: os.environ
Guido van Rossum773ab271996-07-23 03:46:24 +0000104
105 keep_blank_values: flag indicating whether blank values in
106 URL encoded forms should be treated as blank strings.
Thomas Wouters7e474022000-07-16 12:04:32 +0000107 A true value indicates that blanks should be retained as
Guido van Rossum773ab271996-07-23 03:46:24 +0000108 blank strings. The default false value indicates that
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000109 blank values are to be ignored and treated as if they were
110 not included.
Guido van Rossume08c04c1996-11-11 19:29:11 +0000111
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000112 strict_parsing: flag indicating what to do with parsing errors.
113 If false (the default), errors are silently ignored.
114 If true, errors raise a ValueError exception.
Guido van Rossum773ab271996-07-23 03:46:24 +0000115 """
Guido van Rossum7aee3841996-03-07 18:00:44 +0000116 if not fp:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000117 fp = sys.stdin
Guido van Rossum7aee3841996-03-07 18:00:44 +0000118 if not environ.has_key('REQUEST_METHOD'):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000119 environ['REQUEST_METHOD'] = 'GET' # For testing stand-alone
Guido van Rossum7aee3841996-03-07 18:00:44 +0000120 if environ['REQUEST_METHOD'] == 'POST':
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000121 ctype, pdict = parse_header(environ['CONTENT_TYPE'])
122 if ctype == 'multipart/form-data':
123 return parse_multipart(fp, pdict)
124 elif ctype == 'application/x-www-form-urlencoded':
125 clength = string.atoi(environ['CONTENT_LENGTH'])
126 if maxlen and clength > maxlen:
127 raise ValueError, 'Maximum content length exceeded'
128 qs = fp.read(clength)
129 else:
130 qs = '' # Unknown content-type
131 if environ.has_key('QUERY_STRING'):
132 if qs: qs = qs + '&'
133 qs = qs + environ['QUERY_STRING']
134 elif sys.argv[1:]:
135 if qs: qs = qs + '&'
136 qs = qs + sys.argv[1]
137 environ['QUERY_STRING'] = qs # XXX Shouldn't, really
Guido van Rossum7aee3841996-03-07 18:00:44 +0000138 elif environ.has_key('QUERY_STRING'):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000139 qs = environ['QUERY_STRING']
Guido van Rossum7aee3841996-03-07 18:00:44 +0000140 else:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000141 if sys.argv[1:]:
142 qs = sys.argv[1]
143 else:
144 qs = ""
145 environ['QUERY_STRING'] = qs # XXX Shouldn't, really
Guido van Rossume08c04c1996-11-11 19:29:11 +0000146 return parse_qs(qs, keep_blank_values, strict_parsing)
Guido van Rossume7808771995-08-07 20:12:09 +0000147
148
Guido van Rossume08c04c1996-11-11 19:29:11 +0000149def parse_qs(qs, keep_blank_values=0, strict_parsing=0):
150 """Parse a query given as a string argument.
Guido van Rossum773ab271996-07-23 03:46:24 +0000151
152 Arguments:
153
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000154 qs: URL-encoded query string to be parsed
Guido van Rossum773ab271996-07-23 03:46:24 +0000155
156 keep_blank_values: flag indicating whether blank values in
157 URL encoded queries should be treated as blank strings.
Thomas Wouters7e474022000-07-16 12:04:32 +0000158 A true value indicates that blanks should be retained as
Guido van Rossum773ab271996-07-23 03:46:24 +0000159 blank strings. The default false value indicates that
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000160 blank values are to be ignored and treated as if they were
161 not included.
Guido van Rossume08c04c1996-11-11 19:29:11 +0000162
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000163 strict_parsing: flag indicating what to do with parsing errors.
164 If false (the default), errors are silently ignored.
165 If true, errors raise a ValueError exception.
Guido van Rossum773ab271996-07-23 03:46:24 +0000166 """
Guido van Rossum7aee3841996-03-07 18:00:44 +0000167 dict = {}
Guido van Rossum1946f0d1999-06-04 17:54:39 +0000168 for name, value in parse_qsl(qs, keep_blank_values, strict_parsing):
169 if len(value) or keep_blank_values:
170 if dict.has_key(name):
171 dict[name].append(value)
172 else:
173 dict[name] = [value]
174 return dict
175
176def parse_qsl(qs, keep_blank_values=0, strict_parsing=0):
177 """Parse a query given as a string argument.
178
179 Arguments:
180
181 qs: URL-encoded query string to be parsed
182
183 keep_blank_values: flag indicating whether blank values in
184 URL encoded queries should be treated as blank strings.
Thomas Wouters7e474022000-07-16 12:04:32 +0000185 A true value indicates that blanks should be retained as
Guido van Rossum1946f0d1999-06-04 17:54:39 +0000186 blank strings. The default false value indicates that
187 blank values are to be ignored and treated as if they were
188 not included.
189
190 strict_parsing: flag indicating what to do with parsing errors.
191 If false (the default), errors are silently ignored.
192 If true, errors raise a ValueError exception.
193
194 Returns a list, as God intended.
195 """
196 name_value_pairs = string.splitfields(qs, '&')
197 r=[]
Guido van Rossum7aee3841996-03-07 18:00:44 +0000198 for name_value in name_value_pairs:
Jeremy Hyltonc253d9a2000-08-03 20:57:44 +0000199 nv = string.splitfields(name_value, '=', 1)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000200 if len(nv) != 2:
201 if strict_parsing:
202 raise ValueError, "bad query field: %s" % `name_value`
203 continue
204 name = urllib.unquote(string.replace(nv[0], '+', ' '))
205 value = urllib.unquote(string.replace(nv[1], '+', ' '))
Guido van Rossum3af7b052000-02-25 11:44:03 +0000206 r.append((name, value))
Guido van Rossum1946f0d1999-06-04 17:54:39 +0000207
208 return r
Guido van Rossum9a22de11995-01-12 12:29:47 +0000209
210
Guido van Rossum0147db01996-03-09 03:16:04 +0000211def parse_multipart(fp, pdict):
Guido van Rossum7aee3841996-03-07 18:00:44 +0000212 """Parse multipart input.
Guido van Rossum9a22de11995-01-12 12:29:47 +0000213
Guido van Rossum7aee3841996-03-07 18:00:44 +0000214 Arguments:
215 fp : input file
Guido van Rossum7aee3841996-03-07 18:00:44 +0000216 pdict: dictionary containing other parameters of conten-type header
Guido van Rossum72755611996-03-06 07:20:06 +0000217
Guido van Rossum0147db01996-03-09 03:16:04 +0000218 Returns a dictionary just like parse_qs(): keys are the field names, each
219 value is a list of values for that field. This is easy to use but not
220 much good if you are expecting megabytes to be uploaded -- in that case,
221 use the FieldStorage class instead which is much more flexible. Note
222 that content-type is the raw, unparsed contents of the content-type
223 header.
224
225 XXX This does not parse nested multipart parts -- use FieldStorage for
226 that.
227
228 XXX This should really be subsumed by FieldStorage altogether -- no
229 point in having two implementations of the same parsing algorithm.
Guido van Rossum72755611996-03-06 07:20:06 +0000230
Guido van Rossum7aee3841996-03-07 18:00:44 +0000231 """
Guido van Rossum7aee3841996-03-07 18:00:44 +0000232 if pdict.has_key('boundary'):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000233 boundary = pdict['boundary']
Guido van Rossum7aee3841996-03-07 18:00:44 +0000234 else:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000235 boundary = ""
Guido van Rossum7aee3841996-03-07 18:00:44 +0000236 nextpart = "--" + boundary
237 lastpart = "--" + boundary + "--"
238 partdict = {}
239 terminator = ""
240
241 while terminator != lastpart:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000242 bytes = -1
243 data = None
244 if terminator:
245 # At start of next part. Read headers first.
246 headers = mimetools.Message(fp)
247 clength = headers.getheader('content-length')
248 if clength:
249 try:
250 bytes = string.atoi(clength)
251 except string.atoi_error:
252 pass
253 if bytes > 0:
254 if maxlen and bytes > maxlen:
255 raise ValueError, 'Maximum content length exceeded'
256 data = fp.read(bytes)
257 else:
258 data = ""
259 # Read lines until end of part.
260 lines = []
261 while 1:
262 line = fp.readline()
263 if not line:
264 terminator = lastpart # End outer loop
265 break
266 if line[:2] == "--":
267 terminator = string.strip(line)
268 if terminator in (nextpart, lastpart):
269 break
270 lines.append(line)
271 # Done with part.
272 if data is None:
273 continue
274 if bytes < 0:
275 if lines:
276 # Strip final line terminator
277 line = lines[-1]
278 if line[-2:] == "\r\n":
279 line = line[:-2]
280 elif line[-1:] == "\n":
281 line = line[:-1]
282 lines[-1] = line
283 data = string.joinfields(lines, "")
284 line = headers['content-disposition']
285 if not line:
286 continue
287 key, params = parse_header(line)
288 if key != 'form-data':
289 continue
290 if params.has_key('name'):
291 name = params['name']
292 else:
293 continue
294 if partdict.has_key(name):
295 partdict[name].append(data)
296 else:
297 partdict[name] = [data]
Guido van Rossum72755611996-03-06 07:20:06 +0000298
Guido van Rossum7aee3841996-03-07 18:00:44 +0000299 return partdict
Guido van Rossum9a22de11995-01-12 12:29:47 +0000300
301
Guido van Rossum72755611996-03-06 07:20:06 +0000302def parse_header(line):
Guido van Rossum7aee3841996-03-07 18:00:44 +0000303 """Parse a Content-type like header.
304
305 Return the main content-type and a dictionary of options.
306
307 """
308 plist = map(string.strip, string.splitfields(line, ';'))
309 key = string.lower(plist[0])
310 del plist[0]
311 pdict = {}
312 for p in plist:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000313 i = string.find(p, '=')
314 if i >= 0:
315 name = string.lower(string.strip(p[:i]))
316 value = string.strip(p[i+1:])
317 if len(value) >= 2 and value[0] == value[-1] == '"':
318 value = value[1:-1]
319 pdict[name] = value
Guido van Rossum7aee3841996-03-07 18:00:44 +0000320 return key, pdict
Guido van Rossum72755611996-03-06 07:20:06 +0000321
322
Guido van Rossum243ddcd1996-03-07 06:33:07 +0000323# Classes for field storage
324# =========================
325
326class MiniFieldStorage:
327
Guido van Rossum0147db01996-03-09 03:16:04 +0000328 """Like FieldStorage, for use when no file uploads are possible."""
Guido van Rossum243ddcd1996-03-07 06:33:07 +0000329
Guido van Rossum7aee3841996-03-07 18:00:44 +0000330 # Dummy attributes
331 filename = None
332 list = None
333 type = None
Guido van Rossum773ab271996-07-23 03:46:24 +0000334 file = None
Guido van Rossum4032c2c1996-03-09 04:04:35 +0000335 type_options = {}
Guido van Rossum7aee3841996-03-07 18:00:44 +0000336 disposition = None
337 disposition_options = {}
338 headers = {}
Guido van Rossum243ddcd1996-03-07 06:33:07 +0000339
Guido van Rossum7aee3841996-03-07 18:00:44 +0000340 def __init__(self, name, value):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000341 """Constructor from field name and value."""
342 self.name = name
343 self.value = value
Guido van Rossum773ab271996-07-23 03:46:24 +0000344 # self.file = StringIO(value)
Guido van Rossum7aee3841996-03-07 18:00:44 +0000345
346 def __repr__(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000347 """Return printable representation."""
348 return "MiniFieldStorage(%s, %s)" % (`self.name`, `self.value`)
Guido van Rossum243ddcd1996-03-07 06:33:07 +0000349
350
351class FieldStorage:
352
Guido van Rossum7aee3841996-03-07 18:00:44 +0000353 """Store a sequence of fields, reading multipart/form-data.
Guido van Rossum243ddcd1996-03-07 06:33:07 +0000354
Guido van Rossum7aee3841996-03-07 18:00:44 +0000355 This class provides naming, typing, files stored on disk, and
356 more. At the top level, it is accessible like a dictionary, whose
357 keys are the field names. (Note: None can occur as a field name.)
358 The items are either a Python list (if there's multiple values) or
359 another FieldStorage or MiniFieldStorage object. If it's a single
360 object, it has the following attributes:
Guido van Rossum243ddcd1996-03-07 06:33:07 +0000361
Guido van Rossum7aee3841996-03-07 18:00:44 +0000362 name: the field name, if specified; otherwise None
Guido van Rossum243ddcd1996-03-07 06:33:07 +0000363
Guido van Rossum7aee3841996-03-07 18:00:44 +0000364 filename: the filename, if specified; otherwise None; this is the
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000365 client side filename, *not* the file name on which it is
366 stored (that's a temporary file you don't deal with)
Guido van Rossum243ddcd1996-03-07 06:33:07 +0000367
Guido van Rossum7aee3841996-03-07 18:00:44 +0000368 value: the value as a *string*; for file uploads, this
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000369 transparently reads the file every time you request the value
Guido van Rossum7aee3841996-03-07 18:00:44 +0000370
371 file: the file(-like) object from which you can read the data;
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000372 None if the data is stored a simple string
Guido van Rossum7aee3841996-03-07 18:00:44 +0000373
374 type: the content-type, or None if not specified
375
376 type_options: dictionary of options specified on the content-type
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000377 line
Guido van Rossum7aee3841996-03-07 18:00:44 +0000378
379 disposition: content-disposition, or None if not specified
380
381 disposition_options: dictionary of corresponding options
382
383 headers: a dictionary(-like) object (sometimes rfc822.Message or a
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000384 subclass thereof) containing *all* headers
Guido van Rossum7aee3841996-03-07 18:00:44 +0000385
386 The class is subclassable, mostly for the purpose of overriding
387 the make_file() method, which is called internally to come up with
388 a file open for reading and writing. This makes it possible to
389 override the default choice of storing all files in a temporary
390 directory and unlinking them as soon as they have been opened.
391
392 """
393
Guido van Rossum773ab271996-07-23 03:46:24 +0000394 def __init__(self, fp=None, headers=None, outerboundary="",
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000395 environ=os.environ, keep_blank_values=0, strict_parsing=0):
396 """Constructor. Read multipart/* until last part.
Guido van Rossum7aee3841996-03-07 18:00:44 +0000397
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000398 Arguments, all optional:
Guido van Rossum7aee3841996-03-07 18:00:44 +0000399
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000400 fp : file pointer; default: sys.stdin
Guido van Rossumb1b4f941998-05-08 19:55:51 +0000401 (not used when the request method is GET)
Guido van Rossum7aee3841996-03-07 18:00:44 +0000402
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000403 headers : header dictionary-like object; default:
404 taken from environ as per CGI spec
Guido van Rossum7aee3841996-03-07 18:00:44 +0000405
Guido van Rossum773ab271996-07-23 03:46:24 +0000406 outerboundary : terminating multipart boundary
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000407 (for internal use only)
Guido van Rossum7aee3841996-03-07 18:00:44 +0000408
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000409 environ : environment dictionary; default: os.environ
Guido van Rossum773ab271996-07-23 03:46:24 +0000410
411 keep_blank_values: flag indicating whether blank values in
412 URL encoded forms should be treated as blank strings.
Thomas Wouters7e474022000-07-16 12:04:32 +0000413 A true value indicates that blanks should be retained as
Guido van Rossum773ab271996-07-23 03:46:24 +0000414 blank strings. The default false value indicates that
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000415 blank values are to be ignored and treated as if they were
416 not included.
Guido van Rossum773ab271996-07-23 03:46:24 +0000417
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000418 strict_parsing: flag indicating what to do with parsing errors.
419 If false (the default), errors are silently ignored.
420 If true, errors raise a ValueError exception.
Guido van Rossume08c04c1996-11-11 19:29:11 +0000421
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000422 """
423 method = 'GET'
424 self.keep_blank_values = keep_blank_values
425 self.strict_parsing = strict_parsing
426 if environ.has_key('REQUEST_METHOD'):
427 method = string.upper(environ['REQUEST_METHOD'])
Guido van Rossum01852831998-06-25 02:40:17 +0000428 if method == 'GET' or method == 'HEAD':
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000429 if environ.has_key('QUERY_STRING'):
430 qs = environ['QUERY_STRING']
431 elif sys.argv[1:]:
432 qs = sys.argv[1]
433 else:
434 qs = ""
435 fp = StringIO(qs)
436 if headers is None:
437 headers = {'content-type':
438 "application/x-www-form-urlencoded"}
439 if headers is None:
Guido van Rossumcff311a1998-06-11 14:06:59 +0000440 headers = {}
441 if method == 'POST':
442 # Set default content-type for POST to what's traditional
443 headers['content-type'] = "application/x-www-form-urlencoded"
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000444 if environ.has_key('CONTENT_TYPE'):
445 headers['content-type'] = environ['CONTENT_TYPE']
446 if environ.has_key('CONTENT_LENGTH'):
447 headers['content-length'] = environ['CONTENT_LENGTH']
448 self.fp = fp or sys.stdin
449 self.headers = headers
450 self.outerboundary = outerboundary
Guido van Rossum7aee3841996-03-07 18:00:44 +0000451
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000452 # Process content-disposition header
453 cdisp, pdict = "", {}
454 if self.headers.has_key('content-disposition'):
455 cdisp, pdict = parse_header(self.headers['content-disposition'])
456 self.disposition = cdisp
457 self.disposition_options = pdict
458 self.name = None
459 if pdict.has_key('name'):
460 self.name = pdict['name']
461 self.filename = None
462 if pdict.has_key('filename'):
463 self.filename = pdict['filename']
Guido van Rossum7aee3841996-03-07 18:00:44 +0000464
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000465 # Process content-type header
Barry Warsaw302331a1999-01-08 17:42:03 +0000466 #
467 # Honor any existing content-type header. But if there is no
468 # content-type header, use some sensible defaults. Assume
469 # outerboundary is "" at the outer level, but something non-false
470 # inside a multi-part. The default for an inner part is text/plain,
471 # but for an outer part it should be urlencoded. This should catch
472 # bogus clients which erroneously forget to include a content-type
473 # header.
474 #
475 # See below for what we do if there does exist a content-type header,
476 # but it happens to be something we don't understand.
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000477 if self.headers.has_key('content-type'):
478 ctype, pdict = parse_header(self.headers['content-type'])
Guido van Rossumce900de1999-06-02 18:44:22 +0000479 elif self.outerboundary or method != 'POST':
Barry Warsaw302331a1999-01-08 17:42:03 +0000480 ctype, pdict = "text/plain", {}
481 else:
482 ctype, pdict = 'application/x-www-form-urlencoded', {}
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000483 self.type = ctype
484 self.type_options = pdict
485 self.innerboundary = ""
486 if pdict.has_key('boundary'):
487 self.innerboundary = pdict['boundary']
488 clen = -1
489 if self.headers.has_key('content-length'):
490 try:
491 clen = string.atoi(self.headers['content-length'])
492 except:
493 pass
494 if maxlen and clen > maxlen:
495 raise ValueError, 'Maximum content length exceeded'
496 self.length = clen
Guido van Rossum7aee3841996-03-07 18:00:44 +0000497
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000498 self.list = self.file = None
499 self.done = 0
500 self.lines = []
501 if ctype == 'application/x-www-form-urlencoded':
502 self.read_urlencoded()
503 elif ctype[:10] == 'multipart/':
Guido van Rossumf5745001998-10-20 14:43:02 +0000504 self.read_multi(environ, keep_blank_values, strict_parsing)
Barry Warsaw302331a1999-01-08 17:42:03 +0000505 else:
Guido van Rossum60a3bd81999-06-11 18:26:09 +0000506 self.read_single()
Guido van Rossum7aee3841996-03-07 18:00:44 +0000507
508 def __repr__(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000509 """Return a printable representation."""
510 return "FieldStorage(%s, %s, %s)" % (
511 `self.name`, `self.filename`, `self.value`)
Guido van Rossum7aee3841996-03-07 18:00:44 +0000512
513 def __getattr__(self, name):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000514 if name != 'value':
515 raise AttributeError, name
516 if self.file:
517 self.file.seek(0)
518 value = self.file.read()
519 self.file.seek(0)
520 elif self.list is not None:
521 value = self.list
522 else:
523 value = None
524 return value
Guido van Rossum7aee3841996-03-07 18:00:44 +0000525
526 def __getitem__(self, key):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000527 """Dictionary style indexing."""
528 if self.list is None:
529 raise TypeError, "not indexable"
530 found = []
531 for item in self.list:
532 if item.name == key: found.append(item)
533 if not found:
534 raise KeyError, key
535 if len(found) == 1:
536 return found[0]
537 else:
538 return found
Guido van Rossum7aee3841996-03-07 18:00:44 +0000539
540 def keys(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000541 """Dictionary style keys() method."""
542 if self.list is None:
543 raise TypeError, "not indexable"
544 keys = []
545 for item in self.list:
546 if item.name not in keys: keys.append(item.name)
547 return keys
Guido van Rossum7aee3841996-03-07 18:00:44 +0000548
Guido van Rossum0147db01996-03-09 03:16:04 +0000549 def has_key(self, key):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000550 """Dictionary style has_key() method."""
551 if self.list is None:
552 raise TypeError, "not indexable"
553 for item in self.list:
554 if item.name == key: return 1
555 return 0
Guido van Rossum0147db01996-03-09 03:16:04 +0000556
Guido van Rossum88b85d41997-01-11 19:21:33 +0000557 def __len__(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000558 """Dictionary style len(x) support."""
559 return len(self.keys())
Guido van Rossum88b85d41997-01-11 19:21:33 +0000560
Guido van Rossum7aee3841996-03-07 18:00:44 +0000561 def read_urlencoded(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000562 """Internal: read data in query string format."""
563 qs = self.fp.read(self.length)
Guido van Rossum1946f0d1999-06-04 17:54:39 +0000564 self.list = list = []
565 for key, value in parse_qsl(qs, self.keep_blank_values,
566 self.strict_parsing):
567 list.append(MiniFieldStorage(key, value))
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000568 self.skip_lines()
Guido van Rossum7aee3841996-03-07 18:00:44 +0000569
Guido van Rossum030d2ec1998-12-09 22:16:46 +0000570 FieldStorageClass = None
571
Guido van Rossumf5745001998-10-20 14:43:02 +0000572 def read_multi(self, environ, keep_blank_values, strict_parsing):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000573 """Internal: read a part that is itself multipart."""
574 self.list = []
Guido van Rossum030d2ec1998-12-09 22:16:46 +0000575 klass = self.FieldStorageClass or self.__class__
576 part = klass(self.fp, {}, self.innerboundary,
577 environ, keep_blank_values, strict_parsing)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000578 # Throw first part away
579 while not part.done:
580 headers = rfc822.Message(self.fp)
Guido van Rossum030d2ec1998-12-09 22:16:46 +0000581 part = klass(self.fp, headers, self.innerboundary,
582 environ, keep_blank_values, strict_parsing)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000583 self.list.append(part)
584 self.skip_lines()
Guido van Rossum7aee3841996-03-07 18:00:44 +0000585
586 def read_single(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000587 """Internal: read an atomic part."""
588 if self.length >= 0:
589 self.read_binary()
590 self.skip_lines()
591 else:
592 self.read_lines()
593 self.file.seek(0)
Guido van Rossum7aee3841996-03-07 18:00:44 +0000594
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000595 bufsize = 8*1024 # I/O buffering size for copy to file
Guido van Rossum7aee3841996-03-07 18:00:44 +0000596
597 def read_binary(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000598 """Internal: read binary data."""
599 self.file = self.make_file('b')
600 todo = self.length
601 if todo >= 0:
602 while todo > 0:
603 data = self.fp.read(min(todo, self.bufsize))
604 if not data:
605 self.done = -1
606 break
607 self.file.write(data)
608 todo = todo - len(data)
Guido van Rossum7aee3841996-03-07 18:00:44 +0000609
610 def read_lines(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000611 """Internal: read lines until EOF or outerboundary."""
612 self.file = self.make_file('')
613 if self.outerboundary:
614 self.read_lines_to_outerboundary()
615 else:
616 self.read_lines_to_eof()
Guido van Rossum7aee3841996-03-07 18:00:44 +0000617
618 def read_lines_to_eof(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000619 """Internal: read lines until EOF."""
620 while 1:
621 line = self.fp.readline()
622 if not line:
623 self.done = -1
624 break
625 self.lines.append(line)
626 self.file.write(line)
Guido van Rossum7aee3841996-03-07 18:00:44 +0000627
628 def read_lines_to_outerboundary(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000629 """Internal: read lines until outerboundary."""
630 next = "--" + self.outerboundary
631 last = next + "--"
632 delim = ""
633 while 1:
634 line = self.fp.readline()
635 if not line:
636 self.done = -1
637 break
638 self.lines.append(line)
639 if line[:2] == "--":
640 strippedline = string.strip(line)
641 if strippedline == next:
642 break
643 if strippedline == last:
644 self.done = 1
645 break
646 odelim = delim
647 if line[-2:] == "\r\n":
648 delim = "\r\n"
649 line = line[:-2]
650 elif line[-1] == "\n":
651 delim = "\n"
652 line = line[:-1]
653 else:
654 delim = ""
655 self.file.write(odelim + line)
Guido van Rossum7aee3841996-03-07 18:00:44 +0000656
657 def skip_lines(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000658 """Internal: skip lines until outer boundary if defined."""
659 if not self.outerboundary or self.done:
660 return
661 next = "--" + self.outerboundary
662 last = next + "--"
663 while 1:
664 line = self.fp.readline()
665 if not line:
666 self.done = -1
667 break
668 self.lines.append(line)
669 if line[:2] == "--":
670 strippedline = string.strip(line)
671 if strippedline == next:
672 break
673 if strippedline == last:
674 self.done = 1
675 break
Guido van Rossum7aee3841996-03-07 18:00:44 +0000676
Guido van Rossuma5e9fb61997-08-12 18:18:13 +0000677 def make_file(self, binary=None):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000678 """Overridable: return a readable & writable file.
Guido van Rossum7aee3841996-03-07 18:00:44 +0000679
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000680 The file will be used as follows:
681 - data is written to it
682 - seek(0)
683 - data is read from it
Guido van Rossum7aee3841996-03-07 18:00:44 +0000684
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000685 The 'binary' argument is unused -- the file is always opened
686 in binary mode.
Guido van Rossum7aee3841996-03-07 18:00:44 +0000687
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000688 This version opens a temporary file for reading and writing,
689 and immediately deletes (unlinks) it. The trick (on Unix!) is
690 that the file can still be used, but it can't be opened by
691 another process, and it will automatically be deleted when it
692 is closed or when the current process terminates.
Guido van Rossum4032c2c1996-03-09 04:04:35 +0000693
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000694 If you want a more permanent file, you derive a class which
695 overrides this method. If you want a visible temporary file
696 that is nevertheless automatically deleted when the script
697 terminates, try defining a __del__ method in a derived class
698 which unlinks the temporary files you have created.
Guido van Rossum7aee3841996-03-07 18:00:44 +0000699
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000700 """
701 import tempfile
702 return tempfile.TemporaryFile("w+b")
703
Guido van Rossum243ddcd1996-03-07 06:33:07 +0000704
705
Guido van Rossum4032c2c1996-03-09 04:04:35 +0000706# Backwards Compatibility Classes
707# ===============================
Guido van Rossum9a22de11995-01-12 12:29:47 +0000708
709class FormContentDict:
Guido van Rossum7aee3841996-03-07 18:00:44 +0000710 """Basic (multiple values per field) form content as dictionary.
Guido van Rossum72755611996-03-06 07:20:06 +0000711
Guido van Rossum7aee3841996-03-07 18:00:44 +0000712 form = FormContentDict()
713
714 form[key] -> [value, value, ...]
715 form.has_key(key) -> Boolean
716 form.keys() -> [key, key, ...]
717 form.values() -> [[val, val, ...], [val, val, ...], ...]
718 form.items() -> [(key, [val, val, ...]), (key, [val, val, ...]), ...]
719 form.dict == {key: [val, val, ...], ...}
720
721 """
Guido van Rossum773ab271996-07-23 03:46:24 +0000722 def __init__(self, environ=os.environ):
Guido van Rossumafb5e931996-08-08 18:42:12 +0000723 self.dict = parse(environ=environ)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000724 self.query_string = environ['QUERY_STRING']
Guido van Rossum7aee3841996-03-07 18:00:44 +0000725 def __getitem__(self,key):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000726 return self.dict[key]
Guido van Rossum7aee3841996-03-07 18:00:44 +0000727 def keys(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000728 return self.dict.keys()
Guido van Rossum7aee3841996-03-07 18:00:44 +0000729 def has_key(self, key):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000730 return self.dict.has_key(key)
Guido van Rossum7aee3841996-03-07 18:00:44 +0000731 def values(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000732 return self.dict.values()
Guido van Rossum7aee3841996-03-07 18:00:44 +0000733 def items(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000734 return self.dict.items()
Guido van Rossum7aee3841996-03-07 18:00:44 +0000735 def __len__( self ):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000736 return len(self.dict)
Guido van Rossum9a22de11995-01-12 12:29:47 +0000737
738
Guido van Rossum9a22de11995-01-12 12:29:47 +0000739class SvFormContentDict(FormContentDict):
Guido van Rossum7aee3841996-03-07 18:00:44 +0000740 """Strict single-value expecting form content as dictionary.
741
742 IF you only expect a single value for each field, then form[key]
743 will return that single value. It will raise an IndexError if
744 that expectation is not true. IF you expect a field to have
745 possible multiple values, than you can use form.getlist(key) to
746 get all of the values. values() and items() are a compromise:
747 they return single strings where there is a single value, and
748 lists of strings otherwise.
749
750 """
751 def __getitem__(self, key):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000752 if len(self.dict[key]) > 1:
753 raise IndexError, 'expecting a single value'
754 return self.dict[key][0]
Guido van Rossum7aee3841996-03-07 18:00:44 +0000755 def getlist(self, key):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000756 return self.dict[key]
Guido van Rossum7aee3841996-03-07 18:00:44 +0000757 def values(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000758 lis = []
759 for each in self.dict.values():
760 if len( each ) == 1 :
761 lis.append(each[0])
762 else: lis.append(each)
763 return lis
Guido van Rossum7aee3841996-03-07 18:00:44 +0000764 def items(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000765 lis = []
766 for key,value in self.dict.items():
767 if len(value) == 1 :
768 lis.append((key, value[0]))
769 else: lis.append((key, value))
770 return lis
Guido van Rossum9a22de11995-01-12 12:29:47 +0000771
772
Guido van Rossum9a22de11995-01-12 12:29:47 +0000773class InterpFormContentDict(SvFormContentDict):
Guido van Rossum7aee3841996-03-07 18:00:44 +0000774 """This class is present for backwards compatibility only."""
775 def __getitem__( self, key ):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000776 v = SvFormContentDict.__getitem__( self, key )
777 if v[0] in string.digits+'+-.' :
778 try: return string.atoi( v )
779 except ValueError:
780 try: return string.atof( v )
781 except ValueError: pass
782 return string.strip(v)
Guido van Rossum7aee3841996-03-07 18:00:44 +0000783 def values( self ):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000784 lis = []
785 for key in self.keys():
786 try:
787 lis.append( self[key] )
788 except IndexError:
789 lis.append( self.dict[key] )
790 return lis
Guido van Rossum7aee3841996-03-07 18:00:44 +0000791 def items( self ):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000792 lis = []
793 for key in self.keys():
794 try:
795 lis.append( (key, self[key]) )
796 except IndexError:
797 lis.append( (key, self.dict[key]) )
798 return lis
Guido van Rossum9a22de11995-01-12 12:29:47 +0000799
800
Guido van Rossum9a22de11995-01-12 12:29:47 +0000801class FormContent(FormContentDict):
Guido van Rossum7aee3841996-03-07 18:00:44 +0000802 """This class is present for backwards compatibility only."""
Guido van Rossum0147db01996-03-09 03:16:04 +0000803 def values(self, key):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000804 if self.dict.has_key(key) :return self.dict[key]
805 else: return None
Guido van Rossum0147db01996-03-09 03:16:04 +0000806 def indexed_value(self, key, location):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000807 if self.dict.has_key(key):
808 if len (self.dict[key]) > location:
809 return self.dict[key][location]
810 else: return None
811 else: return None
Guido van Rossum0147db01996-03-09 03:16:04 +0000812 def value(self, key):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000813 if self.dict.has_key(key): return self.dict[key][0]
814 else: return None
Guido van Rossum0147db01996-03-09 03:16:04 +0000815 def length(self, key):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000816 return len(self.dict[key])
Guido van Rossum0147db01996-03-09 03:16:04 +0000817 def stripped(self, key):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000818 if self.dict.has_key(key): return string.strip(self.dict[key][0])
819 else: return None
Guido van Rossum7aee3841996-03-07 18:00:44 +0000820 def pars(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000821 return self.dict
Guido van Rossum9a22de11995-01-12 12:29:47 +0000822
823
Guido van Rossum72755611996-03-06 07:20:06 +0000824# Test/debug code
825# ===============
Guido van Rossum9a22de11995-01-12 12:29:47 +0000826
Guido van Rossum773ab271996-07-23 03:46:24 +0000827def test(environ=os.environ):
Guido van Rossum7aee3841996-03-07 18:00:44 +0000828 """Robust test CGI script, usable as main program.
Guido van Rossum9a22de11995-01-12 12:29:47 +0000829
Guido van Rossum7aee3841996-03-07 18:00:44 +0000830 Write minimal HTTP headers and dump all information provided to
831 the script in HTML form.
832
833 """
834 import traceback
835 print "Content-type: text/html"
836 print
837 sys.stderr = sys.stdout
838 try:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000839 form = FieldStorage() # Replace with other classes to test those
840 print_form(form)
Guido van Rossum773ab271996-07-23 03:46:24 +0000841 print_environ(environ)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000842 print_directory()
843 print_arguments()
844 print_environ_usage()
845 def f():
846 exec "testing print_exception() -- <I>italics?</I>"
847 def g(f=f):
848 f()
849 print "<H3>What follows is a test, not an actual exception:</H3>"
850 g()
Guido van Rossum7aee3841996-03-07 18:00:44 +0000851 except:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000852 print_exception()
Guido van Rossumf85de8a1996-08-20 20:22:39 +0000853
Guido van Rossumad164711997-05-13 19:03:23 +0000854 # Second try with a small maxlen...
855 global maxlen
856 maxlen = 50
857 try:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000858 form = FieldStorage() # Replace with other classes to test those
859 print_form(form)
860 print_environ(environ)
861 print_directory()
862 print_arguments()
863 print_environ_usage()
Guido van Rossumad164711997-05-13 19:03:23 +0000864 except:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000865 print_exception()
Guido van Rossumad164711997-05-13 19:03:23 +0000866
Guido van Rossumf85de8a1996-08-20 20:22:39 +0000867def print_exception(type=None, value=None, tb=None, limit=None):
868 if type is None:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000869 type, value, tb = sys.exc_info()
Guido van Rossumf85de8a1996-08-20 20:22:39 +0000870 import traceback
871 print
872 print "<H3>Traceback (innermost last):</H3>"
873 list = traceback.format_tb(tb, limit) + \
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000874 traceback.format_exception_only(type, value)
Guido van Rossumf85de8a1996-08-20 20:22:39 +0000875 print "<PRE>%s<B>%s</B></PRE>" % (
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000876 escape(string.join(list[:-1], "")),
877 escape(list[-1]),
878 )
Guido van Rossumf15d1591997-09-29 23:22:12 +0000879 del tb
Guido van Rossum9a22de11995-01-12 12:29:47 +0000880
Guido van Rossum773ab271996-07-23 03:46:24 +0000881def print_environ(environ=os.environ):
Guido van Rossum7aee3841996-03-07 18:00:44 +0000882 """Dump the shell environment as HTML."""
883 keys = environ.keys()
884 keys.sort()
885 print
Guido van Rossum503e50b1996-05-28 22:57:20 +0000886 print "<H3>Shell Environment:</H3>"
Guido van Rossum7aee3841996-03-07 18:00:44 +0000887 print "<DL>"
888 for key in keys:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000889 print "<DT>", escape(key), "<DD>", escape(environ[key])
Guido van Rossum7aee3841996-03-07 18:00:44 +0000890 print "</DL>"
891 print
Guido van Rossum72755611996-03-06 07:20:06 +0000892
893def print_form(form):
Guido van Rossum7aee3841996-03-07 18:00:44 +0000894 """Dump the contents of a form as HTML."""
895 keys = form.keys()
896 keys.sort()
897 print
Guido van Rossum503e50b1996-05-28 22:57:20 +0000898 print "<H3>Form Contents:</H3>"
Guido van Rossum7aee3841996-03-07 18:00:44 +0000899 print "<DL>"
900 for key in keys:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000901 print "<DT>" + escape(key) + ":",
902 value = form[key]
903 print "<i>" + escape(`type(value)`) + "</i>"
904 print "<DD>" + escape(`value`)
Guido van Rossum7aee3841996-03-07 18:00:44 +0000905 print "</DL>"
906 print
907
908def print_directory():
909 """Dump the current directory as HTML."""
910 print
911 print "<H3>Current Working Directory:</H3>"
912 try:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000913 pwd = os.getcwd()
Guido van Rossum7aee3841996-03-07 18:00:44 +0000914 except os.error, msg:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000915 print "os.error:", escape(str(msg))
Guido van Rossum7aee3841996-03-07 18:00:44 +0000916 else:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000917 print escape(pwd)
Guido van Rossum7aee3841996-03-07 18:00:44 +0000918 print
Guido van Rossum9a22de11995-01-12 12:29:47 +0000919
Guido van Rossuma8738a51996-03-14 21:30:28 +0000920def print_arguments():
921 print
Guido van Rossum503e50b1996-05-28 22:57:20 +0000922 print "<H3>Command Line Arguments:</H3>"
Guido van Rossuma8738a51996-03-14 21:30:28 +0000923 print
924 print sys.argv
925 print
926
Guido van Rossum9a22de11995-01-12 12:29:47 +0000927def print_environ_usage():
Guido van Rossum7aee3841996-03-07 18:00:44 +0000928 """Dump a list of environment variables used by CGI as HTML."""
929 print """
Guido van Rossum72755611996-03-06 07:20:06 +0000930<H3>These environment variables could have been set:</H3>
931<UL>
Guido van Rossum9a22de11995-01-12 12:29:47 +0000932<LI>AUTH_TYPE
933<LI>CONTENT_LENGTH
934<LI>CONTENT_TYPE
935<LI>DATE_GMT
936<LI>DATE_LOCAL
937<LI>DOCUMENT_NAME
938<LI>DOCUMENT_ROOT
939<LI>DOCUMENT_URI
940<LI>GATEWAY_INTERFACE
941<LI>LAST_MODIFIED
942<LI>PATH
943<LI>PATH_INFO
944<LI>PATH_TRANSLATED
945<LI>QUERY_STRING
946<LI>REMOTE_ADDR
947<LI>REMOTE_HOST
948<LI>REMOTE_IDENT
949<LI>REMOTE_USER
950<LI>REQUEST_METHOD
951<LI>SCRIPT_NAME
952<LI>SERVER_NAME
953<LI>SERVER_PORT
954<LI>SERVER_PROTOCOL
955<LI>SERVER_ROOT
956<LI>SERVER_SOFTWARE
957</UL>
Guido van Rossum7aee3841996-03-07 18:00:44 +0000958In addition, HTTP headers sent by the server may be passed in the
959environment as well. Here are some common variable names:
960<UL>
961<LI>HTTP_ACCEPT
962<LI>HTTP_CONNECTION
963<LI>HTTP_HOST
964<LI>HTTP_PRAGMA
965<LI>HTTP_REFERER
966<LI>HTTP_USER_AGENT
967</UL>
Guido van Rossum9a22de11995-01-12 12:29:47 +0000968"""
969
Guido van Rossum9a22de11995-01-12 12:29:47 +0000970
Guido van Rossum72755611996-03-06 07:20:06 +0000971# Utilities
972# =========
Guido van Rossum9a22de11995-01-12 12:29:47 +0000973
Guido van Rossum64c66201997-07-19 20:11:53 +0000974def escape(s, quote=None):
Guido van Rossum7aee3841996-03-07 18:00:44 +0000975 """Replace special characters '&', '<' and '>' by SGML entities."""
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000976 s = string.replace(s, "&", "&amp;") # Must be done first!
Guido van Rossum00f9fea1997-12-24 21:18:41 +0000977 s = string.replace(s, "<", "&lt;")
978 s = string.replace(s, ">", "&gt;",)
Guido van Rossum64c66201997-07-19 20:11:53 +0000979 if quote:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000980 s = string.replace(s, '"', "&quot;")
Guido van Rossum7aee3841996-03-07 18:00:44 +0000981 return s
Guido van Rossum9a22de11995-01-12 12:29:47 +0000982
Guido van Rossum9a22de11995-01-12 12:29:47 +0000983
Guido van Rossum72755611996-03-06 07:20:06 +0000984# Invoke mainline
985# ===============
986
987# Call test() when this file is run as a script (not imported as a module)
988if __name__ == '__main__':
Guido van Rossum7aee3841996-03-07 18:00:44 +0000989 test()