blob: f3d27255cb0fdca8a545262ae4c871548216b9f8 [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# -------
Tim Peters88869f92001-01-14 23:36:06 +000014#
Guido van Rossum98d9fd32000-02-28 15:12:25 +000015# 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.
Tim Peters88869f92001-01-14 23:36:06 +000020#
Guido van Rossum98d9fd32000-02-28 15:12:25 +000021
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
Guido van Rossum72755611996-03-06 07:20:06 +000028import sys
29import os
Guido van Rossuma5e9fb61997-08-12 18:18:13 +000030import urllib
Guido van Rossuma5e9fb61997-08-12 18:18:13 +000031import mimetools
32import rfc822
Moshe Zadkaa1a4b592000-08-25 21:47:56 +000033import UserDict
Guido van Rossuma5e9fb61997-08-12 18:18:13 +000034from StringIO import StringIO
Guido van Rossum72755611996-03-06 07:20:06 +000035
Skip Montanaroe99d5ea2001-01-20 19:54:20 +000036__all__ = ["MiniFieldStorage","FieldStorage","FormContentDict",
37 "SvFormContentDict","InterpFormContentDict","FormContent"]
Guido van Rossumc204c701996-09-05 19:07:11 +000038
39# Logging support
40# ===============
41
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000042logfile = "" # Filename to log to, if not empty
43logfp = None # File object to log to, if not None
Guido van Rossumc204c701996-09-05 19:07:11 +000044
45def initlog(*allargs):
46 """Write a log message, if there is a log file.
47
48 Even though this function is called initlog(), you should always
49 use log(); log is a variable that is set either to initlog
50 (initially), to dolog (once the log file has been opened), or to
51 nolog (when logging is disabled).
52
53 The first argument is a format string; the remaining arguments (if
54 any) are arguments to the % operator, so e.g.
55 log("%s: %s", "a", "b")
56 will write "a: b" to the log file, followed by a newline.
57
58 If the global logfp is not None, it should be a file object to
59 which log data is written.
60
61 If the global logfp is None, the global logfile may be a string
62 giving a filename to open, in append mode. This file should be
63 world writable!!! If the file can't be opened, logging is
64 silently disabled (since there is no safe place where we could
65 send an error message).
66
67 """
68 global logfp, log
69 if logfile and not logfp:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000070 try:
71 logfp = open(logfile, "a")
72 except IOError:
73 pass
Guido van Rossumc204c701996-09-05 19:07:11 +000074 if not logfp:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000075 log = nolog
Guido van Rossumc204c701996-09-05 19:07:11 +000076 else:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000077 log = dolog
Guido van Rossumc204c701996-09-05 19:07:11 +000078 apply(log, allargs)
79
80def dolog(fmt, *args):
81 """Write a log message to the log file. See initlog() for docs."""
82 logfp.write(fmt%args + "\n")
83
84def nolog(*allargs):
85 """Dummy function, assigned to log when logging is disabled."""
86 pass
87
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000088log = initlog # The current logging function
Guido van Rossumc204c701996-09-05 19:07:11 +000089
90
Guido van Rossum72755611996-03-06 07:20:06 +000091# Parsing functions
92# =================
93
Guido van Rossumad164711997-05-13 19:03:23 +000094# Maximum input we will accept when REQUEST_METHOD is POST
95# 0 ==> unlimited input
96maxlen = 0
97
Guido van Rossume08c04c1996-11-11 19:29:11 +000098def parse(fp=None, environ=os.environ, keep_blank_values=0, strict_parsing=0):
Guido van Rossum773ab271996-07-23 03:46:24 +000099 """Parse a query in the environment or from a file (default stdin)
100
101 Arguments, all optional:
102
103 fp : file pointer; default: sys.stdin
104
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000105 environ : environment dictionary; default: os.environ
Guido van Rossum773ab271996-07-23 03:46:24 +0000106
107 keep_blank_values: flag indicating whether blank values in
Tim Peters88869f92001-01-14 23:36:06 +0000108 URL encoded forms should be treated as blank strings.
109 A true value indicates that blanks should be retained as
Guido van Rossum773ab271996-07-23 03:46:24 +0000110 blank strings. The default false value indicates that
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000111 blank values are to be ignored and treated as if they were
112 not included.
Guido van Rossume08c04c1996-11-11 19:29:11 +0000113
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000114 strict_parsing: flag indicating what to do with parsing errors.
115 If false (the default), errors are silently ignored.
116 If true, errors raise a ValueError exception.
Guido van Rossum773ab271996-07-23 03:46:24 +0000117 """
Guido van Rossum7aee3841996-03-07 18:00:44 +0000118 if not fp:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000119 fp = sys.stdin
Guido van Rossum7aee3841996-03-07 18:00:44 +0000120 if not environ.has_key('REQUEST_METHOD'):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000121 environ['REQUEST_METHOD'] = 'GET' # For testing stand-alone
Guido van Rossum7aee3841996-03-07 18:00:44 +0000122 if environ['REQUEST_METHOD'] == 'POST':
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000123 ctype, pdict = parse_header(environ['CONTENT_TYPE'])
124 if ctype == 'multipart/form-data':
125 return parse_multipart(fp, pdict)
126 elif ctype == 'application/x-www-form-urlencoded':
Eric S. Raymond7e9b4f52001-02-09 09:59:10 +0000127 clength = int(environ['CONTENT_LENGTH'])
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000128 if maxlen and clength > maxlen:
129 raise ValueError, 'Maximum content length exceeded'
130 qs = fp.read(clength)
131 else:
132 qs = '' # Unknown content-type
Tim Peters88869f92001-01-14 23:36:06 +0000133 if environ.has_key('QUERY_STRING'):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000134 if qs: qs = qs + '&'
135 qs = qs + environ['QUERY_STRING']
Tim Peters88869f92001-01-14 23:36:06 +0000136 elif sys.argv[1:]:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000137 if qs: qs = qs + '&'
138 qs = qs + sys.argv[1]
139 environ['QUERY_STRING'] = qs # XXX Shouldn't, really
Guido van Rossum7aee3841996-03-07 18:00:44 +0000140 elif environ.has_key('QUERY_STRING'):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000141 qs = environ['QUERY_STRING']
Guido van Rossum7aee3841996-03-07 18:00:44 +0000142 else:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000143 if sys.argv[1:]:
144 qs = sys.argv[1]
145 else:
146 qs = ""
147 environ['QUERY_STRING'] = qs # XXX Shouldn't, really
Guido van Rossume08c04c1996-11-11 19:29:11 +0000148 return parse_qs(qs, keep_blank_values, strict_parsing)
Guido van Rossume7808771995-08-07 20:12:09 +0000149
150
Guido van Rossume08c04c1996-11-11 19:29:11 +0000151def parse_qs(qs, keep_blank_values=0, strict_parsing=0):
152 """Parse a query given as a string argument.
Guido van Rossum773ab271996-07-23 03:46:24 +0000153
154 Arguments:
155
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000156 qs: URL-encoded query string to be parsed
Guido van Rossum773ab271996-07-23 03:46:24 +0000157
158 keep_blank_values: flag indicating whether blank values in
Tim Peters88869f92001-01-14 23:36:06 +0000159 URL encoded queries should be treated as blank strings.
160 A true value indicates that blanks should be retained as
Guido van Rossum773ab271996-07-23 03:46:24 +0000161 blank strings. The default false value indicates that
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000162 blank values are to be ignored and treated as if they were
163 not included.
Guido van Rossume08c04c1996-11-11 19:29:11 +0000164
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000165 strict_parsing: flag indicating what to do with parsing errors.
166 If false (the default), errors are silently ignored.
167 If true, errors raise a ValueError exception.
Guido van Rossum773ab271996-07-23 03:46:24 +0000168 """
Guido van Rossum7aee3841996-03-07 18:00:44 +0000169 dict = {}
Guido van Rossum1946f0d1999-06-04 17:54:39 +0000170 for name, value in parse_qsl(qs, keep_blank_values, strict_parsing):
Moshe Zadkaa1a4b592000-08-25 21:47:56 +0000171 if dict.has_key(name):
172 dict[name].append(value)
173 else:
174 dict[name] = [value]
Guido van Rossum1946f0d1999-06-04 17:54:39 +0000175 return dict
176
177def parse_qsl(qs, keep_blank_values=0, strict_parsing=0):
178 """Parse a query given as a string argument.
179
Jeremy Hyltonafde7e22000-09-15 20:06:57 +0000180 Arguments:
Guido van Rossum1946f0d1999-06-04 17:54:39 +0000181
Jeremy Hyltonafde7e22000-09-15 20:06:57 +0000182 qs: URL-encoded query string to be parsed
Guido van Rossum1946f0d1999-06-04 17:54:39 +0000183
Jeremy Hyltonafde7e22000-09-15 20:06:57 +0000184 keep_blank_values: flag indicating whether blank values in
185 URL encoded queries should be treated as blank strings. A
186 true value indicates that blanks should be retained as blank
187 strings. The default false value indicates that blank values
188 are to be ignored and treated as if they were not included.
Guido van Rossum1946f0d1999-06-04 17:54:39 +0000189
Jeremy Hyltonafde7e22000-09-15 20:06:57 +0000190 strict_parsing: flag indicating what to do with parsing errors. If
191 false (the default), errors are silently ignored. If true,
Tim Peters88869f92001-01-14 23:36:06 +0000192 errors raise a ValueError exception.
Guido van Rossum1946f0d1999-06-04 17:54:39 +0000193
Jeremy Hyltonafde7e22000-09-15 20:06:57 +0000194 Returns a list, as G-d intended.
Guido van Rossum1946f0d1999-06-04 17:54:39 +0000195 """
Jeremy Hyltonafde7e22000-09-15 20:06:57 +0000196 pairs = [s2 for s1 in qs.split('&') for s2 in s1.split(';')]
197 r = []
198 for name_value in pairs:
199 nv = name_value.split('=', 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
Moshe Zadkaa1a4b592000-08-25 21:47:56 +0000204 if len(nv[1]) or keep_blank_values:
Eric S. Raymond7e9b4f52001-02-09 09:59:10 +0000205 name = urllib.unquote(nv[0].replace('+', ' '))
206 value = urllib.unquote(nv[1].replace('+', ' '))
Moshe Zadkaa1a4b592000-08-25 21:47:56 +0000207 r.append((name, value))
Guido van Rossum1946f0d1999-06-04 17:54:39 +0000208
209 return r
Guido van Rossum9a22de11995-01-12 12:29:47 +0000210
211
Guido van Rossum0147db01996-03-09 03:16:04 +0000212def parse_multipart(fp, pdict):
Guido van Rossum7aee3841996-03-07 18:00:44 +0000213 """Parse multipart input.
Guido van Rossum9a22de11995-01-12 12:29:47 +0000214
Guido van Rossum7aee3841996-03-07 18:00:44 +0000215 Arguments:
216 fp : input file
Guido van Rossum7aee3841996-03-07 18:00:44 +0000217 pdict: dictionary containing other parameters of conten-type header
Guido van Rossum72755611996-03-06 07:20:06 +0000218
Tim Peters88869f92001-01-14 23:36:06 +0000219 Returns a dictionary just like parse_qs(): keys are the field names, each
220 value is a list of values for that field. This is easy to use but not
221 much good if you are expecting megabytes to be uploaded -- in that case,
222 use the FieldStorage class instead which is much more flexible. Note
223 that content-type is the raw, unparsed contents of the content-type
Guido van Rossum0147db01996-03-09 03:16:04 +0000224 header.
Tim Peters88869f92001-01-14 23:36:06 +0000225
226 XXX This does not parse nested multipart parts -- use FieldStorage for
Guido van Rossum0147db01996-03-09 03:16:04 +0000227 that.
Tim Peters88869f92001-01-14 23:36:06 +0000228
229 XXX This should really be subsumed by FieldStorage altogether -- no
Guido van Rossum0147db01996-03-09 03:16:04 +0000230 point in having two implementations of the same parsing algorithm.
Guido van Rossum72755611996-03-06 07:20:06 +0000231
Guido van Rossum7aee3841996-03-07 18:00:44 +0000232 """
Guido van Rossum7aee3841996-03-07 18:00:44 +0000233 if pdict.has_key('boundary'):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000234 boundary = pdict['boundary']
Guido van Rossum7aee3841996-03-07 18:00:44 +0000235 else:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000236 boundary = ""
Guido van Rossum7aee3841996-03-07 18:00:44 +0000237 nextpart = "--" + boundary
238 lastpart = "--" + boundary + "--"
239 partdict = {}
240 terminator = ""
241
242 while terminator != lastpart:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000243 bytes = -1
244 data = None
245 if terminator:
246 # At start of next part. Read headers first.
247 headers = mimetools.Message(fp)
248 clength = headers.getheader('content-length')
249 if clength:
250 try:
Eric S. Raymond7e9b4f52001-02-09 09:59:10 +0000251 bytes = int(clength)
252 except ValueError:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000253 pass
254 if bytes > 0:
255 if maxlen and bytes > maxlen:
256 raise ValueError, 'Maximum content length exceeded'
257 data = fp.read(bytes)
258 else:
259 data = ""
260 # Read lines until end of part.
261 lines = []
262 while 1:
263 line = fp.readline()
264 if not line:
265 terminator = lastpart # End outer loop
266 break
267 if line[:2] == "--":
Eric S. Raymond7e9b4f52001-02-09 09:59:10 +0000268 terminator = line.strip()
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000269 if terminator in (nextpart, lastpart):
270 break
271 lines.append(line)
272 # Done with part.
273 if data is None:
274 continue
275 if bytes < 0:
276 if lines:
277 # Strip final line terminator
278 line = lines[-1]
279 if line[-2:] == "\r\n":
280 line = line[:-2]
281 elif line[-1:] == "\n":
282 line = line[:-1]
283 lines[-1] = line
Eric S. Raymond7e9b4f52001-02-09 09:59:10 +0000284 data = "".join(lines)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000285 line = headers['content-disposition']
286 if not line:
287 continue
288 key, params = parse_header(line)
289 if key != 'form-data':
290 continue
291 if params.has_key('name'):
292 name = params['name']
293 else:
294 continue
295 if partdict.has_key(name):
296 partdict[name].append(data)
297 else:
298 partdict[name] = [data]
Guido van Rossum72755611996-03-06 07:20:06 +0000299
Guido van Rossum7aee3841996-03-07 18:00:44 +0000300 return partdict
Guido van Rossum9a22de11995-01-12 12:29:47 +0000301
302
Guido van Rossum72755611996-03-06 07:20:06 +0000303def parse_header(line):
Guido van Rossum7aee3841996-03-07 18:00:44 +0000304 """Parse a Content-type like header.
305
306 Return the main content-type and a dictionary of options.
307
308 """
Eric S. Raymond7e9b4f52001-02-09 09:59:10 +0000309 plist = map(lambda x: x.strip(), line.split(';'))
310 key = plist[0].lower()
Guido van Rossum7aee3841996-03-07 18:00:44 +0000311 del plist[0]
312 pdict = {}
313 for p in plist:
Eric S. Raymond7e9b4f52001-02-09 09:59:10 +0000314 i = p.find('=')
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000315 if i >= 0:
Eric S. Raymond7e9b4f52001-02-09 09:59:10 +0000316 name = p[:i].strip().lower()
317 value = p[i+1:].strip()
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000318 if len(value) >= 2 and value[0] == value[-1] == '"':
319 value = value[1:-1]
320 pdict[name] = value
Guido van Rossum7aee3841996-03-07 18:00:44 +0000321 return key, pdict
Guido van Rossum72755611996-03-06 07:20:06 +0000322
323
Guido van Rossum243ddcd1996-03-07 06:33:07 +0000324# Classes for field storage
325# =========================
326
327class MiniFieldStorage:
328
Guido van Rossum0147db01996-03-09 03:16:04 +0000329 """Like FieldStorage, for use when no file uploads are possible."""
Guido van Rossum243ddcd1996-03-07 06:33:07 +0000330
Guido van Rossum7aee3841996-03-07 18:00:44 +0000331 # Dummy attributes
332 filename = None
333 list = None
334 type = None
Guido van Rossum773ab271996-07-23 03:46:24 +0000335 file = None
Guido van Rossum4032c2c1996-03-09 04:04:35 +0000336 type_options = {}
Guido van Rossum7aee3841996-03-07 18:00:44 +0000337 disposition = None
338 disposition_options = {}
339 headers = {}
Guido van Rossum243ddcd1996-03-07 06:33:07 +0000340
Guido van Rossum7aee3841996-03-07 18:00:44 +0000341 def __init__(self, name, value):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000342 """Constructor from field name and value."""
343 self.name = name
344 self.value = value
Guido van Rossum773ab271996-07-23 03:46:24 +0000345 # self.file = StringIO(value)
Guido van Rossum7aee3841996-03-07 18:00:44 +0000346
347 def __repr__(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000348 """Return printable representation."""
349 return "MiniFieldStorage(%s, %s)" % (`self.name`, `self.value`)
Guido van Rossum243ddcd1996-03-07 06:33:07 +0000350
351
352class FieldStorage:
353
Guido van Rossum7aee3841996-03-07 18:00:44 +0000354 """Store a sequence of fields, reading multipart/form-data.
Guido van Rossum243ddcd1996-03-07 06:33:07 +0000355
Guido van Rossum7aee3841996-03-07 18:00:44 +0000356 This class provides naming, typing, files stored on disk, and
357 more. At the top level, it is accessible like a dictionary, whose
358 keys are the field names. (Note: None can occur as a field name.)
359 The items are either a Python list (if there's multiple values) or
360 another FieldStorage or MiniFieldStorage object. If it's a single
361 object, it has the following attributes:
Guido van Rossum243ddcd1996-03-07 06:33:07 +0000362
Guido van Rossum7aee3841996-03-07 18:00:44 +0000363 name: the field name, if specified; otherwise None
Guido van Rossum243ddcd1996-03-07 06:33:07 +0000364
Guido van Rossum7aee3841996-03-07 18:00:44 +0000365 filename: the filename, if specified; otherwise None; this is the
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000366 client side filename, *not* the file name on which it is
367 stored (that's a temporary file you don't deal with)
Guido van Rossum243ddcd1996-03-07 06:33:07 +0000368
Guido van Rossum7aee3841996-03-07 18:00:44 +0000369 value: the value as a *string*; for file uploads, this
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000370 transparently reads the file every time you request the value
Guido van Rossum7aee3841996-03-07 18:00:44 +0000371
372 file: the file(-like) object from which you can read the data;
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000373 None if the data is stored a simple string
Guido van Rossum7aee3841996-03-07 18:00:44 +0000374
375 type: the content-type, or None if not specified
376
377 type_options: dictionary of options specified on the content-type
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000378 line
Guido van Rossum7aee3841996-03-07 18:00:44 +0000379
380 disposition: content-disposition, or None if not specified
381
382 disposition_options: dictionary of corresponding options
383
384 headers: a dictionary(-like) object (sometimes rfc822.Message or a
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000385 subclass thereof) containing *all* headers
Guido van Rossum7aee3841996-03-07 18:00:44 +0000386
387 The class is subclassable, mostly for the purpose of overriding
388 the make_file() method, which is called internally to come up with
389 a file open for reading and writing. This makes it possible to
390 override the default choice of storing all files in a temporary
391 directory and unlinking them as soon as they have been opened.
392
393 """
394
Guido van Rossum773ab271996-07-23 03:46:24 +0000395 def __init__(self, fp=None, headers=None, outerboundary="",
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000396 environ=os.environ, keep_blank_values=0, strict_parsing=0):
397 """Constructor. Read multipart/* until last part.
Guido van Rossum7aee3841996-03-07 18:00:44 +0000398
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000399 Arguments, all optional:
Guido van Rossum7aee3841996-03-07 18:00:44 +0000400
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000401 fp : file pointer; default: sys.stdin
Guido van Rossumb1b4f941998-05-08 19:55:51 +0000402 (not used when the request method is GET)
Guido van Rossum7aee3841996-03-07 18:00:44 +0000403
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000404 headers : header dictionary-like object; default:
405 taken from environ as per CGI spec
Guido van Rossum7aee3841996-03-07 18:00:44 +0000406
Guido van Rossum773ab271996-07-23 03:46:24 +0000407 outerboundary : terminating multipart boundary
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000408 (for internal use only)
Guido van Rossum7aee3841996-03-07 18:00:44 +0000409
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000410 environ : environment dictionary; default: os.environ
Guido van Rossum773ab271996-07-23 03:46:24 +0000411
412 keep_blank_values: flag indicating whether blank values in
Tim Peters88869f92001-01-14 23:36:06 +0000413 URL encoded forms should be treated as blank strings.
414 A true value indicates that blanks should be retained as
Guido van Rossum773ab271996-07-23 03:46:24 +0000415 blank strings. The default false value indicates that
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000416 blank values are to be ignored and treated as if they were
417 not included.
Guido van Rossum773ab271996-07-23 03:46:24 +0000418
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000419 strict_parsing: flag indicating what to do with parsing errors.
420 If false (the default), errors are silently ignored.
421 If true, errors raise a ValueError exception.
Guido van Rossume08c04c1996-11-11 19:29:11 +0000422
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000423 """
424 method = 'GET'
425 self.keep_blank_values = keep_blank_values
426 self.strict_parsing = strict_parsing
427 if environ.has_key('REQUEST_METHOD'):
Eric S. Raymond7e9b4f52001-02-09 09:59:10 +0000428 method = environ['REQUEST_METHOD'].upper()
Guido van Rossum01852831998-06-25 02:40:17 +0000429 if method == 'GET' or method == 'HEAD':
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000430 if environ.has_key('QUERY_STRING'):
431 qs = environ['QUERY_STRING']
432 elif sys.argv[1:]:
433 qs = sys.argv[1]
434 else:
435 qs = ""
436 fp = StringIO(qs)
437 if headers is None:
438 headers = {'content-type':
439 "application/x-www-form-urlencoded"}
440 if headers is None:
Guido van Rossumcff311a1998-06-11 14:06:59 +0000441 headers = {}
442 if method == 'POST':
443 # Set default content-type for POST to what's traditional
444 headers['content-type'] = "application/x-www-form-urlencoded"
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000445 if environ.has_key('CONTENT_TYPE'):
446 headers['content-type'] = environ['CONTENT_TYPE']
447 if environ.has_key('CONTENT_LENGTH'):
448 headers['content-length'] = environ['CONTENT_LENGTH']
449 self.fp = fp or sys.stdin
450 self.headers = headers
451 self.outerboundary = outerboundary
Guido van Rossum7aee3841996-03-07 18:00:44 +0000452
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000453 # Process content-disposition header
454 cdisp, pdict = "", {}
455 if self.headers.has_key('content-disposition'):
456 cdisp, pdict = parse_header(self.headers['content-disposition'])
457 self.disposition = cdisp
458 self.disposition_options = pdict
459 self.name = None
460 if pdict.has_key('name'):
461 self.name = pdict['name']
462 self.filename = None
463 if pdict.has_key('filename'):
464 self.filename = pdict['filename']
Guido van Rossum7aee3841996-03-07 18:00:44 +0000465
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000466 # Process content-type header
Barry Warsaw302331a1999-01-08 17:42:03 +0000467 #
468 # Honor any existing content-type header. But if there is no
469 # content-type header, use some sensible defaults. Assume
470 # outerboundary is "" at the outer level, but something non-false
471 # inside a multi-part. The default for an inner part is text/plain,
472 # but for an outer part it should be urlencoded. This should catch
473 # bogus clients which erroneously forget to include a content-type
474 # header.
475 #
476 # See below for what we do if there does exist a content-type header,
477 # but it happens to be something we don't understand.
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000478 if self.headers.has_key('content-type'):
479 ctype, pdict = parse_header(self.headers['content-type'])
Guido van Rossumce900de1999-06-02 18:44:22 +0000480 elif self.outerboundary or method != 'POST':
Barry Warsaw302331a1999-01-08 17:42:03 +0000481 ctype, pdict = "text/plain", {}
482 else:
483 ctype, pdict = 'application/x-www-form-urlencoded', {}
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000484 self.type = ctype
485 self.type_options = pdict
486 self.innerboundary = ""
487 if pdict.has_key('boundary'):
488 self.innerboundary = pdict['boundary']
489 clen = -1
490 if self.headers.has_key('content-length'):
491 try:
Eric S. Raymond7e9b4f52001-02-09 09:59:10 +0000492 clen = int(self.headers['content-length'])
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000493 except:
494 pass
495 if maxlen and clen > maxlen:
496 raise ValueError, 'Maximum content length exceeded'
497 self.length = clen
Guido van Rossum7aee3841996-03-07 18:00:44 +0000498
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000499 self.list = self.file = None
500 self.done = 0
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000501 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
Moshe Zadkaa1a4b592000-08-25 21:47:56 +0000540 def getvalue(self, key, default=None):
541 """Dictionary style get() method, including 'value' lookup."""
542 if self.has_key(key):
543 value = self[key]
544 if type(value) is type([]):
545 return map(lambda v: v.value, value)
546 else:
547 return value.value
548 else:
549 return default
550
Guido van Rossum7aee3841996-03-07 18:00:44 +0000551 def keys(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000552 """Dictionary style keys() method."""
553 if self.list is None:
554 raise TypeError, "not indexable"
555 keys = []
556 for item in self.list:
557 if item.name not in keys: keys.append(item.name)
558 return keys
Guido van Rossum7aee3841996-03-07 18:00:44 +0000559
Guido van Rossum0147db01996-03-09 03:16:04 +0000560 def has_key(self, key):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000561 """Dictionary style has_key() method."""
562 if self.list is None:
563 raise TypeError, "not indexable"
564 for item in self.list:
565 if item.name == key: return 1
566 return 0
Guido van Rossum0147db01996-03-09 03:16:04 +0000567
Guido van Rossum88b85d41997-01-11 19:21:33 +0000568 def __len__(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000569 """Dictionary style len(x) support."""
570 return len(self.keys())
Guido van Rossum88b85d41997-01-11 19:21:33 +0000571
Guido van Rossum7aee3841996-03-07 18:00:44 +0000572 def read_urlencoded(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000573 """Internal: read data in query string format."""
574 qs = self.fp.read(self.length)
Guido van Rossum1946f0d1999-06-04 17:54:39 +0000575 self.list = list = []
576 for key, value in parse_qsl(qs, self.keep_blank_values,
577 self.strict_parsing):
578 list.append(MiniFieldStorage(key, value))
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000579 self.skip_lines()
Guido van Rossum7aee3841996-03-07 18:00:44 +0000580
Guido van Rossum030d2ec1998-12-09 22:16:46 +0000581 FieldStorageClass = None
582
Guido van Rossumf5745001998-10-20 14:43:02 +0000583 def read_multi(self, environ, keep_blank_values, strict_parsing):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000584 """Internal: read a part that is itself multipart."""
585 self.list = []
Guido van Rossum030d2ec1998-12-09 22:16:46 +0000586 klass = self.FieldStorageClass or self.__class__
587 part = klass(self.fp, {}, self.innerboundary,
588 environ, keep_blank_values, strict_parsing)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000589 # Throw first part away
590 while not part.done:
591 headers = rfc822.Message(self.fp)
Guido van Rossum030d2ec1998-12-09 22:16:46 +0000592 part = klass(self.fp, headers, self.innerboundary,
593 environ, keep_blank_values, strict_parsing)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000594 self.list.append(part)
595 self.skip_lines()
Guido van Rossum7aee3841996-03-07 18:00:44 +0000596
597 def read_single(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000598 """Internal: read an atomic part."""
599 if self.length >= 0:
600 self.read_binary()
601 self.skip_lines()
602 else:
603 self.read_lines()
604 self.file.seek(0)
Guido van Rossum7aee3841996-03-07 18:00:44 +0000605
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000606 bufsize = 8*1024 # I/O buffering size for copy to file
Guido van Rossum7aee3841996-03-07 18:00:44 +0000607
608 def read_binary(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000609 """Internal: read binary data."""
610 self.file = self.make_file('b')
611 todo = self.length
612 if todo >= 0:
613 while todo > 0:
614 data = self.fp.read(min(todo, self.bufsize))
615 if not data:
616 self.done = -1
617 break
618 self.file.write(data)
619 todo = todo - len(data)
Guido van Rossum7aee3841996-03-07 18:00:44 +0000620
621 def read_lines(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000622 """Internal: read lines until EOF or outerboundary."""
623 self.file = self.make_file('')
624 if self.outerboundary:
625 self.read_lines_to_outerboundary()
626 else:
627 self.read_lines_to_eof()
Guido van Rossum7aee3841996-03-07 18:00:44 +0000628
629 def read_lines_to_eof(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000630 """Internal: read lines until EOF."""
631 while 1:
632 line = self.fp.readline()
633 if not line:
634 self.done = -1
635 break
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000636 self.file.write(line)
Guido van Rossum7aee3841996-03-07 18:00:44 +0000637
638 def read_lines_to_outerboundary(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000639 """Internal: read lines until outerboundary."""
640 next = "--" + self.outerboundary
641 last = next + "--"
642 delim = ""
643 while 1:
644 line = self.fp.readline()
645 if not line:
646 self.done = -1
647 break
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000648 if line[:2] == "--":
Eric S. Raymond7e9b4f52001-02-09 09:59:10 +0000649 strippedline = line.strip()
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000650 if strippedline == next:
651 break
652 if strippedline == last:
653 self.done = 1
654 break
655 odelim = delim
656 if line[-2:] == "\r\n":
657 delim = "\r\n"
658 line = line[:-2]
659 elif line[-1] == "\n":
660 delim = "\n"
661 line = line[:-1]
662 else:
663 delim = ""
664 self.file.write(odelim + line)
Guido van Rossum7aee3841996-03-07 18:00:44 +0000665
666 def skip_lines(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000667 """Internal: skip lines until outer boundary if defined."""
668 if not self.outerboundary or self.done:
669 return
670 next = "--" + self.outerboundary
671 last = next + "--"
672 while 1:
673 line = self.fp.readline()
674 if not line:
675 self.done = -1
676 break
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000677 if line[:2] == "--":
Eric S. Raymond7e9b4f52001-02-09 09:59:10 +0000678 strippedline = line.strip()
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000679 if strippedline == next:
680 break
681 if strippedline == last:
682 self.done = 1
683 break
Guido van Rossum7aee3841996-03-07 18:00:44 +0000684
Guido van Rossuma5e9fb61997-08-12 18:18:13 +0000685 def make_file(self, binary=None):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000686 """Overridable: return a readable & writable file.
Guido van Rossum7aee3841996-03-07 18:00:44 +0000687
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000688 The file will be used as follows:
689 - data is written to it
690 - seek(0)
691 - data is read from it
Guido van Rossum7aee3841996-03-07 18:00:44 +0000692
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000693 The 'binary' argument is unused -- the file is always opened
694 in binary mode.
Guido van Rossum7aee3841996-03-07 18:00:44 +0000695
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000696 This version opens a temporary file for reading and writing,
697 and immediately deletes (unlinks) it. The trick (on Unix!) is
698 that the file can still be used, but it can't be opened by
699 another process, and it will automatically be deleted when it
700 is closed or when the current process terminates.
Guido van Rossum4032c2c1996-03-09 04:04:35 +0000701
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000702 If you want a more permanent file, you derive a class which
703 overrides this method. If you want a visible temporary file
704 that is nevertheless automatically deleted when the script
705 terminates, try defining a __del__ method in a derived class
706 which unlinks the temporary files you have created.
Guido van Rossum7aee3841996-03-07 18:00:44 +0000707
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000708 """
709 import tempfile
710 return tempfile.TemporaryFile("w+b")
Tim Peters88869f92001-01-14 23:36:06 +0000711
Guido van Rossum243ddcd1996-03-07 06:33:07 +0000712
713
Guido van Rossum4032c2c1996-03-09 04:04:35 +0000714# Backwards Compatibility Classes
715# ===============================
Guido van Rossum9a22de11995-01-12 12:29:47 +0000716
Moshe Zadkaa1a4b592000-08-25 21:47:56 +0000717class FormContentDict(UserDict.UserDict):
Guido van Rossuma3c6a8a2000-09-19 04:11:46 +0000718 """Form content as dictionary with a list of values per field.
Guido van Rossum72755611996-03-06 07:20:06 +0000719
Guido van Rossum7aee3841996-03-07 18:00:44 +0000720 form = FormContentDict()
721
722 form[key] -> [value, value, ...]
723 form.has_key(key) -> Boolean
724 form.keys() -> [key, key, ...]
725 form.values() -> [[val, val, ...], [val, val, ...], ...]
726 form.items() -> [(key, [val, val, ...]), (key, [val, val, ...]), ...]
727 form.dict == {key: [val, val, ...], ...}
728
729 """
Guido van Rossum773ab271996-07-23 03:46:24 +0000730 def __init__(self, environ=os.environ):
Moshe Zadkaa1a4b592000-08-25 21:47:56 +0000731 self.dict = self.data = parse(environ=environ)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000732 self.query_string = environ['QUERY_STRING']
Guido van Rossum9a22de11995-01-12 12:29:47 +0000733
734
Guido van Rossum9a22de11995-01-12 12:29:47 +0000735class SvFormContentDict(FormContentDict):
Guido van Rossuma3c6a8a2000-09-19 04:11:46 +0000736 """Form content as dictionary expecting a single value per field.
Guido van Rossum7aee3841996-03-07 18:00:44 +0000737
Guido van Rossuma3c6a8a2000-09-19 04:11:46 +0000738 If you only expect a single value for each field, then form[key]
Guido van Rossum7aee3841996-03-07 18:00:44 +0000739 will return that single value. It will raise an IndexError if
Guido van Rossuma3c6a8a2000-09-19 04:11:46 +0000740 that expectation is not true. If you expect a field to have
Guido van Rossum7aee3841996-03-07 18:00:44 +0000741 possible multiple values, than you can use form.getlist(key) to
742 get all of the values. values() and items() are a compromise:
743 they return single strings where there is a single value, and
744 lists of strings otherwise.
745
746 """
747 def __getitem__(self, key):
Tim Peters88869f92001-01-14 23:36:06 +0000748 if len(self.dict[key]) > 1:
749 raise IndexError, 'expecting a single value'
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000750 return self.dict[key][0]
Guido van Rossum7aee3841996-03-07 18:00:44 +0000751 def getlist(self, key):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000752 return self.dict[key]
Guido van Rossum7aee3841996-03-07 18:00:44 +0000753 def values(self):
Guido van Rossuma3c6a8a2000-09-19 04:11:46 +0000754 result = []
755 for value in self.dict.values():
756 if len(value) == 1:
757 result.append(value[0])
758 else: result.append(value)
759 return result
Guido van Rossum7aee3841996-03-07 18:00:44 +0000760 def items(self):
Guido van Rossuma3c6a8a2000-09-19 04:11:46 +0000761 result = []
762 for key, value in self.dict.items():
763 if len(value) == 1:
764 result.append((key, value[0]))
765 else: result.append((key, value))
766 return result
Guido van Rossum9a22de11995-01-12 12:29:47 +0000767
768
Guido van Rossum9a22de11995-01-12 12:29:47 +0000769class InterpFormContentDict(SvFormContentDict):
Tim Peters88869f92001-01-14 23:36:06 +0000770 """This class is present for backwards compatibility only."""
Guido van Rossuma3c6a8a2000-09-19 04:11:46 +0000771 def __getitem__(self, key):
772 v = SvFormContentDict.__getitem__(self, key)
Eric S. Raymond7e9b4f52001-02-09 09:59:10 +0000773 if v[0] in '0123456789+-.':
774 try: return int(v)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000775 except ValueError:
Eric S. Raymond7e9b4f52001-02-09 09:59:10 +0000776 try: return float(v)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000777 except ValueError: pass
Eric S. Raymond7e9b4f52001-02-09 09:59:10 +0000778 return v.strip()
Guido van Rossuma3c6a8a2000-09-19 04:11:46 +0000779 def values(self):
780 result = []
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000781 for key in self.keys():
782 try:
Guido van Rossuma3c6a8a2000-09-19 04:11:46 +0000783 result.append(self[key])
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000784 except IndexError:
Guido van Rossuma3c6a8a2000-09-19 04:11:46 +0000785 result.append(self.dict[key])
786 return result
787 def items(self):
788 result = []
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000789 for key in self.keys():
790 try:
Guido van Rossuma3c6a8a2000-09-19 04:11:46 +0000791 result.append((key, self[key]))
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000792 except IndexError:
Guido van Rossuma3c6a8a2000-09-19 04:11:46 +0000793 result.append((key, self.dict[key]))
794 return result
Guido van Rossum9a22de11995-01-12 12:29:47 +0000795
796
Guido van Rossum9a22de11995-01-12 12:29:47 +0000797class FormContent(FormContentDict):
Tim Peters88869f92001-01-14 23:36:06 +0000798 """This class is present for backwards compatibility only."""
Guido van Rossum0147db01996-03-09 03:16:04 +0000799 def values(self, key):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000800 if self.dict.has_key(key) :return self.dict[key]
801 else: return None
Guido van Rossum0147db01996-03-09 03:16:04 +0000802 def indexed_value(self, key, location):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000803 if self.dict.has_key(key):
Guido van Rossuma3c6a8a2000-09-19 04:11:46 +0000804 if len(self.dict[key]) > location:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000805 return self.dict[key][location]
806 else: return None
807 else: return None
Guido van Rossum0147db01996-03-09 03:16:04 +0000808 def value(self, key):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000809 if self.dict.has_key(key): return self.dict[key][0]
810 else: return None
Guido van Rossum0147db01996-03-09 03:16:04 +0000811 def length(self, key):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000812 return len(self.dict[key])
Guido van Rossum0147db01996-03-09 03:16:04 +0000813 def stripped(self, key):
Eric S. Raymond7e9b4f52001-02-09 09:59:10 +0000814 if self.dict.has_key(key): return self.dict[key][0].strip()
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000815 else: return None
Guido van Rossum7aee3841996-03-07 18:00:44 +0000816 def pars(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000817 return self.dict
Guido van Rossum9a22de11995-01-12 12:29:47 +0000818
819
Guido van Rossum72755611996-03-06 07:20:06 +0000820# Test/debug code
821# ===============
Guido van Rossum9a22de11995-01-12 12:29:47 +0000822
Guido van Rossum773ab271996-07-23 03:46:24 +0000823def test(environ=os.environ):
Guido van Rossum7aee3841996-03-07 18:00:44 +0000824 """Robust test CGI script, usable as main program.
Guido van Rossum9a22de11995-01-12 12:29:47 +0000825
Guido van Rossum7aee3841996-03-07 18:00:44 +0000826 Write minimal HTTP headers and dump all information provided to
827 the script in HTML form.
828
829 """
830 import traceback
831 print "Content-type: text/html"
832 print
833 sys.stderr = sys.stdout
834 try:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000835 form = FieldStorage() # Replace with other classes to test those
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000836 print_directory()
837 print_arguments()
Guido van Rossuma3c6a8a2000-09-19 04:11:46 +0000838 print_form(form)
839 print_environ(environ)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000840 print_environ_usage()
841 def f():
842 exec "testing print_exception() -- <I>italics?</I>"
843 def g(f=f):
844 f()
845 print "<H3>What follows is a test, not an actual exception:</H3>"
846 g()
Guido van Rossum7aee3841996-03-07 18:00:44 +0000847 except:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000848 print_exception()
Guido van Rossumf85de8a1996-08-20 20:22:39 +0000849
Guido van Rossum57d51f22000-09-16 21:16:01 +0000850 print "<H1>Second try with a small maxlen...</H1>"
851
Guido van Rossumad164711997-05-13 19:03:23 +0000852 global maxlen
853 maxlen = 50
854 try:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000855 form = FieldStorage() # Replace with other classes to test those
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000856 print_directory()
857 print_arguments()
Guido van Rossuma3c6a8a2000-09-19 04:11:46 +0000858 print_form(form)
859 print_environ(environ)
Guido van Rossumad164711997-05-13 19:03:23 +0000860 except:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000861 print_exception()
Guido van Rossumad164711997-05-13 19:03:23 +0000862
Guido van Rossumf85de8a1996-08-20 20:22:39 +0000863def print_exception(type=None, value=None, tb=None, limit=None):
864 if type is None:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000865 type, value, tb = sys.exc_info()
Guido van Rossumf85de8a1996-08-20 20:22:39 +0000866 import traceback
867 print
Guido van Rossum7dd06962000-12-27 19:12:58 +0000868 print "<H3>Traceback (most recent call last):</H3>"
Guido van Rossumf85de8a1996-08-20 20:22:39 +0000869 list = traceback.format_tb(tb, limit) + \
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000870 traceback.format_exception_only(type, value)
Guido van Rossumf85de8a1996-08-20 20:22:39 +0000871 print "<PRE>%s<B>%s</B></PRE>" % (
Eric S. Raymond7e9b4f52001-02-09 09:59:10 +0000872 escape("".join(list[:-1])),
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000873 escape(list[-1]),
874 )
Guido van Rossumf15d1591997-09-29 23:22:12 +0000875 del tb
Guido van Rossum9a22de11995-01-12 12:29:47 +0000876
Guido van Rossum773ab271996-07-23 03:46:24 +0000877def print_environ(environ=os.environ):
Guido van Rossum7aee3841996-03-07 18:00:44 +0000878 """Dump the shell environment as HTML."""
879 keys = environ.keys()
880 keys.sort()
881 print
Guido van Rossum503e50b1996-05-28 22:57:20 +0000882 print "<H3>Shell Environment:</H3>"
Guido van Rossum7aee3841996-03-07 18:00:44 +0000883 print "<DL>"
884 for key in keys:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000885 print "<DT>", escape(key), "<DD>", escape(environ[key])
Tim Peters88869f92001-01-14 23:36:06 +0000886 print "</DL>"
Guido van Rossum7aee3841996-03-07 18:00:44 +0000887 print
Guido van Rossum72755611996-03-06 07:20:06 +0000888
889def print_form(form):
Guido van Rossum7aee3841996-03-07 18:00:44 +0000890 """Dump the contents of a form as HTML."""
891 keys = form.keys()
892 keys.sort()
893 print
Guido van Rossum503e50b1996-05-28 22:57:20 +0000894 print "<H3>Form Contents:</H3>"
Guido van Rossum57d51f22000-09-16 21:16:01 +0000895 if not keys:
896 print "<P>No form fields."
Guido van Rossum7aee3841996-03-07 18:00:44 +0000897 print "<DL>"
898 for key in keys:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000899 print "<DT>" + escape(key) + ":",
900 value = form[key]
901 print "<i>" + escape(`type(value)`) + "</i>"
902 print "<DD>" + escape(`value`)
Guido van Rossum7aee3841996-03-07 18:00:44 +0000903 print "</DL>"
904 print
905
906def print_directory():
907 """Dump the current directory as HTML."""
908 print
909 print "<H3>Current Working Directory:</H3>"
910 try:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000911 pwd = os.getcwd()
Guido van Rossum7aee3841996-03-07 18:00:44 +0000912 except os.error, msg:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000913 print "os.error:", escape(str(msg))
Guido van Rossum7aee3841996-03-07 18:00:44 +0000914 else:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000915 print escape(pwd)
Guido van Rossum7aee3841996-03-07 18:00:44 +0000916 print
Guido van Rossum9a22de11995-01-12 12:29:47 +0000917
Guido van Rossuma8738a51996-03-14 21:30:28 +0000918def print_arguments():
919 print
Guido van Rossum503e50b1996-05-28 22:57:20 +0000920 print "<H3>Command Line Arguments:</H3>"
Guido van Rossuma8738a51996-03-14 21:30:28 +0000921 print
922 print sys.argv
923 print
924
Guido van Rossum9a22de11995-01-12 12:29:47 +0000925def print_environ_usage():
Guido van Rossum7aee3841996-03-07 18:00:44 +0000926 """Dump a list of environment variables used by CGI as HTML."""
927 print """
Guido van Rossum72755611996-03-06 07:20:06 +0000928<H3>These environment variables could have been set:</H3>
929<UL>
Guido van Rossum9a22de11995-01-12 12:29:47 +0000930<LI>AUTH_TYPE
931<LI>CONTENT_LENGTH
932<LI>CONTENT_TYPE
933<LI>DATE_GMT
934<LI>DATE_LOCAL
935<LI>DOCUMENT_NAME
936<LI>DOCUMENT_ROOT
937<LI>DOCUMENT_URI
938<LI>GATEWAY_INTERFACE
939<LI>LAST_MODIFIED
940<LI>PATH
941<LI>PATH_INFO
942<LI>PATH_TRANSLATED
943<LI>QUERY_STRING
944<LI>REMOTE_ADDR
945<LI>REMOTE_HOST
946<LI>REMOTE_IDENT
947<LI>REMOTE_USER
948<LI>REQUEST_METHOD
949<LI>SCRIPT_NAME
950<LI>SERVER_NAME
951<LI>SERVER_PORT
952<LI>SERVER_PROTOCOL
953<LI>SERVER_ROOT
954<LI>SERVER_SOFTWARE
955</UL>
Guido van Rossum7aee3841996-03-07 18:00:44 +0000956In addition, HTTP headers sent by the server may be passed in the
957environment as well. Here are some common variable names:
958<UL>
959<LI>HTTP_ACCEPT
960<LI>HTTP_CONNECTION
961<LI>HTTP_HOST
962<LI>HTTP_PRAGMA
963<LI>HTTP_REFERER
964<LI>HTTP_USER_AGENT
965</UL>
Guido van Rossum9a22de11995-01-12 12:29:47 +0000966"""
967
Guido van Rossum9a22de11995-01-12 12:29:47 +0000968
Guido van Rossum72755611996-03-06 07:20:06 +0000969# Utilities
970# =========
Guido van Rossum9a22de11995-01-12 12:29:47 +0000971
Guido van Rossum64c66201997-07-19 20:11:53 +0000972def escape(s, quote=None):
Guido van Rossum7aee3841996-03-07 18:00:44 +0000973 """Replace special characters '&', '<' and '>' by SGML entities."""
Eric S. Raymond7e9b4f52001-02-09 09:59:10 +0000974 s = s.replace("&", "&amp;") # Must be done first!
975 s = s.replace("<", "&lt;")
976 s = s.replace(">", "&gt;")
Guido van Rossum64c66201997-07-19 20:11:53 +0000977 if quote:
Eric S. Raymond7e9b4f52001-02-09 09:59:10 +0000978 s = s.replace('"', "&quot;")
Guido van Rossum7aee3841996-03-07 18:00:44 +0000979 return s
Guido van Rossum9a22de11995-01-12 12:29:47 +0000980
Guido van Rossum9a22de11995-01-12 12:29:47 +0000981
Guido van Rossum72755611996-03-06 07:20:06 +0000982# Invoke mainline
983# ===============
984
985# Call test() when this file is run as a script (not imported as a module)
Tim Peters88869f92001-01-14 23:36:06 +0000986if __name__ == '__main__':
Guido van Rossum7aee3841996-03-07 18:00:44 +0000987 test()