blob: 345c8a199ed5d312bf3e75f041f36f9358b8dae1 [file] [log] [blame]
Guido van Rossum51914632000-10-03 13:51:09 +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
Barry Warsaw7fed2172000-11-06 18:46:09 +000022__version__ = "2.5"
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
Moshe Zadkaa1a4b592000-08-25 21:47:56 +000034import UserDict
Guido van Rossuma5e9fb61997-08-12 18:18:13 +000035from StringIO import StringIO
Guido van Rossum72755611996-03-06 07:20:06 +000036
Guido van Rossumc204c701996-09-05 19:07:11 +000037
38# Logging support
39# ===============
40
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000041logfile = "" # Filename to log to, if not empty
42logfp = None # File object to log to, if not None
Guido van Rossumc204c701996-09-05 19:07:11 +000043
44def initlog(*allargs):
45 """Write a log message, if there is a log file.
46
47 Even though this function is called initlog(), you should always
48 use log(); log is a variable that is set either to initlog
49 (initially), to dolog (once the log file has been opened), or to
50 nolog (when logging is disabled).
51
52 The first argument is a format string; the remaining arguments (if
53 any) are arguments to the % operator, so e.g.
54 log("%s: %s", "a", "b")
55 will write "a: b" to the log file, followed by a newline.
56
57 If the global logfp is not None, it should be a file object to
58 which log data is written.
59
60 If the global logfp is None, the global logfile may be a string
61 giving a filename to open, in append mode. This file should be
62 world writable!!! If the file can't be opened, logging is
63 silently disabled (since there is no safe place where we could
64 send an error message).
65
66 """
67 global logfp, log
68 if logfile and not logfp:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000069 try:
70 logfp = open(logfile, "a")
71 except IOError:
72 pass
Guido van Rossumc204c701996-09-05 19:07:11 +000073 if not logfp:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000074 log = nolog
Guido van Rossumc204c701996-09-05 19:07:11 +000075 else:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000076 log = dolog
Guido van Rossumc204c701996-09-05 19:07:11 +000077 apply(log, allargs)
78
79def dolog(fmt, *args):
80 """Write a log message to the log file. See initlog() for docs."""
81 logfp.write(fmt%args + "\n")
82
83def nolog(*allargs):
84 """Dummy function, assigned to log when logging is disabled."""
85 pass
86
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000087log = initlog # The current logging function
Guido van Rossumc204c701996-09-05 19:07:11 +000088
89
Guido van Rossum72755611996-03-06 07:20:06 +000090# Parsing functions
91# =================
92
Guido van Rossumad164711997-05-13 19:03:23 +000093# Maximum input we will accept when REQUEST_METHOD is POST
94# 0 ==> unlimited input
95maxlen = 0
96
Guido van Rossume08c04c1996-11-11 19:29:11 +000097def parse(fp=None, environ=os.environ, keep_blank_values=0, strict_parsing=0):
Guido van Rossum773ab271996-07-23 03:46:24 +000098 """Parse a query in the environment or from a file (default stdin)
99
100 Arguments, all optional:
101
102 fp : file pointer; default: sys.stdin
103
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000104 environ : environment dictionary; default: os.environ
Guido van Rossum773ab271996-07-23 03:46:24 +0000105
106 keep_blank_values: flag indicating whether blank values in
107 URL encoded forms should be treated as blank strings.
Thomas Wouters7e474022000-07-16 12:04:32 +0000108 A true value indicates that blanks should be retained as
Guido van Rossum773ab271996-07-23 03:46:24 +0000109 blank strings. The default false value indicates that
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000110 blank values are to be ignored and treated as if they were
111 not included.
Guido van Rossume08c04c1996-11-11 19:29:11 +0000112
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000113 strict_parsing: flag indicating what to do with parsing errors.
114 If false (the default), errors are silently ignored.
115 If true, errors raise a ValueError exception.
Guido van Rossum773ab271996-07-23 03:46:24 +0000116 """
Guido van Rossum7aee3841996-03-07 18:00:44 +0000117 if not fp:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000118 fp = sys.stdin
Guido van Rossum7aee3841996-03-07 18:00:44 +0000119 if not environ.has_key('REQUEST_METHOD'):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000120 environ['REQUEST_METHOD'] = 'GET' # For testing stand-alone
Guido van Rossum7aee3841996-03-07 18:00:44 +0000121 if environ['REQUEST_METHOD'] == 'POST':
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000122 ctype, pdict = parse_header(environ['CONTENT_TYPE'])
123 if ctype == 'multipart/form-data':
124 return parse_multipart(fp, pdict)
125 elif ctype == 'application/x-www-form-urlencoded':
126 clength = string.atoi(environ['CONTENT_LENGTH'])
127 if maxlen and clength > maxlen:
128 raise ValueError, 'Maximum content length exceeded'
129 qs = fp.read(clength)
130 else:
131 qs = '' # Unknown content-type
132 if environ.has_key('QUERY_STRING'):
133 if qs: qs = qs + '&'
134 qs = qs + environ['QUERY_STRING']
135 elif sys.argv[1:]:
136 if qs: qs = qs + '&'
137 qs = qs + sys.argv[1]
138 environ['QUERY_STRING'] = qs # XXX Shouldn't, really
Guido van Rossum7aee3841996-03-07 18:00:44 +0000139 elif environ.has_key('QUERY_STRING'):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000140 qs = environ['QUERY_STRING']
Guido van Rossum7aee3841996-03-07 18:00:44 +0000141 else:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000142 if sys.argv[1:]:
143 qs = sys.argv[1]
144 else:
145 qs = ""
146 environ['QUERY_STRING'] = qs # XXX Shouldn't, really
Guido van Rossume08c04c1996-11-11 19:29:11 +0000147 return parse_qs(qs, keep_blank_values, strict_parsing)
Guido van Rossume7808771995-08-07 20:12:09 +0000148
149
Guido van Rossume08c04c1996-11-11 19:29:11 +0000150def parse_qs(qs, keep_blank_values=0, strict_parsing=0):
151 """Parse a query given as a string argument.
Guido van Rossum773ab271996-07-23 03:46:24 +0000152
153 Arguments:
154
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000155 qs: URL-encoded query string to be parsed
Guido van Rossum773ab271996-07-23 03:46:24 +0000156
157 keep_blank_values: flag indicating whether blank values in
158 URL encoded queries should be treated as blank strings.
Thomas Wouters7e474022000-07-16 12:04:32 +0000159 A true value indicates that blanks should be retained as
Guido van Rossum773ab271996-07-23 03:46:24 +0000160 blank strings. The default false value indicates that
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000161 blank values are to be ignored and treated as if they were
162 not included.
Guido van Rossume08c04c1996-11-11 19:29:11 +0000163
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000164 strict_parsing: flag indicating what to do with parsing errors.
165 If false (the default), errors are silently ignored.
166 If true, errors raise a ValueError exception.
Guido van Rossum773ab271996-07-23 03:46:24 +0000167 """
Guido van Rossum7aee3841996-03-07 18:00:44 +0000168 dict = {}
Guido van Rossum1946f0d1999-06-04 17:54:39 +0000169 for name, value in parse_qsl(qs, keep_blank_values, strict_parsing):
Moshe Zadkaa1a4b592000-08-25 21:47:56 +0000170 if dict.has_key(name):
171 dict[name].append(value)
172 else:
173 dict[name] = [value]
Guido van Rossum1946f0d1999-06-04 17:54:39 +0000174 return dict
175
176def parse_qsl(qs, keep_blank_values=0, strict_parsing=0):
177 """Parse a query given as a string argument.
178
Jeremy Hyltonafde7e22000-09-15 20:06:57 +0000179 Arguments:
Guido van Rossum1946f0d1999-06-04 17:54:39 +0000180
Jeremy Hyltonafde7e22000-09-15 20:06:57 +0000181 qs: URL-encoded query string to be parsed
Guido van Rossum1946f0d1999-06-04 17:54:39 +0000182
Jeremy Hyltonafde7e22000-09-15 20:06:57 +0000183 keep_blank_values: flag indicating whether blank values in
184 URL encoded queries should be treated as blank strings. A
185 true value indicates that blanks should be retained as blank
186 strings. The default false value indicates that blank values
187 are to be ignored and treated as if they were not included.
Guido van Rossum1946f0d1999-06-04 17:54:39 +0000188
Jeremy Hyltonafde7e22000-09-15 20:06:57 +0000189 strict_parsing: flag indicating what to do with parsing errors. If
190 false (the default), errors are silently ignored. If true,
191 errors raise a ValueError exception.
Guido van Rossum1946f0d1999-06-04 17:54:39 +0000192
Jeremy Hyltonafde7e22000-09-15 20:06:57 +0000193 Returns a list, as G-d intended.
Guido van Rossum1946f0d1999-06-04 17:54:39 +0000194 """
Jeremy Hyltonafde7e22000-09-15 20:06:57 +0000195 pairs = [s2 for s1 in qs.split('&') for s2 in s1.split(';')]
196 r = []
197 for name_value in pairs:
198 nv = name_value.split('=', 1)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000199 if len(nv) != 2:
200 if strict_parsing:
201 raise ValueError, "bad query field: %s" % `name_value`
202 continue
Moshe Zadkaa1a4b592000-08-25 21:47:56 +0000203 if len(nv[1]) or keep_blank_values:
204 name = urllib.unquote(string.replace(nv[0], '+', ' '))
205 value = urllib.unquote(string.replace(nv[1], '+', ' '))
206 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
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000500 if ctype == 'application/x-www-form-urlencoded':
501 self.read_urlencoded()
502 elif ctype[:10] == 'multipart/':
Guido van Rossumf5745001998-10-20 14:43:02 +0000503 self.read_multi(environ, keep_blank_values, strict_parsing)
Barry Warsaw302331a1999-01-08 17:42:03 +0000504 else:
Guido van Rossum60a3bd81999-06-11 18:26:09 +0000505 self.read_single()
Guido van Rossum7aee3841996-03-07 18:00:44 +0000506
507 def __repr__(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000508 """Return a printable representation."""
509 return "FieldStorage(%s, %s, %s)" % (
510 `self.name`, `self.filename`, `self.value`)
Guido van Rossum7aee3841996-03-07 18:00:44 +0000511
512 def __getattr__(self, name):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000513 if name != 'value':
514 raise AttributeError, name
515 if self.file:
516 self.file.seek(0)
517 value = self.file.read()
518 self.file.seek(0)
519 elif self.list is not None:
520 value = self.list
521 else:
522 value = None
523 return value
Guido van Rossum7aee3841996-03-07 18:00:44 +0000524
525 def __getitem__(self, key):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000526 """Dictionary style indexing."""
527 if self.list is None:
528 raise TypeError, "not indexable"
529 found = []
530 for item in self.list:
531 if item.name == key: found.append(item)
532 if not found:
533 raise KeyError, key
534 if len(found) == 1:
535 return found[0]
536 else:
537 return found
Guido van Rossum7aee3841996-03-07 18:00:44 +0000538
Moshe Zadkaa1a4b592000-08-25 21:47:56 +0000539 def getvalue(self, key, default=None):
540 """Dictionary style get() method, including 'value' lookup."""
541 if self.has_key(key):
542 value = self[key]
543 if type(value) is type([]):
544 return map(lambda v: v.value, value)
545 else:
546 return value.value
547 else:
548 return default
549
Guido van Rossum7aee3841996-03-07 18:00:44 +0000550 def keys(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000551 """Dictionary style keys() method."""
552 if self.list is None:
553 raise TypeError, "not indexable"
554 keys = []
555 for item in self.list:
556 if item.name not in keys: keys.append(item.name)
557 return keys
Guido van Rossum7aee3841996-03-07 18:00:44 +0000558
Guido van Rossum0147db01996-03-09 03:16:04 +0000559 def has_key(self, key):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000560 """Dictionary style has_key() method."""
561 if self.list is None:
562 raise TypeError, "not indexable"
563 for item in self.list:
564 if item.name == key: return 1
565 return 0
Guido van Rossum0147db01996-03-09 03:16:04 +0000566
Guido van Rossum88b85d41997-01-11 19:21:33 +0000567 def __len__(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000568 """Dictionary style len(x) support."""
569 return len(self.keys())
Guido van Rossum88b85d41997-01-11 19:21:33 +0000570
Guido van Rossum7aee3841996-03-07 18:00:44 +0000571 def read_urlencoded(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000572 """Internal: read data in query string format."""
573 qs = self.fp.read(self.length)
Guido van Rossum1946f0d1999-06-04 17:54:39 +0000574 self.list = list = []
575 for key, value in parse_qsl(qs, self.keep_blank_values,
576 self.strict_parsing):
577 list.append(MiniFieldStorage(key, value))
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000578 self.skip_lines()
Guido van Rossum7aee3841996-03-07 18:00:44 +0000579
Guido van Rossum030d2ec1998-12-09 22:16:46 +0000580 FieldStorageClass = None
581
Guido van Rossumf5745001998-10-20 14:43:02 +0000582 def read_multi(self, environ, keep_blank_values, strict_parsing):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000583 """Internal: read a part that is itself multipart."""
584 self.list = []
Guido van Rossum030d2ec1998-12-09 22:16:46 +0000585 klass = self.FieldStorageClass or self.__class__
586 part = klass(self.fp, {}, self.innerboundary,
587 environ, keep_blank_values, strict_parsing)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000588 # Throw first part away
589 while not part.done:
590 headers = rfc822.Message(self.fp)
Guido van Rossum030d2ec1998-12-09 22:16:46 +0000591 part = klass(self.fp, headers, self.innerboundary,
592 environ, keep_blank_values, strict_parsing)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000593 self.list.append(part)
594 self.skip_lines()
Guido van Rossum7aee3841996-03-07 18:00:44 +0000595
596 def read_single(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000597 """Internal: read an atomic part."""
598 if self.length >= 0:
599 self.read_binary()
600 self.skip_lines()
601 else:
602 self.read_lines()
603 self.file.seek(0)
Guido van Rossum7aee3841996-03-07 18:00:44 +0000604
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000605 bufsize = 8*1024 # I/O buffering size for copy to file
Guido van Rossum7aee3841996-03-07 18:00:44 +0000606
607 def read_binary(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000608 """Internal: read binary data."""
609 self.file = self.make_file('b')
610 todo = self.length
611 if todo >= 0:
612 while todo > 0:
613 data = self.fp.read(min(todo, self.bufsize))
614 if not data:
615 self.done = -1
616 break
617 self.file.write(data)
618 todo = todo - len(data)
Guido van Rossum7aee3841996-03-07 18:00:44 +0000619
620 def read_lines(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000621 """Internal: read lines until EOF or outerboundary."""
622 self.file = self.make_file('')
623 if self.outerboundary:
624 self.read_lines_to_outerboundary()
625 else:
626 self.read_lines_to_eof()
Guido van Rossum7aee3841996-03-07 18:00:44 +0000627
628 def read_lines_to_eof(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000629 """Internal: read lines until EOF."""
630 while 1:
631 line = self.fp.readline()
632 if not line:
633 self.done = -1
634 break
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000635 self.file.write(line)
Guido van Rossum7aee3841996-03-07 18:00:44 +0000636
637 def read_lines_to_outerboundary(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000638 """Internal: read lines until outerboundary."""
639 next = "--" + self.outerboundary
640 last = next + "--"
641 delim = ""
642 while 1:
643 line = self.fp.readline()
644 if not line:
645 self.done = -1
646 break
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000647 if line[:2] == "--":
648 strippedline = string.strip(line)
649 if strippedline == next:
650 break
651 if strippedline == last:
652 self.done = 1
653 break
654 odelim = delim
655 if line[-2:] == "\r\n":
656 delim = "\r\n"
657 line = line[:-2]
658 elif line[-1] == "\n":
659 delim = "\n"
660 line = line[:-1]
661 else:
662 delim = ""
663 self.file.write(odelim + line)
Guido van Rossum7aee3841996-03-07 18:00:44 +0000664
665 def skip_lines(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000666 """Internal: skip lines until outer boundary if defined."""
667 if not self.outerboundary or self.done:
668 return
669 next = "--" + self.outerboundary
670 last = next + "--"
671 while 1:
672 line = self.fp.readline()
673 if not line:
674 self.done = -1
675 break
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000676 if line[:2] == "--":
677 strippedline = string.strip(line)
678 if strippedline == next:
679 break
680 if strippedline == last:
681 self.done = 1
682 break
Guido van Rossum7aee3841996-03-07 18:00:44 +0000683
Guido van Rossuma5e9fb61997-08-12 18:18:13 +0000684 def make_file(self, binary=None):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000685 """Overridable: return a readable & writable file.
Guido van Rossum7aee3841996-03-07 18:00:44 +0000686
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000687 The file will be used as follows:
688 - data is written to it
689 - seek(0)
690 - data is read from it
Guido van Rossum7aee3841996-03-07 18:00:44 +0000691
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000692 The 'binary' argument is unused -- the file is always opened
693 in binary mode.
Guido van Rossum7aee3841996-03-07 18:00:44 +0000694
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000695 This version opens a temporary file for reading and writing,
696 and immediately deletes (unlinks) it. The trick (on Unix!) is
697 that the file can still be used, but it can't be opened by
698 another process, and it will automatically be deleted when it
699 is closed or when the current process terminates.
Guido van Rossum4032c2c1996-03-09 04:04:35 +0000700
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000701 If you want a more permanent file, you derive a class which
702 overrides this method. If you want a visible temporary file
703 that is nevertheless automatically deleted when the script
704 terminates, try defining a __del__ method in a derived class
705 which unlinks the temporary files you have created.
Guido van Rossum7aee3841996-03-07 18:00:44 +0000706
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000707 """
708 import tempfile
709 return tempfile.TemporaryFile("w+b")
710
Guido van Rossum243ddcd1996-03-07 06:33:07 +0000711
712
Guido van Rossum4032c2c1996-03-09 04:04:35 +0000713# Backwards Compatibility Classes
714# ===============================
Guido van Rossum9a22de11995-01-12 12:29:47 +0000715
Moshe Zadkaa1a4b592000-08-25 21:47:56 +0000716class FormContentDict(UserDict.UserDict):
Guido van Rossuma3c6a8a2000-09-19 04:11:46 +0000717 """Form content as dictionary with a list of values per field.
Guido van Rossum72755611996-03-06 07:20:06 +0000718
Guido van Rossum7aee3841996-03-07 18:00:44 +0000719 form = FormContentDict()
720
721 form[key] -> [value, value, ...]
722 form.has_key(key) -> Boolean
723 form.keys() -> [key, key, ...]
724 form.values() -> [[val, val, ...], [val, val, ...], ...]
725 form.items() -> [(key, [val, val, ...]), (key, [val, val, ...]), ...]
726 form.dict == {key: [val, val, ...], ...}
727
728 """
Guido van Rossum773ab271996-07-23 03:46:24 +0000729 def __init__(self, environ=os.environ):
Moshe Zadkaa1a4b592000-08-25 21:47:56 +0000730 self.dict = self.data = parse(environ=environ)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000731 self.query_string = environ['QUERY_STRING']
Guido van Rossum9a22de11995-01-12 12:29:47 +0000732
733
Guido van Rossum9a22de11995-01-12 12:29:47 +0000734class SvFormContentDict(FormContentDict):
Guido van Rossuma3c6a8a2000-09-19 04:11:46 +0000735 """Form content as dictionary expecting a single value per field.
Guido van Rossum7aee3841996-03-07 18:00:44 +0000736
Guido van Rossuma3c6a8a2000-09-19 04:11:46 +0000737 If you only expect a single value for each field, then form[key]
Guido van Rossum7aee3841996-03-07 18:00:44 +0000738 will return that single value. It will raise an IndexError if
Guido van Rossuma3c6a8a2000-09-19 04:11:46 +0000739 that expectation is not true. If you expect a field to have
Guido van Rossum7aee3841996-03-07 18:00:44 +0000740 possible multiple values, than you can use form.getlist(key) to
741 get all of the values. values() and items() are a compromise:
742 they return single strings where there is a single value, and
743 lists of strings otherwise.
744
745 """
746 def __getitem__(self, key):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000747 if len(self.dict[key]) > 1:
748 raise IndexError, 'expecting a single value'
749 return self.dict[key][0]
Guido van Rossum7aee3841996-03-07 18:00:44 +0000750 def getlist(self, key):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000751 return self.dict[key]
Guido van Rossum7aee3841996-03-07 18:00:44 +0000752 def values(self):
Guido van Rossuma3c6a8a2000-09-19 04:11:46 +0000753 result = []
754 for value in self.dict.values():
755 if len(value) == 1:
756 result.append(value[0])
757 else: result.append(value)
758 return result
Guido van Rossum7aee3841996-03-07 18:00:44 +0000759 def items(self):
Guido van Rossuma3c6a8a2000-09-19 04:11:46 +0000760 result = []
761 for key, value in self.dict.items():
762 if len(value) == 1:
763 result.append((key, value[0]))
764 else: result.append((key, value))
765 return result
Guido van Rossum9a22de11995-01-12 12:29:47 +0000766
767
Guido van Rossum9a22de11995-01-12 12:29:47 +0000768class InterpFormContentDict(SvFormContentDict):
Guido van Rossum7aee3841996-03-07 18:00:44 +0000769 """This class is present for backwards compatibility only."""
Guido van Rossuma3c6a8a2000-09-19 04:11:46 +0000770 def __getitem__(self, key):
771 v = SvFormContentDict.__getitem__(self, key)
772 if v[0] in string.digits + '+-.':
773 try: return string.atoi(v)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000774 except ValueError:
Guido van Rossuma3c6a8a2000-09-19 04:11:46 +0000775 try: return string.atof(v)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000776 except ValueError: pass
777 return string.strip(v)
Guido van Rossuma3c6a8a2000-09-19 04:11:46 +0000778 def values(self):
779 result = []
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000780 for key in self.keys():
781 try:
Guido van Rossuma3c6a8a2000-09-19 04:11:46 +0000782 result.append(self[key])
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000783 except IndexError:
Guido van Rossuma3c6a8a2000-09-19 04:11:46 +0000784 result.append(self.dict[key])
785 return result
786 def items(self):
787 result = []
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000788 for key in self.keys():
789 try:
Guido van Rossuma3c6a8a2000-09-19 04:11:46 +0000790 result.append((key, self[key]))
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000791 except IndexError:
Guido van Rossuma3c6a8a2000-09-19 04:11:46 +0000792 result.append((key, self.dict[key]))
793 return result
Guido van Rossum9a22de11995-01-12 12:29:47 +0000794
795
Guido van Rossum9a22de11995-01-12 12:29:47 +0000796class FormContent(FormContentDict):
Guido van Rossum7aee3841996-03-07 18:00:44 +0000797 """This class is present for backwards compatibility only."""
Guido van Rossum0147db01996-03-09 03:16:04 +0000798 def values(self, key):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000799 if self.dict.has_key(key) :return self.dict[key]
800 else: return None
Guido van Rossum0147db01996-03-09 03:16:04 +0000801 def indexed_value(self, key, location):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000802 if self.dict.has_key(key):
Guido van Rossuma3c6a8a2000-09-19 04:11:46 +0000803 if len(self.dict[key]) > location:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000804 return self.dict[key][location]
805 else: return None
806 else: return None
Guido van Rossum0147db01996-03-09 03:16:04 +0000807 def value(self, key):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000808 if self.dict.has_key(key): return self.dict[key][0]
809 else: return None
Guido van Rossum0147db01996-03-09 03:16:04 +0000810 def length(self, key):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000811 return len(self.dict[key])
Guido van Rossum0147db01996-03-09 03:16:04 +0000812 def stripped(self, key):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000813 if self.dict.has_key(key): return string.strip(self.dict[key][0])
814 else: return None
Guido van Rossum7aee3841996-03-07 18:00:44 +0000815 def pars(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000816 return self.dict
Guido van Rossum9a22de11995-01-12 12:29:47 +0000817
818
Guido van Rossum72755611996-03-06 07:20:06 +0000819# Test/debug code
820# ===============
Guido van Rossum9a22de11995-01-12 12:29:47 +0000821
Guido van Rossum773ab271996-07-23 03:46:24 +0000822def test(environ=os.environ):
Guido van Rossum7aee3841996-03-07 18:00:44 +0000823 """Robust test CGI script, usable as main program.
Guido van Rossum9a22de11995-01-12 12:29:47 +0000824
Guido van Rossum7aee3841996-03-07 18:00:44 +0000825 Write minimal HTTP headers and dump all information provided to
826 the script in HTML form.
827
828 """
829 import traceback
830 print "Content-type: text/html"
831 print
832 sys.stderr = sys.stdout
833 try:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000834 form = FieldStorage() # Replace with other classes to test those
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000835 print_directory()
836 print_arguments()
Guido van Rossuma3c6a8a2000-09-19 04:11:46 +0000837 print_form(form)
838 print_environ(environ)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000839 print_environ_usage()
840 def f():
841 exec "testing print_exception() -- <I>italics?</I>"
842 def g(f=f):
843 f()
844 print "<H3>What follows is a test, not an actual exception:</H3>"
845 g()
Guido van Rossum7aee3841996-03-07 18:00:44 +0000846 except:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000847 print_exception()
Guido van Rossumf85de8a1996-08-20 20:22:39 +0000848
Guido van Rossum57d51f22000-09-16 21:16:01 +0000849 print "<H1>Second try with a small maxlen...</H1>"
850
Guido van Rossumad164711997-05-13 19:03:23 +0000851 global maxlen
852 maxlen = 50
853 try:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000854 form = FieldStorage() # Replace with other classes to test those
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000855 print_directory()
856 print_arguments()
Guido van Rossuma3c6a8a2000-09-19 04:11:46 +0000857 print_form(form)
858 print_environ(environ)
Guido van Rossumad164711997-05-13 19:03:23 +0000859 except:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000860 print_exception()
Guido van Rossumad164711997-05-13 19:03:23 +0000861
Guido van Rossumf85de8a1996-08-20 20:22:39 +0000862def print_exception(type=None, value=None, tb=None, limit=None):
863 if type is None:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000864 type, value, tb = sys.exc_info()
Guido van Rossumf85de8a1996-08-20 20:22:39 +0000865 import traceback
866 print
Guido van Rossum7dd06962000-12-27 19:12:58 +0000867 print "<H3>Traceback (most recent call last):</H3>"
Guido van Rossumf85de8a1996-08-20 20:22:39 +0000868 list = traceback.format_tb(tb, limit) + \
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000869 traceback.format_exception_only(type, value)
Guido van Rossumf85de8a1996-08-20 20:22:39 +0000870 print "<PRE>%s<B>%s</B></PRE>" % (
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000871 escape(string.join(list[:-1], "")),
872 escape(list[-1]),
873 )
Guido van Rossumf15d1591997-09-29 23:22:12 +0000874 del tb
Guido van Rossum9a22de11995-01-12 12:29:47 +0000875
Guido van Rossum773ab271996-07-23 03:46:24 +0000876def print_environ(environ=os.environ):
Guido van Rossum7aee3841996-03-07 18:00:44 +0000877 """Dump the shell environment as HTML."""
878 keys = environ.keys()
879 keys.sort()
880 print
Guido van Rossum503e50b1996-05-28 22:57:20 +0000881 print "<H3>Shell Environment:</H3>"
Guido van Rossum7aee3841996-03-07 18:00:44 +0000882 print "<DL>"
883 for key in keys:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000884 print "<DT>", escape(key), "<DD>", escape(environ[key])
Guido van Rossum7aee3841996-03-07 18:00:44 +0000885 print "</DL>"
886 print
Guido van Rossum72755611996-03-06 07:20:06 +0000887
888def print_form(form):
Guido van Rossum7aee3841996-03-07 18:00:44 +0000889 """Dump the contents of a form as HTML."""
890 keys = form.keys()
891 keys.sort()
892 print
Guido van Rossum503e50b1996-05-28 22:57:20 +0000893 print "<H3>Form Contents:</H3>"
Guido van Rossum57d51f22000-09-16 21:16:01 +0000894 if not keys:
895 print "<P>No form fields."
Guido van Rossum7aee3841996-03-07 18:00:44 +0000896 print "<DL>"
897 for key in keys:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000898 print "<DT>" + escape(key) + ":",
899 value = form[key]
900 print "<i>" + escape(`type(value)`) + "</i>"
901 print "<DD>" + escape(`value`)
Guido van Rossum7aee3841996-03-07 18:00:44 +0000902 print "</DL>"
903 print
904
905def print_directory():
906 """Dump the current directory as HTML."""
907 print
908 print "<H3>Current Working Directory:</H3>"
909 try:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000910 pwd = os.getcwd()
Guido van Rossum7aee3841996-03-07 18:00:44 +0000911 except os.error, msg:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000912 print "os.error:", escape(str(msg))
Guido van Rossum7aee3841996-03-07 18:00:44 +0000913 else:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000914 print escape(pwd)
Guido van Rossum7aee3841996-03-07 18:00:44 +0000915 print
Guido van Rossum9a22de11995-01-12 12:29:47 +0000916
Guido van Rossuma8738a51996-03-14 21:30:28 +0000917def print_arguments():
918 print
Guido van Rossum503e50b1996-05-28 22:57:20 +0000919 print "<H3>Command Line Arguments:</H3>"
Guido van Rossuma8738a51996-03-14 21:30:28 +0000920 print
921 print sys.argv
922 print
923
Guido van Rossum9a22de11995-01-12 12:29:47 +0000924def print_environ_usage():
Guido van Rossum7aee3841996-03-07 18:00:44 +0000925 """Dump a list of environment variables used by CGI as HTML."""
926 print """
Guido van Rossum72755611996-03-06 07:20:06 +0000927<H3>These environment variables could have been set:</H3>
928<UL>
Guido van Rossum9a22de11995-01-12 12:29:47 +0000929<LI>AUTH_TYPE
930<LI>CONTENT_LENGTH
931<LI>CONTENT_TYPE
932<LI>DATE_GMT
933<LI>DATE_LOCAL
934<LI>DOCUMENT_NAME
935<LI>DOCUMENT_ROOT
936<LI>DOCUMENT_URI
937<LI>GATEWAY_INTERFACE
938<LI>LAST_MODIFIED
939<LI>PATH
940<LI>PATH_INFO
941<LI>PATH_TRANSLATED
942<LI>QUERY_STRING
943<LI>REMOTE_ADDR
944<LI>REMOTE_HOST
945<LI>REMOTE_IDENT
946<LI>REMOTE_USER
947<LI>REQUEST_METHOD
948<LI>SCRIPT_NAME
949<LI>SERVER_NAME
950<LI>SERVER_PORT
951<LI>SERVER_PROTOCOL
952<LI>SERVER_ROOT
953<LI>SERVER_SOFTWARE
954</UL>
Guido van Rossum7aee3841996-03-07 18:00:44 +0000955In addition, HTTP headers sent by the server may be passed in the
956environment as well. Here are some common variable names:
957<UL>
958<LI>HTTP_ACCEPT
959<LI>HTTP_CONNECTION
960<LI>HTTP_HOST
961<LI>HTTP_PRAGMA
962<LI>HTTP_REFERER
963<LI>HTTP_USER_AGENT
964</UL>
Guido van Rossum9a22de11995-01-12 12:29:47 +0000965"""
966
Guido van Rossum9a22de11995-01-12 12:29:47 +0000967
Guido van Rossum72755611996-03-06 07:20:06 +0000968# Utilities
969# =========
Guido van Rossum9a22de11995-01-12 12:29:47 +0000970
Guido van Rossum64c66201997-07-19 20:11:53 +0000971def escape(s, quote=None):
Guido van Rossum7aee3841996-03-07 18:00:44 +0000972 """Replace special characters '&', '<' and '>' by SGML entities."""
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000973 s = string.replace(s, "&", "&amp;") # Must be done first!
Guido van Rossum00f9fea1997-12-24 21:18:41 +0000974 s = string.replace(s, "<", "&lt;")
975 s = string.replace(s, ">", "&gt;",)
Guido van Rossum64c66201997-07-19 20:11:53 +0000976 if quote:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000977 s = string.replace(s, '"', "&quot;")
Guido van Rossum7aee3841996-03-07 18:00:44 +0000978 return s
Guido van Rossum9a22de11995-01-12 12:29:47 +0000979
Guido van Rossum9a22de11995-01-12 12:29:47 +0000980
Guido van Rossum72755611996-03-06 07:20:06 +0000981# Invoke mainline
982# ===============
983
984# Call test() when this file is run as a script (not imported as a module)
985if __name__ == '__main__':
Guido van Rossum7aee3841996-03-07 18:00:44 +0000986 test()