blob: 9c38359d4bfc07824a66f4b3e2b9f4d9a30359c2 [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 Rossum467d7232001-02-13 13:13:33 +00003# NOTE: the above "/usr/local/bin/python" is NOT a mistake. It is
4# intentionally NOT "/usr/bin/env python". On many systems
5# (e.g. Solaris), /usr/local/bin is not in $PATH as passed to CGI
6# scripts, and /usr/local/bin is the default directory where Python is
7# installed, so /usr/bin/env would be unable to find python. Granted,
8# binary installations by Linux vendors often install Python in
9# /usr/bin. So let those vendors patch cgi.py to match their choice
10# of installation.
11
Guido van Rossum72755611996-03-06 07:20:06 +000012"""Support module for CGI (Common Gateway Interface) scripts.
Guido van Rossum1c9daa81995-09-18 21:52:37 +000013
Guido van Rossum7aee3841996-03-07 18:00:44 +000014This module defines a number of utilities for use by CGI scripts
15written in Python.
Guido van Rossum72755611996-03-06 07:20:06 +000016"""
17
Jeremy Hyltonc253d9a2000-08-03 20:57:44 +000018# XXX Perhaps there should be a slimmed version that doesn't contain
19# all those backwards compatible and debugging classes and functions?
Guido van Rossum98d9fd32000-02-28 15:12:25 +000020
21# History
22# -------
Tim Peters88869f92001-01-14 23:36:06 +000023#
Guido van Rossum98d9fd32000-02-28 15:12:25 +000024# Michael McLay started this module. Steve Majewski changed the
25# interface to SvFormContentDict and FormContentDict. The multipart
26# parsing was inspired by code submitted by Andreas Paepcke. Guido van
27# Rossum rewrote, reformatted and documented the module and is currently
28# responsible for its maintenance.
Tim Peters88869f92001-01-14 23:36:06 +000029#
Guido van Rossum98d9fd32000-02-28 15:12:25 +000030
Barry Warsaw7fed2172000-11-06 18:46:09 +000031__version__ = "2.5"
Guido van Rossum0147db01996-03-09 03:16:04 +000032
Guido van Rossum72755611996-03-06 07:20:06 +000033
34# Imports
35# =======
36
Guido van Rossum72755611996-03-06 07:20:06 +000037import sys
38import os
Guido van Rossuma5e9fb61997-08-12 18:18:13 +000039import urllib
Guido van Rossuma5e9fb61997-08-12 18:18:13 +000040import mimetools
41import rfc822
Moshe Zadkaa1a4b592000-08-25 21:47:56 +000042import UserDict
Guido van Rossuma5e9fb61997-08-12 18:18:13 +000043from StringIO import StringIO
Guido van Rossum72755611996-03-06 07:20:06 +000044
Skip Montanaroe99d5ea2001-01-20 19:54:20 +000045__all__ = ["MiniFieldStorage","FieldStorage","FormContentDict",
46 "SvFormContentDict","InterpFormContentDict","FormContent"]
Guido van Rossumc204c701996-09-05 19:07:11 +000047
48# Logging support
49# ===============
50
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000051logfile = "" # Filename to log to, if not empty
52logfp = None # File object to log to, if not None
Guido van Rossumc204c701996-09-05 19:07:11 +000053
54def initlog(*allargs):
55 """Write a log message, if there is a log file.
56
57 Even though this function is called initlog(), you should always
58 use log(); log is a variable that is set either to initlog
59 (initially), to dolog (once the log file has been opened), or to
60 nolog (when logging is disabled).
61
62 The first argument is a format string; the remaining arguments (if
63 any) are arguments to the % operator, so e.g.
64 log("%s: %s", "a", "b")
65 will write "a: b" to the log file, followed by a newline.
66
67 If the global logfp is not None, it should be a file object to
68 which log data is written.
69
70 If the global logfp is None, the global logfile may be a string
71 giving a filename to open, in append mode. This file should be
72 world writable!!! If the file can't be opened, logging is
73 silently disabled (since there is no safe place where we could
74 send an error message).
75
76 """
77 global logfp, log
78 if logfile and not logfp:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000079 try:
80 logfp = open(logfile, "a")
81 except IOError:
82 pass
Guido van Rossumc204c701996-09-05 19:07:11 +000083 if not logfp:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000084 log = nolog
Guido van Rossumc204c701996-09-05 19:07:11 +000085 else:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000086 log = dolog
Guido van Rossumc204c701996-09-05 19:07:11 +000087 apply(log, allargs)
88
89def dolog(fmt, *args):
90 """Write a log message to the log file. See initlog() for docs."""
91 logfp.write(fmt%args + "\n")
92
93def nolog(*allargs):
94 """Dummy function, assigned to log when logging is disabled."""
95 pass
96
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000097log = initlog # The current logging function
Guido van Rossumc204c701996-09-05 19:07:11 +000098
99
Guido van Rossum72755611996-03-06 07:20:06 +0000100# Parsing functions
101# =================
102
Guido van Rossumad164711997-05-13 19:03:23 +0000103# Maximum input we will accept when REQUEST_METHOD is POST
104# 0 ==> unlimited input
105maxlen = 0
106
Guido van Rossume08c04c1996-11-11 19:29:11 +0000107def parse(fp=None, environ=os.environ, keep_blank_values=0, strict_parsing=0):
Guido van Rossum773ab271996-07-23 03:46:24 +0000108 """Parse a query in the environment or from a file (default stdin)
109
110 Arguments, all optional:
111
112 fp : file pointer; default: sys.stdin
113
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000114 environ : environment dictionary; default: os.environ
Guido van Rossum773ab271996-07-23 03:46:24 +0000115
116 keep_blank_values: flag indicating whether blank values in
Tim Peters88869f92001-01-14 23:36:06 +0000117 URL encoded forms should be treated as blank strings.
118 A true value indicates that blanks should be retained as
Guido van Rossum773ab271996-07-23 03:46:24 +0000119 blank strings. The default false value indicates that
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000120 blank values are to be ignored and treated as if they were
121 not included.
Guido van Rossume08c04c1996-11-11 19:29:11 +0000122
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000123 strict_parsing: flag indicating what to do with parsing errors.
124 If false (the default), errors are silently ignored.
125 If true, errors raise a ValueError exception.
Guido van Rossum773ab271996-07-23 03:46:24 +0000126 """
Guido van Rossum7aee3841996-03-07 18:00:44 +0000127 if not fp:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000128 fp = sys.stdin
Guido van Rossum7aee3841996-03-07 18:00:44 +0000129 if not environ.has_key('REQUEST_METHOD'):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000130 environ['REQUEST_METHOD'] = 'GET' # For testing stand-alone
Guido van Rossum7aee3841996-03-07 18:00:44 +0000131 if environ['REQUEST_METHOD'] == 'POST':
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000132 ctype, pdict = parse_header(environ['CONTENT_TYPE'])
133 if ctype == 'multipart/form-data':
134 return parse_multipart(fp, pdict)
135 elif ctype == 'application/x-www-form-urlencoded':
Eric S. Raymond7e9b4f52001-02-09 09:59:10 +0000136 clength = int(environ['CONTENT_LENGTH'])
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000137 if maxlen and clength > maxlen:
138 raise ValueError, 'Maximum content length exceeded'
139 qs = fp.read(clength)
140 else:
141 qs = '' # Unknown content-type
Tim Peters88869f92001-01-14 23:36:06 +0000142 if environ.has_key('QUERY_STRING'):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000143 if qs: qs = qs + '&'
144 qs = qs + environ['QUERY_STRING']
Tim Peters88869f92001-01-14 23:36:06 +0000145 elif sys.argv[1:]:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000146 if qs: qs = qs + '&'
147 qs = qs + sys.argv[1]
148 environ['QUERY_STRING'] = qs # XXX Shouldn't, really
Guido van Rossum7aee3841996-03-07 18:00:44 +0000149 elif environ.has_key('QUERY_STRING'):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000150 qs = environ['QUERY_STRING']
Guido van Rossum7aee3841996-03-07 18:00:44 +0000151 else:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000152 if sys.argv[1:]:
153 qs = sys.argv[1]
154 else:
155 qs = ""
156 environ['QUERY_STRING'] = qs # XXX Shouldn't, really
Guido van Rossume08c04c1996-11-11 19:29:11 +0000157 return parse_qs(qs, keep_blank_values, strict_parsing)
Guido van Rossume7808771995-08-07 20:12:09 +0000158
159
Guido van Rossume08c04c1996-11-11 19:29:11 +0000160def parse_qs(qs, keep_blank_values=0, strict_parsing=0):
161 """Parse a query given as a string argument.
Guido van Rossum773ab271996-07-23 03:46:24 +0000162
163 Arguments:
164
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000165 qs: URL-encoded query string to be parsed
Guido van Rossum773ab271996-07-23 03:46:24 +0000166
167 keep_blank_values: flag indicating whether blank values in
Tim Peters88869f92001-01-14 23:36:06 +0000168 URL encoded queries should be treated as blank strings.
169 A true value indicates that blanks should be retained as
Guido van Rossum773ab271996-07-23 03:46:24 +0000170 blank strings. The default false value indicates that
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000171 blank values are to be ignored and treated as if they were
172 not included.
Guido van Rossume08c04c1996-11-11 19:29:11 +0000173
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000174 strict_parsing: flag indicating what to do with parsing errors.
175 If false (the default), errors are silently ignored.
176 If true, errors raise a ValueError exception.
Guido van Rossum773ab271996-07-23 03:46:24 +0000177 """
Guido van Rossum7aee3841996-03-07 18:00:44 +0000178 dict = {}
Guido van Rossum1946f0d1999-06-04 17:54:39 +0000179 for name, value in parse_qsl(qs, keep_blank_values, strict_parsing):
Moshe Zadkaa1a4b592000-08-25 21:47:56 +0000180 if dict.has_key(name):
181 dict[name].append(value)
182 else:
183 dict[name] = [value]
Guido van Rossum1946f0d1999-06-04 17:54:39 +0000184 return dict
185
186def parse_qsl(qs, keep_blank_values=0, strict_parsing=0):
187 """Parse a query given as a string argument.
188
Jeremy Hyltonafde7e22000-09-15 20:06:57 +0000189 Arguments:
Guido van Rossum1946f0d1999-06-04 17:54:39 +0000190
Jeremy Hyltonafde7e22000-09-15 20:06:57 +0000191 qs: URL-encoded query string to be parsed
Guido van Rossum1946f0d1999-06-04 17:54:39 +0000192
Jeremy Hyltonafde7e22000-09-15 20:06:57 +0000193 keep_blank_values: flag indicating whether blank values in
194 URL encoded queries should be treated as blank strings. A
195 true value indicates that blanks should be retained as blank
196 strings. The default false value indicates that blank values
197 are to be ignored and treated as if they were not included.
Guido van Rossum1946f0d1999-06-04 17:54:39 +0000198
Jeremy Hyltonafde7e22000-09-15 20:06:57 +0000199 strict_parsing: flag indicating what to do with parsing errors. If
200 false (the default), errors are silently ignored. If true,
Tim Peters88869f92001-01-14 23:36:06 +0000201 errors raise a ValueError exception.
Guido van Rossum1946f0d1999-06-04 17:54:39 +0000202
Jeremy Hyltonafde7e22000-09-15 20:06:57 +0000203 Returns a list, as G-d intended.
Guido van Rossum1946f0d1999-06-04 17:54:39 +0000204 """
Jeremy Hyltonafde7e22000-09-15 20:06:57 +0000205 pairs = [s2 for s1 in qs.split('&') for s2 in s1.split(';')]
206 r = []
207 for name_value in pairs:
208 nv = name_value.split('=', 1)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000209 if len(nv) != 2:
210 if strict_parsing:
211 raise ValueError, "bad query field: %s" % `name_value`
212 continue
Moshe Zadkaa1a4b592000-08-25 21:47:56 +0000213 if len(nv[1]) or keep_blank_values:
Eric S. Raymond7e9b4f52001-02-09 09:59:10 +0000214 name = urllib.unquote(nv[0].replace('+', ' '))
215 value = urllib.unquote(nv[1].replace('+', ' '))
Moshe Zadkaa1a4b592000-08-25 21:47:56 +0000216 r.append((name, value))
Guido van Rossum1946f0d1999-06-04 17:54:39 +0000217
218 return r
Guido van Rossum9a22de11995-01-12 12:29:47 +0000219
220
Guido van Rossum0147db01996-03-09 03:16:04 +0000221def parse_multipart(fp, pdict):
Guido van Rossum7aee3841996-03-07 18:00:44 +0000222 """Parse multipart input.
Guido van Rossum9a22de11995-01-12 12:29:47 +0000223
Guido van Rossum7aee3841996-03-07 18:00:44 +0000224 Arguments:
225 fp : input file
Guido van Rossum7aee3841996-03-07 18:00:44 +0000226 pdict: dictionary containing other parameters of conten-type header
Guido van Rossum72755611996-03-06 07:20:06 +0000227
Tim Peters88869f92001-01-14 23:36:06 +0000228 Returns a dictionary just like parse_qs(): keys are the field names, each
229 value is a list of values for that field. This is easy to use but not
230 much good if you are expecting megabytes to be uploaded -- in that case,
231 use the FieldStorage class instead which is much more flexible. Note
232 that content-type is the raw, unparsed contents of the content-type
Guido van Rossum0147db01996-03-09 03:16:04 +0000233 header.
Tim Peters88869f92001-01-14 23:36:06 +0000234
235 XXX This does not parse nested multipart parts -- use FieldStorage for
Guido van Rossum0147db01996-03-09 03:16:04 +0000236 that.
Tim Peters88869f92001-01-14 23:36:06 +0000237
238 XXX This should really be subsumed by FieldStorage altogether -- no
Guido van Rossum0147db01996-03-09 03:16:04 +0000239 point in having two implementations of the same parsing algorithm.
Guido van Rossum72755611996-03-06 07:20:06 +0000240
Guido van Rossum7aee3841996-03-07 18:00:44 +0000241 """
Guido van Rossum7aee3841996-03-07 18:00:44 +0000242 if pdict.has_key('boundary'):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000243 boundary = pdict['boundary']
Guido van Rossum7aee3841996-03-07 18:00:44 +0000244 else:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000245 boundary = ""
Guido van Rossum7aee3841996-03-07 18:00:44 +0000246 nextpart = "--" + boundary
247 lastpart = "--" + boundary + "--"
248 partdict = {}
249 terminator = ""
250
251 while terminator != lastpart:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000252 bytes = -1
253 data = None
254 if terminator:
255 # At start of next part. Read headers first.
256 headers = mimetools.Message(fp)
257 clength = headers.getheader('content-length')
258 if clength:
259 try:
Eric S. Raymond7e9b4f52001-02-09 09:59:10 +0000260 bytes = int(clength)
261 except ValueError:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000262 pass
263 if bytes > 0:
264 if maxlen and bytes > maxlen:
265 raise ValueError, 'Maximum content length exceeded'
266 data = fp.read(bytes)
267 else:
268 data = ""
269 # Read lines until end of part.
270 lines = []
271 while 1:
272 line = fp.readline()
273 if not line:
274 terminator = lastpart # End outer loop
275 break
276 if line[:2] == "--":
Eric S. Raymond7e9b4f52001-02-09 09:59:10 +0000277 terminator = line.strip()
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000278 if terminator in (nextpart, lastpart):
279 break
280 lines.append(line)
281 # Done with part.
282 if data is None:
283 continue
284 if bytes < 0:
285 if lines:
286 # Strip final line terminator
287 line = lines[-1]
288 if line[-2:] == "\r\n":
289 line = line[:-2]
290 elif line[-1:] == "\n":
291 line = line[:-1]
292 lines[-1] = line
Eric S. Raymond7e9b4f52001-02-09 09:59:10 +0000293 data = "".join(lines)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000294 line = headers['content-disposition']
295 if not line:
296 continue
297 key, params = parse_header(line)
298 if key != 'form-data':
299 continue
300 if params.has_key('name'):
301 name = params['name']
302 else:
303 continue
304 if partdict.has_key(name):
305 partdict[name].append(data)
306 else:
307 partdict[name] = [data]
Guido van Rossum72755611996-03-06 07:20:06 +0000308
Guido van Rossum7aee3841996-03-07 18:00:44 +0000309 return partdict
Guido van Rossum9a22de11995-01-12 12:29:47 +0000310
311
Guido van Rossum72755611996-03-06 07:20:06 +0000312def parse_header(line):
Guido van Rossum7aee3841996-03-07 18:00:44 +0000313 """Parse a Content-type like header.
314
315 Return the main content-type and a dictionary of options.
316
317 """
Eric S. Raymond7e9b4f52001-02-09 09:59:10 +0000318 plist = map(lambda x: x.strip(), line.split(';'))
319 key = plist[0].lower()
Guido van Rossum7aee3841996-03-07 18:00:44 +0000320 del plist[0]
321 pdict = {}
322 for p in plist:
Eric S. Raymond7e9b4f52001-02-09 09:59:10 +0000323 i = p.find('=')
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000324 if i >= 0:
Eric S. Raymond7e9b4f52001-02-09 09:59:10 +0000325 name = p[:i].strip().lower()
326 value = p[i+1:].strip()
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000327 if len(value) >= 2 and value[0] == value[-1] == '"':
328 value = value[1:-1]
329 pdict[name] = value
Guido van Rossum7aee3841996-03-07 18:00:44 +0000330 return key, pdict
Guido van Rossum72755611996-03-06 07:20:06 +0000331
332
Guido van Rossum243ddcd1996-03-07 06:33:07 +0000333# Classes for field storage
334# =========================
335
336class MiniFieldStorage:
337
Guido van Rossum0147db01996-03-09 03:16:04 +0000338 """Like FieldStorage, for use when no file uploads are possible."""
Guido van Rossum243ddcd1996-03-07 06:33:07 +0000339
Guido van Rossum7aee3841996-03-07 18:00:44 +0000340 # Dummy attributes
341 filename = None
342 list = None
343 type = None
Guido van Rossum773ab271996-07-23 03:46:24 +0000344 file = None
Guido van Rossum4032c2c1996-03-09 04:04:35 +0000345 type_options = {}
Guido van Rossum7aee3841996-03-07 18:00:44 +0000346 disposition = None
347 disposition_options = {}
348 headers = {}
Guido van Rossum243ddcd1996-03-07 06:33:07 +0000349
Guido van Rossum7aee3841996-03-07 18:00:44 +0000350 def __init__(self, name, value):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000351 """Constructor from field name and value."""
352 self.name = name
353 self.value = value
Guido van Rossum773ab271996-07-23 03:46:24 +0000354 # self.file = StringIO(value)
Guido van Rossum7aee3841996-03-07 18:00:44 +0000355
356 def __repr__(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000357 """Return printable representation."""
358 return "MiniFieldStorage(%s, %s)" % (`self.name`, `self.value`)
Guido van Rossum243ddcd1996-03-07 06:33:07 +0000359
360
361class FieldStorage:
362
Guido van Rossum7aee3841996-03-07 18:00:44 +0000363 """Store a sequence of fields, reading multipart/form-data.
Guido van Rossum243ddcd1996-03-07 06:33:07 +0000364
Guido van Rossum7aee3841996-03-07 18:00:44 +0000365 This class provides naming, typing, files stored on disk, and
366 more. At the top level, it is accessible like a dictionary, whose
367 keys are the field names. (Note: None can occur as a field name.)
368 The items are either a Python list (if there's multiple values) or
369 another FieldStorage or MiniFieldStorage object. If it's a single
370 object, it has the following attributes:
Guido van Rossum243ddcd1996-03-07 06:33:07 +0000371
Guido van Rossum7aee3841996-03-07 18:00:44 +0000372 name: the field name, if specified; otherwise None
Guido van Rossum243ddcd1996-03-07 06:33:07 +0000373
Guido van Rossum7aee3841996-03-07 18:00:44 +0000374 filename: the filename, if specified; otherwise None; this is the
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000375 client side filename, *not* the file name on which it is
376 stored (that's a temporary file you don't deal with)
Guido van Rossum243ddcd1996-03-07 06:33:07 +0000377
Guido van Rossum7aee3841996-03-07 18:00:44 +0000378 value: the value as a *string*; for file uploads, this
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000379 transparently reads the file every time you request the value
Guido van Rossum7aee3841996-03-07 18:00:44 +0000380
381 file: the file(-like) object from which you can read the data;
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000382 None if the data is stored a simple string
Guido van Rossum7aee3841996-03-07 18:00:44 +0000383
384 type: the content-type, or None if not specified
385
386 type_options: dictionary of options specified on the content-type
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000387 line
Guido van Rossum7aee3841996-03-07 18:00:44 +0000388
389 disposition: content-disposition, or None if not specified
390
391 disposition_options: dictionary of corresponding options
392
393 headers: a dictionary(-like) object (sometimes rfc822.Message or a
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000394 subclass thereof) containing *all* headers
Guido van Rossum7aee3841996-03-07 18:00:44 +0000395
396 The class is subclassable, mostly for the purpose of overriding
397 the make_file() method, which is called internally to come up with
398 a file open for reading and writing. This makes it possible to
399 override the default choice of storing all files in a temporary
400 directory and unlinking them as soon as they have been opened.
401
402 """
403
Guido van Rossum773ab271996-07-23 03:46:24 +0000404 def __init__(self, fp=None, headers=None, outerboundary="",
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000405 environ=os.environ, keep_blank_values=0, strict_parsing=0):
406 """Constructor. Read multipart/* until last part.
Guido van Rossum7aee3841996-03-07 18:00:44 +0000407
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000408 Arguments, all optional:
Guido van Rossum7aee3841996-03-07 18:00:44 +0000409
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000410 fp : file pointer; default: sys.stdin
Guido van Rossumb1b4f941998-05-08 19:55:51 +0000411 (not used when the request method is GET)
Guido van Rossum7aee3841996-03-07 18:00:44 +0000412
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000413 headers : header dictionary-like object; default:
414 taken from environ as per CGI spec
Guido van Rossum7aee3841996-03-07 18:00:44 +0000415
Guido van Rossum773ab271996-07-23 03:46:24 +0000416 outerboundary : terminating multipart boundary
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000417 (for internal use only)
Guido van Rossum7aee3841996-03-07 18:00:44 +0000418
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000419 environ : environment dictionary; default: os.environ
Guido van Rossum773ab271996-07-23 03:46:24 +0000420
421 keep_blank_values: flag indicating whether blank values in
Tim Peters88869f92001-01-14 23:36:06 +0000422 URL encoded forms should be treated as blank strings.
423 A true value indicates that blanks should be retained as
Guido van Rossum773ab271996-07-23 03:46:24 +0000424 blank strings. The default false value indicates that
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000425 blank values are to be ignored and treated as if they were
426 not included.
Guido van Rossum773ab271996-07-23 03:46:24 +0000427
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000428 strict_parsing: flag indicating what to do with parsing errors.
429 If false (the default), errors are silently ignored.
430 If true, errors raise a ValueError exception.
Guido van Rossume08c04c1996-11-11 19:29:11 +0000431
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000432 """
433 method = 'GET'
434 self.keep_blank_values = keep_blank_values
435 self.strict_parsing = strict_parsing
436 if environ.has_key('REQUEST_METHOD'):
Eric S. Raymond7e9b4f52001-02-09 09:59:10 +0000437 method = environ['REQUEST_METHOD'].upper()
Guido van Rossum01852831998-06-25 02:40:17 +0000438 if method == 'GET' or method == 'HEAD':
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000439 if environ.has_key('QUERY_STRING'):
440 qs = environ['QUERY_STRING']
441 elif sys.argv[1:]:
442 qs = sys.argv[1]
443 else:
444 qs = ""
445 fp = StringIO(qs)
446 if headers is None:
447 headers = {'content-type':
448 "application/x-www-form-urlencoded"}
449 if headers is None:
Guido van Rossumcff311a1998-06-11 14:06:59 +0000450 headers = {}
451 if method == 'POST':
452 # Set default content-type for POST to what's traditional
453 headers['content-type'] = "application/x-www-form-urlencoded"
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000454 if environ.has_key('CONTENT_TYPE'):
455 headers['content-type'] = environ['CONTENT_TYPE']
456 if environ.has_key('CONTENT_LENGTH'):
457 headers['content-length'] = environ['CONTENT_LENGTH']
458 self.fp = fp or sys.stdin
459 self.headers = headers
460 self.outerboundary = outerboundary
Guido van Rossum7aee3841996-03-07 18:00:44 +0000461
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000462 # Process content-disposition header
463 cdisp, pdict = "", {}
464 if self.headers.has_key('content-disposition'):
465 cdisp, pdict = parse_header(self.headers['content-disposition'])
466 self.disposition = cdisp
467 self.disposition_options = pdict
468 self.name = None
469 if pdict.has_key('name'):
470 self.name = pdict['name']
471 self.filename = None
472 if pdict.has_key('filename'):
473 self.filename = pdict['filename']
Guido van Rossum7aee3841996-03-07 18:00:44 +0000474
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000475 # Process content-type header
Barry Warsaw302331a1999-01-08 17:42:03 +0000476 #
477 # Honor any existing content-type header. But if there is no
478 # content-type header, use some sensible defaults. Assume
479 # outerboundary is "" at the outer level, but something non-false
480 # inside a multi-part. The default for an inner part is text/plain,
481 # but for an outer part it should be urlencoded. This should catch
482 # bogus clients which erroneously forget to include a content-type
483 # header.
484 #
485 # See below for what we do if there does exist a content-type header,
486 # but it happens to be something we don't understand.
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000487 if self.headers.has_key('content-type'):
488 ctype, pdict = parse_header(self.headers['content-type'])
Guido van Rossumce900de1999-06-02 18:44:22 +0000489 elif self.outerboundary or method != 'POST':
Barry Warsaw302331a1999-01-08 17:42:03 +0000490 ctype, pdict = "text/plain", {}
491 else:
492 ctype, pdict = 'application/x-www-form-urlencoded', {}
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000493 self.type = ctype
494 self.type_options = pdict
495 self.innerboundary = ""
496 if pdict.has_key('boundary'):
497 self.innerboundary = pdict['boundary']
498 clen = -1
499 if self.headers.has_key('content-length'):
500 try:
Eric S. Raymond7e9b4f52001-02-09 09:59:10 +0000501 clen = int(self.headers['content-length'])
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000502 except:
503 pass
504 if maxlen and clen > maxlen:
505 raise ValueError, 'Maximum content length exceeded'
506 self.length = clen
Guido van Rossum7aee3841996-03-07 18:00:44 +0000507
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000508 self.list = self.file = None
509 self.done = 0
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000510 if ctype == 'application/x-www-form-urlencoded':
511 self.read_urlencoded()
512 elif ctype[:10] == 'multipart/':
Guido van Rossumf5745001998-10-20 14:43:02 +0000513 self.read_multi(environ, keep_blank_values, strict_parsing)
Barry Warsaw302331a1999-01-08 17:42:03 +0000514 else:
Guido van Rossum60a3bd81999-06-11 18:26:09 +0000515 self.read_single()
Guido van Rossum7aee3841996-03-07 18:00:44 +0000516
517 def __repr__(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000518 """Return a printable representation."""
519 return "FieldStorage(%s, %s, %s)" % (
520 `self.name`, `self.filename`, `self.value`)
Guido van Rossum7aee3841996-03-07 18:00:44 +0000521
522 def __getattr__(self, name):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000523 if name != 'value':
524 raise AttributeError, name
525 if self.file:
526 self.file.seek(0)
527 value = self.file.read()
528 self.file.seek(0)
529 elif self.list is not None:
530 value = self.list
531 else:
532 value = None
533 return value
Guido van Rossum7aee3841996-03-07 18:00:44 +0000534
535 def __getitem__(self, key):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000536 """Dictionary style indexing."""
537 if self.list is None:
538 raise TypeError, "not indexable"
539 found = []
540 for item in self.list:
541 if item.name == key: found.append(item)
542 if not found:
543 raise KeyError, key
544 if len(found) == 1:
545 return found[0]
546 else:
547 return found
Guido van Rossum7aee3841996-03-07 18:00:44 +0000548
Moshe Zadkaa1a4b592000-08-25 21:47:56 +0000549 def getvalue(self, key, default=None):
550 """Dictionary style get() method, including 'value' lookup."""
551 if self.has_key(key):
552 value = self[key]
553 if type(value) is type([]):
554 return map(lambda v: v.value, value)
555 else:
556 return value.value
557 else:
558 return default
559
Guido van Rossum7aee3841996-03-07 18:00:44 +0000560 def keys(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000561 """Dictionary style keys() method."""
562 if self.list is None:
563 raise TypeError, "not indexable"
564 keys = []
565 for item in self.list:
566 if item.name not in keys: keys.append(item.name)
567 return keys
Guido van Rossum7aee3841996-03-07 18:00:44 +0000568
Guido van Rossum0147db01996-03-09 03:16:04 +0000569 def has_key(self, key):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000570 """Dictionary style has_key() method."""
571 if self.list is None:
572 raise TypeError, "not indexable"
573 for item in self.list:
574 if item.name == key: return 1
575 return 0
Guido van Rossum0147db01996-03-09 03:16:04 +0000576
Guido van Rossum88b85d41997-01-11 19:21:33 +0000577 def __len__(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000578 """Dictionary style len(x) support."""
579 return len(self.keys())
Guido van Rossum88b85d41997-01-11 19:21:33 +0000580
Guido van Rossum7aee3841996-03-07 18:00:44 +0000581 def read_urlencoded(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000582 """Internal: read data in query string format."""
583 qs = self.fp.read(self.length)
Guido van Rossum1946f0d1999-06-04 17:54:39 +0000584 self.list = list = []
585 for key, value in parse_qsl(qs, self.keep_blank_values,
586 self.strict_parsing):
587 list.append(MiniFieldStorage(key, value))
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000588 self.skip_lines()
Guido van Rossum7aee3841996-03-07 18:00:44 +0000589
Guido van Rossum030d2ec1998-12-09 22:16:46 +0000590 FieldStorageClass = None
591
Guido van Rossumf5745001998-10-20 14:43:02 +0000592 def read_multi(self, environ, keep_blank_values, strict_parsing):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000593 """Internal: read a part that is itself multipart."""
594 self.list = []
Guido van Rossum030d2ec1998-12-09 22:16:46 +0000595 klass = self.FieldStorageClass or self.__class__
596 part = klass(self.fp, {}, self.innerboundary,
597 environ, keep_blank_values, strict_parsing)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000598 # Throw first part away
599 while not part.done:
600 headers = rfc822.Message(self.fp)
Guido van Rossum030d2ec1998-12-09 22:16:46 +0000601 part = klass(self.fp, headers, self.innerboundary,
602 environ, keep_blank_values, strict_parsing)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000603 self.list.append(part)
604 self.skip_lines()
Guido van Rossum7aee3841996-03-07 18:00:44 +0000605
606 def read_single(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000607 """Internal: read an atomic part."""
608 if self.length >= 0:
609 self.read_binary()
610 self.skip_lines()
611 else:
612 self.read_lines()
613 self.file.seek(0)
Guido van Rossum7aee3841996-03-07 18:00:44 +0000614
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000615 bufsize = 8*1024 # I/O buffering size for copy to file
Guido van Rossum7aee3841996-03-07 18:00:44 +0000616
617 def read_binary(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000618 """Internal: read binary data."""
619 self.file = self.make_file('b')
620 todo = self.length
621 if todo >= 0:
622 while todo > 0:
623 data = self.fp.read(min(todo, self.bufsize))
624 if not data:
625 self.done = -1
626 break
627 self.file.write(data)
628 todo = todo - len(data)
Guido van Rossum7aee3841996-03-07 18:00:44 +0000629
630 def read_lines(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000631 """Internal: read lines until EOF or outerboundary."""
632 self.file = self.make_file('')
633 if self.outerboundary:
634 self.read_lines_to_outerboundary()
635 else:
636 self.read_lines_to_eof()
Guido van Rossum7aee3841996-03-07 18:00:44 +0000637
638 def read_lines_to_eof(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000639 """Internal: read lines until EOF."""
640 while 1:
641 line = self.fp.readline()
642 if not line:
643 self.done = -1
644 break
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000645 self.file.write(line)
Guido van Rossum7aee3841996-03-07 18:00:44 +0000646
647 def read_lines_to_outerboundary(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000648 """Internal: read lines until outerboundary."""
649 next = "--" + self.outerboundary
650 last = next + "--"
651 delim = ""
652 while 1:
653 line = self.fp.readline()
654 if not line:
655 self.done = -1
656 break
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000657 if line[:2] == "--":
Eric S. Raymond7e9b4f52001-02-09 09:59:10 +0000658 strippedline = line.strip()
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000659 if strippedline == next:
660 break
661 if strippedline == last:
662 self.done = 1
663 break
664 odelim = delim
665 if line[-2:] == "\r\n":
666 delim = "\r\n"
667 line = line[:-2]
668 elif line[-1] == "\n":
669 delim = "\n"
670 line = line[:-1]
671 else:
672 delim = ""
673 self.file.write(odelim + line)
Guido van Rossum7aee3841996-03-07 18:00:44 +0000674
675 def skip_lines(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000676 """Internal: skip lines until outer boundary if defined."""
677 if not self.outerboundary or self.done:
678 return
679 next = "--" + self.outerboundary
680 last = next + "--"
681 while 1:
682 line = self.fp.readline()
683 if not line:
684 self.done = -1
685 break
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000686 if line[:2] == "--":
Eric S. Raymond7e9b4f52001-02-09 09:59:10 +0000687 strippedline = line.strip()
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000688 if strippedline == next:
689 break
690 if strippedline == last:
691 self.done = 1
692 break
Guido van Rossum7aee3841996-03-07 18:00:44 +0000693
Guido van Rossuma5e9fb61997-08-12 18:18:13 +0000694 def make_file(self, binary=None):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000695 """Overridable: return a readable & writable file.
Guido van Rossum7aee3841996-03-07 18:00:44 +0000696
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000697 The file will be used as follows:
698 - data is written to it
699 - seek(0)
700 - data is read from it
Guido van Rossum7aee3841996-03-07 18:00:44 +0000701
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000702 The 'binary' argument is unused -- the file is always opened
703 in binary mode.
Guido van Rossum7aee3841996-03-07 18:00:44 +0000704
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000705 This version opens a temporary file for reading and writing,
706 and immediately deletes (unlinks) it. The trick (on Unix!) is
707 that the file can still be used, but it can't be opened by
708 another process, and it will automatically be deleted when it
709 is closed or when the current process terminates.
Guido van Rossum4032c2c1996-03-09 04:04:35 +0000710
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000711 If you want a more permanent file, you derive a class which
712 overrides this method. If you want a visible temporary file
713 that is nevertheless automatically deleted when the script
714 terminates, try defining a __del__ method in a derived class
715 which unlinks the temporary files you have created.
Guido van Rossum7aee3841996-03-07 18:00:44 +0000716
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000717 """
718 import tempfile
719 return tempfile.TemporaryFile("w+b")
Tim Peters88869f92001-01-14 23:36:06 +0000720
Guido van Rossum243ddcd1996-03-07 06:33:07 +0000721
722
Guido van Rossum4032c2c1996-03-09 04:04:35 +0000723# Backwards Compatibility Classes
724# ===============================
Guido van Rossum9a22de11995-01-12 12:29:47 +0000725
Moshe Zadkaa1a4b592000-08-25 21:47:56 +0000726class FormContentDict(UserDict.UserDict):
Guido van Rossuma3c6a8a2000-09-19 04:11:46 +0000727 """Form content as dictionary with a list of values per field.
Guido van Rossum72755611996-03-06 07:20:06 +0000728
Guido van Rossum7aee3841996-03-07 18:00:44 +0000729 form = FormContentDict()
730
731 form[key] -> [value, value, ...]
732 form.has_key(key) -> Boolean
733 form.keys() -> [key, key, ...]
734 form.values() -> [[val, val, ...], [val, val, ...], ...]
735 form.items() -> [(key, [val, val, ...]), (key, [val, val, ...]), ...]
736 form.dict == {key: [val, val, ...], ...}
737
738 """
Guido van Rossum773ab271996-07-23 03:46:24 +0000739 def __init__(self, environ=os.environ):
Moshe Zadkaa1a4b592000-08-25 21:47:56 +0000740 self.dict = self.data = parse(environ=environ)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000741 self.query_string = environ['QUERY_STRING']
Guido van Rossum9a22de11995-01-12 12:29:47 +0000742
743
Guido van Rossum9a22de11995-01-12 12:29:47 +0000744class SvFormContentDict(FormContentDict):
Guido van Rossuma3c6a8a2000-09-19 04:11:46 +0000745 """Form content as dictionary expecting a single value per field.
Guido van Rossum7aee3841996-03-07 18:00:44 +0000746
Guido van Rossuma3c6a8a2000-09-19 04:11:46 +0000747 If you only expect a single value for each field, then form[key]
Guido van Rossum7aee3841996-03-07 18:00:44 +0000748 will return that single value. It will raise an IndexError if
Guido van Rossuma3c6a8a2000-09-19 04:11:46 +0000749 that expectation is not true. If you expect a field to have
Guido van Rossum7aee3841996-03-07 18:00:44 +0000750 possible multiple values, than you can use form.getlist(key) to
751 get all of the values. values() and items() are a compromise:
752 they return single strings where there is a single value, and
753 lists of strings otherwise.
754
755 """
756 def __getitem__(self, key):
Tim Peters88869f92001-01-14 23:36:06 +0000757 if len(self.dict[key]) > 1:
758 raise IndexError, 'expecting a single value'
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000759 return self.dict[key][0]
Guido van Rossum7aee3841996-03-07 18:00:44 +0000760 def getlist(self, key):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000761 return self.dict[key]
Guido van Rossum7aee3841996-03-07 18:00:44 +0000762 def values(self):
Guido van Rossuma3c6a8a2000-09-19 04:11:46 +0000763 result = []
764 for value in self.dict.values():
765 if len(value) == 1:
766 result.append(value[0])
767 else: result.append(value)
768 return result
Guido van Rossum7aee3841996-03-07 18:00:44 +0000769 def items(self):
Guido van Rossuma3c6a8a2000-09-19 04:11:46 +0000770 result = []
771 for key, value in self.dict.items():
772 if len(value) == 1:
773 result.append((key, value[0]))
774 else: result.append((key, value))
775 return result
Guido van Rossum9a22de11995-01-12 12:29:47 +0000776
777
Guido van Rossum9a22de11995-01-12 12:29:47 +0000778class InterpFormContentDict(SvFormContentDict):
Tim Peters88869f92001-01-14 23:36:06 +0000779 """This class is present for backwards compatibility only."""
Guido van Rossuma3c6a8a2000-09-19 04:11:46 +0000780 def __getitem__(self, key):
781 v = SvFormContentDict.__getitem__(self, key)
Eric S. Raymond7e9b4f52001-02-09 09:59:10 +0000782 if v[0] in '0123456789+-.':
783 try: return int(v)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000784 except ValueError:
Eric S. Raymond7e9b4f52001-02-09 09:59:10 +0000785 try: return float(v)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000786 except ValueError: pass
Eric S. Raymond7e9b4f52001-02-09 09:59:10 +0000787 return v.strip()
Guido van Rossuma3c6a8a2000-09-19 04:11:46 +0000788 def values(self):
789 result = []
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000790 for key in self.keys():
791 try:
Guido van Rossuma3c6a8a2000-09-19 04:11:46 +0000792 result.append(self[key])
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000793 except IndexError:
Guido van Rossuma3c6a8a2000-09-19 04:11:46 +0000794 result.append(self.dict[key])
795 return result
796 def items(self):
797 result = []
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000798 for key in self.keys():
799 try:
Guido van Rossuma3c6a8a2000-09-19 04:11:46 +0000800 result.append((key, self[key]))
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000801 except IndexError:
Guido van Rossuma3c6a8a2000-09-19 04:11:46 +0000802 result.append((key, self.dict[key]))
803 return result
Guido van Rossum9a22de11995-01-12 12:29:47 +0000804
805
Guido van Rossum9a22de11995-01-12 12:29:47 +0000806class FormContent(FormContentDict):
Tim Peters88869f92001-01-14 23:36:06 +0000807 """This class is present for backwards compatibility only."""
Guido van Rossum0147db01996-03-09 03:16:04 +0000808 def values(self, key):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000809 if self.dict.has_key(key) :return self.dict[key]
810 else: return None
Guido van Rossum0147db01996-03-09 03:16:04 +0000811 def indexed_value(self, key, location):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000812 if self.dict.has_key(key):
Guido van Rossuma3c6a8a2000-09-19 04:11:46 +0000813 if len(self.dict[key]) > location:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000814 return self.dict[key][location]
815 else: return None
816 else: return None
Guido van Rossum0147db01996-03-09 03:16:04 +0000817 def value(self, key):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000818 if self.dict.has_key(key): return self.dict[key][0]
819 else: return None
Guido van Rossum0147db01996-03-09 03:16:04 +0000820 def length(self, key):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000821 return len(self.dict[key])
Guido van Rossum0147db01996-03-09 03:16:04 +0000822 def stripped(self, key):
Eric S. Raymond7e9b4f52001-02-09 09:59:10 +0000823 if self.dict.has_key(key): return self.dict[key][0].strip()
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000824 else: return None
Guido van Rossum7aee3841996-03-07 18:00:44 +0000825 def pars(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000826 return self.dict
Guido van Rossum9a22de11995-01-12 12:29:47 +0000827
828
Guido van Rossum72755611996-03-06 07:20:06 +0000829# Test/debug code
830# ===============
Guido van Rossum9a22de11995-01-12 12:29:47 +0000831
Guido van Rossum773ab271996-07-23 03:46:24 +0000832def test(environ=os.environ):
Guido van Rossum7aee3841996-03-07 18:00:44 +0000833 """Robust test CGI script, usable as main program.
Guido van Rossum9a22de11995-01-12 12:29:47 +0000834
Guido van Rossum7aee3841996-03-07 18:00:44 +0000835 Write minimal HTTP headers and dump all information provided to
836 the script in HTML form.
837
838 """
839 import traceback
840 print "Content-type: text/html"
841 print
842 sys.stderr = sys.stdout
843 try:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000844 form = FieldStorage() # Replace with other classes to test those
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000845 print_directory()
846 print_arguments()
Guido van Rossuma3c6a8a2000-09-19 04:11:46 +0000847 print_form(form)
848 print_environ(environ)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000849 print_environ_usage()
850 def f():
851 exec "testing print_exception() -- <I>italics?</I>"
852 def g(f=f):
853 f()
854 print "<H3>What follows is a test, not an actual exception:</H3>"
855 g()
Guido van Rossum7aee3841996-03-07 18:00:44 +0000856 except:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000857 print_exception()
Guido van Rossumf85de8a1996-08-20 20:22:39 +0000858
Guido van Rossum57d51f22000-09-16 21:16:01 +0000859 print "<H1>Second try with a small maxlen...</H1>"
860
Guido van Rossumad164711997-05-13 19:03:23 +0000861 global maxlen
862 maxlen = 50
863 try:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000864 form = FieldStorage() # Replace with other classes to test those
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000865 print_directory()
866 print_arguments()
Guido van Rossuma3c6a8a2000-09-19 04:11:46 +0000867 print_form(form)
868 print_environ(environ)
Guido van Rossumad164711997-05-13 19:03:23 +0000869 except:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000870 print_exception()
Guido van Rossumad164711997-05-13 19:03:23 +0000871
Guido van Rossumf85de8a1996-08-20 20:22:39 +0000872def print_exception(type=None, value=None, tb=None, limit=None):
873 if type is None:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000874 type, value, tb = sys.exc_info()
Guido van Rossumf85de8a1996-08-20 20:22:39 +0000875 import traceback
876 print
Guido van Rossum7dd06962000-12-27 19:12:58 +0000877 print "<H3>Traceback (most recent call last):</H3>"
Guido van Rossumf85de8a1996-08-20 20:22:39 +0000878 list = traceback.format_tb(tb, limit) + \
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000879 traceback.format_exception_only(type, value)
Guido van Rossumf85de8a1996-08-20 20:22:39 +0000880 print "<PRE>%s<B>%s</B></PRE>" % (
Eric S. Raymond7e9b4f52001-02-09 09:59:10 +0000881 escape("".join(list[:-1])),
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000882 escape(list[-1]),
883 )
Guido van Rossumf15d1591997-09-29 23:22:12 +0000884 del tb
Guido van Rossum9a22de11995-01-12 12:29:47 +0000885
Guido van Rossum773ab271996-07-23 03:46:24 +0000886def print_environ(environ=os.environ):
Guido van Rossum7aee3841996-03-07 18:00:44 +0000887 """Dump the shell environment as HTML."""
888 keys = environ.keys()
889 keys.sort()
890 print
Guido van Rossum503e50b1996-05-28 22:57:20 +0000891 print "<H3>Shell Environment:</H3>"
Guido van Rossum7aee3841996-03-07 18:00:44 +0000892 print "<DL>"
893 for key in keys:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000894 print "<DT>", escape(key), "<DD>", escape(environ[key])
Tim Peters88869f92001-01-14 23:36:06 +0000895 print "</DL>"
Guido van Rossum7aee3841996-03-07 18:00:44 +0000896 print
Guido van Rossum72755611996-03-06 07:20:06 +0000897
898def print_form(form):
Guido van Rossum7aee3841996-03-07 18:00:44 +0000899 """Dump the contents of a form as HTML."""
900 keys = form.keys()
901 keys.sort()
902 print
Guido van Rossum503e50b1996-05-28 22:57:20 +0000903 print "<H3>Form Contents:</H3>"
Guido van Rossum57d51f22000-09-16 21:16:01 +0000904 if not keys:
905 print "<P>No form fields."
Guido van Rossum7aee3841996-03-07 18:00:44 +0000906 print "<DL>"
907 for key in keys:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000908 print "<DT>" + escape(key) + ":",
909 value = form[key]
910 print "<i>" + escape(`type(value)`) + "</i>"
911 print "<DD>" + escape(`value`)
Guido van Rossum7aee3841996-03-07 18:00:44 +0000912 print "</DL>"
913 print
914
915def print_directory():
916 """Dump the current directory as HTML."""
917 print
918 print "<H3>Current Working Directory:</H3>"
919 try:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000920 pwd = os.getcwd()
Guido van Rossum7aee3841996-03-07 18:00:44 +0000921 except os.error, msg:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000922 print "os.error:", escape(str(msg))
Guido van Rossum7aee3841996-03-07 18:00:44 +0000923 else:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000924 print escape(pwd)
Guido van Rossum7aee3841996-03-07 18:00:44 +0000925 print
Guido van Rossum9a22de11995-01-12 12:29:47 +0000926
Guido van Rossuma8738a51996-03-14 21:30:28 +0000927def print_arguments():
928 print
Guido van Rossum503e50b1996-05-28 22:57:20 +0000929 print "<H3>Command Line Arguments:</H3>"
Guido van Rossuma8738a51996-03-14 21:30:28 +0000930 print
931 print sys.argv
932 print
933
Guido van Rossum9a22de11995-01-12 12:29:47 +0000934def print_environ_usage():
Guido van Rossum7aee3841996-03-07 18:00:44 +0000935 """Dump a list of environment variables used by CGI as HTML."""
936 print """
Guido van Rossum72755611996-03-06 07:20:06 +0000937<H3>These environment variables could have been set:</H3>
938<UL>
Guido van Rossum9a22de11995-01-12 12:29:47 +0000939<LI>AUTH_TYPE
940<LI>CONTENT_LENGTH
941<LI>CONTENT_TYPE
942<LI>DATE_GMT
943<LI>DATE_LOCAL
944<LI>DOCUMENT_NAME
945<LI>DOCUMENT_ROOT
946<LI>DOCUMENT_URI
947<LI>GATEWAY_INTERFACE
948<LI>LAST_MODIFIED
949<LI>PATH
950<LI>PATH_INFO
951<LI>PATH_TRANSLATED
952<LI>QUERY_STRING
953<LI>REMOTE_ADDR
954<LI>REMOTE_HOST
955<LI>REMOTE_IDENT
956<LI>REMOTE_USER
957<LI>REQUEST_METHOD
958<LI>SCRIPT_NAME
959<LI>SERVER_NAME
960<LI>SERVER_PORT
961<LI>SERVER_PROTOCOL
962<LI>SERVER_ROOT
963<LI>SERVER_SOFTWARE
964</UL>
Guido van Rossum7aee3841996-03-07 18:00:44 +0000965In addition, HTTP headers sent by the server may be passed in the
966environment as well. Here are some common variable names:
967<UL>
968<LI>HTTP_ACCEPT
969<LI>HTTP_CONNECTION
970<LI>HTTP_HOST
971<LI>HTTP_PRAGMA
972<LI>HTTP_REFERER
973<LI>HTTP_USER_AGENT
974</UL>
Guido van Rossum9a22de11995-01-12 12:29:47 +0000975"""
976
Guido van Rossum9a22de11995-01-12 12:29:47 +0000977
Guido van Rossum72755611996-03-06 07:20:06 +0000978# Utilities
979# =========
Guido van Rossum9a22de11995-01-12 12:29:47 +0000980
Guido van Rossum64c66201997-07-19 20:11:53 +0000981def escape(s, quote=None):
Guido van Rossum7aee3841996-03-07 18:00:44 +0000982 """Replace special characters '&', '<' and '>' by SGML entities."""
Eric S. Raymond7e9b4f52001-02-09 09:59:10 +0000983 s = s.replace("&", "&amp;") # Must be done first!
984 s = s.replace("<", "&lt;")
985 s = s.replace(">", "&gt;")
Guido van Rossum64c66201997-07-19 20:11:53 +0000986 if quote:
Eric S. Raymond7e9b4f52001-02-09 09:59:10 +0000987 s = s.replace('"', "&quot;")
Guido van Rossum7aee3841996-03-07 18:00:44 +0000988 return s
Guido van Rossum9a22de11995-01-12 12:29:47 +0000989
Guido van Rossum9a22de11995-01-12 12:29:47 +0000990
Guido van Rossum72755611996-03-06 07:20:06 +0000991# Invoke mainline
992# ===============
993
994# Call test() when this file is run as a script (not imported as a module)
Tim Peters88869f92001-01-14 23:36:06 +0000995if __name__ == '__main__':
Guido van Rossum7aee3841996-03-07 18:00:44 +0000996 test()