blob: 61b25cd72da1ba12a6a931bf128771493b68868d [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",
Skip Montanaroff443a52001-02-28 01:03:48 +000046 "SvFormContentDict","InterpFormContentDict","FormContent",
47 "escape"]
Guido van Rossumc204c701996-09-05 19:07:11 +000048
49# Logging support
50# ===============
51
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000052logfile = "" # Filename to log to, if not empty
53logfp = None # File object to log to, if not None
Guido van Rossumc204c701996-09-05 19:07:11 +000054
55def initlog(*allargs):
56 """Write a log message, if there is a log file.
57
58 Even though this function is called initlog(), you should always
59 use log(); log is a variable that is set either to initlog
60 (initially), to dolog (once the log file has been opened), or to
61 nolog (when logging is disabled).
62
63 The first argument is a format string; the remaining arguments (if
64 any) are arguments to the % operator, so e.g.
65 log("%s: %s", "a", "b")
66 will write "a: b" to the log file, followed by a newline.
67
68 If the global logfp is not None, it should be a file object to
69 which log data is written.
70
71 If the global logfp is None, the global logfile may be a string
72 giving a filename to open, in append mode. This file should be
73 world writable!!! If the file can't be opened, logging is
74 silently disabled (since there is no safe place where we could
75 send an error message).
76
77 """
78 global logfp, log
79 if logfile and not logfp:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000080 try:
81 logfp = open(logfile, "a")
82 except IOError:
83 pass
Guido van Rossumc204c701996-09-05 19:07:11 +000084 if not logfp:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000085 log = nolog
Guido van Rossumc204c701996-09-05 19:07:11 +000086 else:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000087 log = dolog
Guido van Rossumc204c701996-09-05 19:07:11 +000088 apply(log, allargs)
89
90def dolog(fmt, *args):
91 """Write a log message to the log file. See initlog() for docs."""
92 logfp.write(fmt%args + "\n")
93
94def nolog(*allargs):
95 """Dummy function, assigned to log when logging is disabled."""
96 pass
97
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000098log = initlog # The current logging function
Guido van Rossumc204c701996-09-05 19:07:11 +000099
100
Guido van Rossum72755611996-03-06 07:20:06 +0000101# Parsing functions
102# =================
103
Guido van Rossumad164711997-05-13 19:03:23 +0000104# Maximum input we will accept when REQUEST_METHOD is POST
105# 0 ==> unlimited input
106maxlen = 0
107
Guido van Rossume08c04c1996-11-11 19:29:11 +0000108def parse(fp=None, environ=os.environ, keep_blank_values=0, strict_parsing=0):
Guido van Rossum773ab271996-07-23 03:46:24 +0000109 """Parse a query in the environment or from a file (default stdin)
110
111 Arguments, all optional:
112
113 fp : file pointer; default: sys.stdin
114
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000115 environ : environment dictionary; default: os.environ
Guido van Rossum773ab271996-07-23 03:46:24 +0000116
117 keep_blank_values: flag indicating whether blank values in
Tim Peters88869f92001-01-14 23:36:06 +0000118 URL encoded forms should be treated as blank strings.
119 A true value indicates that blanks should be retained as
Guido van Rossum773ab271996-07-23 03:46:24 +0000120 blank strings. The default false value indicates that
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000121 blank values are to be ignored and treated as if they were
122 not included.
Guido van Rossume08c04c1996-11-11 19:29:11 +0000123
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000124 strict_parsing: flag indicating what to do with parsing errors.
125 If false (the default), errors are silently ignored.
126 If true, errors raise a ValueError exception.
Guido van Rossum773ab271996-07-23 03:46:24 +0000127 """
Guido van Rossum7aee3841996-03-07 18:00:44 +0000128 if not fp:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000129 fp = sys.stdin
Guido van Rossum7aee3841996-03-07 18:00:44 +0000130 if not environ.has_key('REQUEST_METHOD'):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000131 environ['REQUEST_METHOD'] = 'GET' # For testing stand-alone
Guido van Rossum7aee3841996-03-07 18:00:44 +0000132 if environ['REQUEST_METHOD'] == 'POST':
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000133 ctype, pdict = parse_header(environ['CONTENT_TYPE'])
134 if ctype == 'multipart/form-data':
135 return parse_multipart(fp, pdict)
136 elif ctype == 'application/x-www-form-urlencoded':
Eric S. Raymond7e9b4f52001-02-09 09:59:10 +0000137 clength = int(environ['CONTENT_LENGTH'])
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000138 if maxlen and clength > maxlen:
139 raise ValueError, 'Maximum content length exceeded'
140 qs = fp.read(clength)
141 else:
142 qs = '' # Unknown content-type
Tim Peters88869f92001-01-14 23:36:06 +0000143 if environ.has_key('QUERY_STRING'):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000144 if qs: qs = qs + '&'
145 qs = qs + environ['QUERY_STRING']
Tim Peters88869f92001-01-14 23:36:06 +0000146 elif sys.argv[1:]:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000147 if qs: qs = qs + '&'
148 qs = qs + sys.argv[1]
149 environ['QUERY_STRING'] = qs # XXX Shouldn't, really
Guido van Rossum7aee3841996-03-07 18:00:44 +0000150 elif environ.has_key('QUERY_STRING'):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000151 qs = environ['QUERY_STRING']
Guido van Rossum7aee3841996-03-07 18:00:44 +0000152 else:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000153 if sys.argv[1:]:
154 qs = sys.argv[1]
155 else:
156 qs = ""
157 environ['QUERY_STRING'] = qs # XXX Shouldn't, really
Guido van Rossume08c04c1996-11-11 19:29:11 +0000158 return parse_qs(qs, keep_blank_values, strict_parsing)
Guido van Rossume7808771995-08-07 20:12:09 +0000159
160
Guido van Rossume08c04c1996-11-11 19:29:11 +0000161def parse_qs(qs, keep_blank_values=0, strict_parsing=0):
162 """Parse a query given as a string argument.
Guido van Rossum773ab271996-07-23 03:46:24 +0000163
164 Arguments:
165
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000166 qs: URL-encoded query string to be parsed
Guido van Rossum773ab271996-07-23 03:46:24 +0000167
168 keep_blank_values: flag indicating whether blank values in
Tim Peters88869f92001-01-14 23:36:06 +0000169 URL encoded queries should be treated as blank strings.
170 A true value indicates that blanks should be retained as
Guido van Rossum773ab271996-07-23 03:46:24 +0000171 blank strings. The default false value indicates that
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000172 blank values are to be ignored and treated as if they were
173 not included.
Guido van Rossume08c04c1996-11-11 19:29:11 +0000174
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000175 strict_parsing: flag indicating what to do with parsing errors.
176 If false (the default), errors are silently ignored.
177 If true, errors raise a ValueError exception.
Guido van Rossum773ab271996-07-23 03:46:24 +0000178 """
Guido van Rossum7aee3841996-03-07 18:00:44 +0000179 dict = {}
Guido van Rossum1946f0d1999-06-04 17:54:39 +0000180 for name, value in parse_qsl(qs, keep_blank_values, strict_parsing):
Moshe Zadkaa1a4b592000-08-25 21:47:56 +0000181 if dict.has_key(name):
182 dict[name].append(value)
183 else:
184 dict[name] = [value]
Guido van Rossum1946f0d1999-06-04 17:54:39 +0000185 return dict
186
187def parse_qsl(qs, keep_blank_values=0, strict_parsing=0):
188 """Parse a query given as a string argument.
189
Jeremy Hyltonafde7e22000-09-15 20:06:57 +0000190 Arguments:
Guido van Rossum1946f0d1999-06-04 17:54:39 +0000191
Jeremy Hyltonafde7e22000-09-15 20:06:57 +0000192 qs: URL-encoded query string to be parsed
Guido van Rossum1946f0d1999-06-04 17:54:39 +0000193
Jeremy Hyltonafde7e22000-09-15 20:06:57 +0000194 keep_blank_values: flag indicating whether blank values in
195 URL encoded queries should be treated as blank strings. A
196 true value indicates that blanks should be retained as blank
197 strings. The default false value indicates that blank values
198 are to be ignored and treated as if they were not included.
Guido van Rossum1946f0d1999-06-04 17:54:39 +0000199
Jeremy Hyltonafde7e22000-09-15 20:06:57 +0000200 strict_parsing: flag indicating what to do with parsing errors. If
201 false (the default), errors are silently ignored. If true,
Tim Peters88869f92001-01-14 23:36:06 +0000202 errors raise a ValueError exception.
Guido van Rossum1946f0d1999-06-04 17:54:39 +0000203
Jeremy Hyltonafde7e22000-09-15 20:06:57 +0000204 Returns a list, as G-d intended.
Guido van Rossum1946f0d1999-06-04 17:54:39 +0000205 """
Jeremy Hyltonafde7e22000-09-15 20:06:57 +0000206 pairs = [s2 for s1 in qs.split('&') for s2 in s1.split(';')]
207 r = []
208 for name_value in pairs:
209 nv = name_value.split('=', 1)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000210 if len(nv) != 2:
211 if strict_parsing:
212 raise ValueError, "bad query field: %s" % `name_value`
213 continue
Moshe Zadkaa1a4b592000-08-25 21:47:56 +0000214 if len(nv[1]) or keep_blank_values:
Eric S. Raymond7e9b4f52001-02-09 09:59:10 +0000215 name = urllib.unquote(nv[0].replace('+', ' '))
216 value = urllib.unquote(nv[1].replace('+', ' '))
Moshe Zadkaa1a4b592000-08-25 21:47:56 +0000217 r.append((name, value))
Guido van Rossum1946f0d1999-06-04 17:54:39 +0000218
219 return r
Guido van Rossum9a22de11995-01-12 12:29:47 +0000220
221
Guido van Rossum0147db01996-03-09 03:16:04 +0000222def parse_multipart(fp, pdict):
Guido van Rossum7aee3841996-03-07 18:00:44 +0000223 """Parse multipart input.
Guido van Rossum9a22de11995-01-12 12:29:47 +0000224
Guido van Rossum7aee3841996-03-07 18:00:44 +0000225 Arguments:
226 fp : input file
Guido van Rossum7aee3841996-03-07 18:00:44 +0000227 pdict: dictionary containing other parameters of conten-type header
Guido van Rossum72755611996-03-06 07:20:06 +0000228
Tim Peters88869f92001-01-14 23:36:06 +0000229 Returns a dictionary just like parse_qs(): keys are the field names, each
230 value is a list of values for that field. This is easy to use but not
231 much good if you are expecting megabytes to be uploaded -- in that case,
232 use the FieldStorage class instead which is much more flexible. Note
233 that content-type is the raw, unparsed contents of the content-type
Guido van Rossum0147db01996-03-09 03:16:04 +0000234 header.
Tim Peters88869f92001-01-14 23:36:06 +0000235
236 XXX This does not parse nested multipart parts -- use FieldStorage for
Guido van Rossum0147db01996-03-09 03:16:04 +0000237 that.
Tim Peters88869f92001-01-14 23:36:06 +0000238
239 XXX This should really be subsumed by FieldStorage altogether -- no
Guido van Rossum0147db01996-03-09 03:16:04 +0000240 point in having two implementations of the same parsing algorithm.
Guido van Rossum72755611996-03-06 07:20:06 +0000241
Guido van Rossum7aee3841996-03-07 18:00:44 +0000242 """
Guido van Rossum7aee3841996-03-07 18:00:44 +0000243 if pdict.has_key('boundary'):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000244 boundary = pdict['boundary']
Guido van Rossum7aee3841996-03-07 18:00:44 +0000245 else:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000246 boundary = ""
Guido van Rossum7aee3841996-03-07 18:00:44 +0000247 nextpart = "--" + boundary
248 lastpart = "--" + boundary + "--"
249 partdict = {}
250 terminator = ""
251
252 while terminator != lastpart:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000253 bytes = -1
254 data = None
255 if terminator:
256 # At start of next part. Read headers first.
257 headers = mimetools.Message(fp)
258 clength = headers.getheader('content-length')
259 if clength:
260 try:
Eric S. Raymond7e9b4f52001-02-09 09:59:10 +0000261 bytes = int(clength)
262 except ValueError:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000263 pass
264 if bytes > 0:
265 if maxlen and bytes > maxlen:
266 raise ValueError, 'Maximum content length exceeded'
267 data = fp.read(bytes)
268 else:
269 data = ""
270 # Read lines until end of part.
271 lines = []
272 while 1:
273 line = fp.readline()
274 if not line:
275 terminator = lastpart # End outer loop
276 break
277 if line[:2] == "--":
Eric S. Raymond7e9b4f52001-02-09 09:59:10 +0000278 terminator = line.strip()
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000279 if terminator in (nextpart, lastpart):
280 break
281 lines.append(line)
282 # Done with part.
283 if data is None:
284 continue
285 if bytes < 0:
286 if lines:
287 # Strip final line terminator
288 line = lines[-1]
289 if line[-2:] == "\r\n":
290 line = line[:-2]
291 elif line[-1:] == "\n":
292 line = line[:-1]
293 lines[-1] = line
Eric S. Raymond7e9b4f52001-02-09 09:59:10 +0000294 data = "".join(lines)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000295 line = headers['content-disposition']
296 if not line:
297 continue
298 key, params = parse_header(line)
299 if key != 'form-data':
300 continue
301 if params.has_key('name'):
302 name = params['name']
303 else:
304 continue
305 if partdict.has_key(name):
306 partdict[name].append(data)
307 else:
308 partdict[name] = [data]
Guido van Rossum72755611996-03-06 07:20:06 +0000309
Guido van Rossum7aee3841996-03-07 18:00:44 +0000310 return partdict
Guido van Rossum9a22de11995-01-12 12:29:47 +0000311
312
Guido van Rossum72755611996-03-06 07:20:06 +0000313def parse_header(line):
Guido van Rossum7aee3841996-03-07 18:00:44 +0000314 """Parse a Content-type like header.
315
316 Return the main content-type and a dictionary of options.
317
318 """
Eric S. Raymond7e9b4f52001-02-09 09:59:10 +0000319 plist = map(lambda x: x.strip(), line.split(';'))
320 key = plist[0].lower()
Guido van Rossum7aee3841996-03-07 18:00:44 +0000321 del plist[0]
322 pdict = {}
323 for p in plist:
Eric S. Raymond7e9b4f52001-02-09 09:59:10 +0000324 i = p.find('=')
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000325 if i >= 0:
Eric S. Raymond7e9b4f52001-02-09 09:59:10 +0000326 name = p[:i].strip().lower()
327 value = p[i+1:].strip()
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000328 if len(value) >= 2 and value[0] == value[-1] == '"':
329 value = value[1:-1]
330 pdict[name] = value
Guido van Rossum7aee3841996-03-07 18:00:44 +0000331 return key, pdict
Guido van Rossum72755611996-03-06 07:20:06 +0000332
333
Guido van Rossum243ddcd1996-03-07 06:33:07 +0000334# Classes for field storage
335# =========================
336
337class MiniFieldStorage:
338
Guido van Rossum0147db01996-03-09 03:16:04 +0000339 """Like FieldStorage, for use when no file uploads are possible."""
Guido van Rossum243ddcd1996-03-07 06:33:07 +0000340
Guido van Rossum7aee3841996-03-07 18:00:44 +0000341 # Dummy attributes
342 filename = None
343 list = None
344 type = None
Guido van Rossum773ab271996-07-23 03:46:24 +0000345 file = None
Guido van Rossum4032c2c1996-03-09 04:04:35 +0000346 type_options = {}
Guido van Rossum7aee3841996-03-07 18:00:44 +0000347 disposition = None
348 disposition_options = {}
349 headers = {}
Guido van Rossum243ddcd1996-03-07 06:33:07 +0000350
Guido van Rossum7aee3841996-03-07 18:00:44 +0000351 def __init__(self, name, value):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000352 """Constructor from field name and value."""
353 self.name = name
354 self.value = value
Guido van Rossum773ab271996-07-23 03:46:24 +0000355 # self.file = StringIO(value)
Guido van Rossum7aee3841996-03-07 18:00:44 +0000356
357 def __repr__(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000358 """Return printable representation."""
359 return "MiniFieldStorage(%s, %s)" % (`self.name`, `self.value`)
Guido van Rossum243ddcd1996-03-07 06:33:07 +0000360
361
362class FieldStorage:
363
Guido van Rossum7aee3841996-03-07 18:00:44 +0000364 """Store a sequence of fields, reading multipart/form-data.
Guido van Rossum243ddcd1996-03-07 06:33:07 +0000365
Guido van Rossum7aee3841996-03-07 18:00:44 +0000366 This class provides naming, typing, files stored on disk, and
367 more. At the top level, it is accessible like a dictionary, whose
368 keys are the field names. (Note: None can occur as a field name.)
369 The items are either a Python list (if there's multiple values) or
370 another FieldStorage or MiniFieldStorage object. If it's a single
371 object, it has the following attributes:
Guido van Rossum243ddcd1996-03-07 06:33:07 +0000372
Guido van Rossum7aee3841996-03-07 18:00:44 +0000373 name: the field name, if specified; otherwise None
Guido van Rossum243ddcd1996-03-07 06:33:07 +0000374
Guido van Rossum7aee3841996-03-07 18:00:44 +0000375 filename: the filename, if specified; otherwise None; this is the
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000376 client side filename, *not* the file name on which it is
377 stored (that's a temporary file you don't deal with)
Guido van Rossum243ddcd1996-03-07 06:33:07 +0000378
Guido van Rossum7aee3841996-03-07 18:00:44 +0000379 value: the value as a *string*; for file uploads, this
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000380 transparently reads the file every time you request the value
Guido van Rossum7aee3841996-03-07 18:00:44 +0000381
382 file: the file(-like) object from which you can read the data;
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000383 None if the data is stored a simple string
Guido van Rossum7aee3841996-03-07 18:00:44 +0000384
385 type: the content-type, or None if not specified
386
387 type_options: dictionary of options specified on the content-type
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000388 line
Guido van Rossum7aee3841996-03-07 18:00:44 +0000389
390 disposition: content-disposition, or None if not specified
391
392 disposition_options: dictionary of corresponding options
393
394 headers: a dictionary(-like) object (sometimes rfc822.Message or a
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000395 subclass thereof) containing *all* headers
Guido van Rossum7aee3841996-03-07 18:00:44 +0000396
397 The class is subclassable, mostly for the purpose of overriding
398 the make_file() method, which is called internally to come up with
399 a file open for reading and writing. This makes it possible to
400 override the default choice of storing all files in a temporary
401 directory and unlinking them as soon as they have been opened.
402
403 """
404
Guido van Rossum773ab271996-07-23 03:46:24 +0000405 def __init__(self, fp=None, headers=None, outerboundary="",
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000406 environ=os.environ, keep_blank_values=0, strict_parsing=0):
407 """Constructor. Read multipart/* until last part.
Guido van Rossum7aee3841996-03-07 18:00:44 +0000408
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000409 Arguments, all optional:
Guido van Rossum7aee3841996-03-07 18:00:44 +0000410
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000411 fp : file pointer; default: sys.stdin
Guido van Rossumb1b4f941998-05-08 19:55:51 +0000412 (not used when the request method is GET)
Guido van Rossum7aee3841996-03-07 18:00:44 +0000413
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000414 headers : header dictionary-like object; default:
415 taken from environ as per CGI spec
Guido van Rossum7aee3841996-03-07 18:00:44 +0000416
Guido van Rossum773ab271996-07-23 03:46:24 +0000417 outerboundary : terminating multipart boundary
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000418 (for internal use only)
Guido van Rossum7aee3841996-03-07 18:00:44 +0000419
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000420 environ : environment dictionary; default: os.environ
Guido van Rossum773ab271996-07-23 03:46:24 +0000421
422 keep_blank_values: flag indicating whether blank values in
Tim Peters88869f92001-01-14 23:36:06 +0000423 URL encoded forms should be treated as blank strings.
424 A true value indicates that blanks should be retained as
Guido van Rossum773ab271996-07-23 03:46:24 +0000425 blank strings. The default false value indicates that
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000426 blank values are to be ignored and treated as if they were
427 not included.
Guido van Rossum773ab271996-07-23 03:46:24 +0000428
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000429 strict_parsing: flag indicating what to do with parsing errors.
430 If false (the default), errors are silently ignored.
431 If true, errors raise a ValueError exception.
Guido van Rossume08c04c1996-11-11 19:29:11 +0000432
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000433 """
434 method = 'GET'
435 self.keep_blank_values = keep_blank_values
436 self.strict_parsing = strict_parsing
437 if environ.has_key('REQUEST_METHOD'):
Eric S. Raymond7e9b4f52001-02-09 09:59:10 +0000438 method = environ['REQUEST_METHOD'].upper()
Guido van Rossum01852831998-06-25 02:40:17 +0000439 if method == 'GET' or method == 'HEAD':
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000440 if environ.has_key('QUERY_STRING'):
441 qs = environ['QUERY_STRING']
442 elif sys.argv[1:]:
443 qs = sys.argv[1]
444 else:
445 qs = ""
446 fp = StringIO(qs)
447 if headers is None:
448 headers = {'content-type':
449 "application/x-www-form-urlencoded"}
450 if headers is None:
Guido van Rossumcff311a1998-06-11 14:06:59 +0000451 headers = {}
452 if method == 'POST':
453 # Set default content-type for POST to what's traditional
454 headers['content-type'] = "application/x-www-form-urlencoded"
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000455 if environ.has_key('CONTENT_TYPE'):
456 headers['content-type'] = environ['CONTENT_TYPE']
457 if environ.has_key('CONTENT_LENGTH'):
458 headers['content-length'] = environ['CONTENT_LENGTH']
459 self.fp = fp or sys.stdin
460 self.headers = headers
461 self.outerboundary = outerboundary
Guido van Rossum7aee3841996-03-07 18:00:44 +0000462
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000463 # Process content-disposition header
464 cdisp, pdict = "", {}
465 if self.headers.has_key('content-disposition'):
466 cdisp, pdict = parse_header(self.headers['content-disposition'])
467 self.disposition = cdisp
468 self.disposition_options = pdict
469 self.name = None
470 if pdict.has_key('name'):
471 self.name = pdict['name']
472 self.filename = None
473 if pdict.has_key('filename'):
474 self.filename = pdict['filename']
Guido van Rossum7aee3841996-03-07 18:00:44 +0000475
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000476 # Process content-type header
Barry Warsaw302331a1999-01-08 17:42:03 +0000477 #
478 # Honor any existing content-type header. But if there is no
479 # content-type header, use some sensible defaults. Assume
480 # outerboundary is "" at the outer level, but something non-false
481 # inside a multi-part. The default for an inner part is text/plain,
482 # but for an outer part it should be urlencoded. This should catch
483 # bogus clients which erroneously forget to include a content-type
484 # header.
485 #
486 # See below for what we do if there does exist a content-type header,
487 # but it happens to be something we don't understand.
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000488 if self.headers.has_key('content-type'):
489 ctype, pdict = parse_header(self.headers['content-type'])
Guido van Rossumce900de1999-06-02 18:44:22 +0000490 elif self.outerboundary or method != 'POST':
Barry Warsaw302331a1999-01-08 17:42:03 +0000491 ctype, pdict = "text/plain", {}
492 else:
493 ctype, pdict = 'application/x-www-form-urlencoded', {}
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000494 self.type = ctype
495 self.type_options = pdict
496 self.innerboundary = ""
497 if pdict.has_key('boundary'):
498 self.innerboundary = pdict['boundary']
499 clen = -1
500 if self.headers.has_key('content-length'):
501 try:
Eric S. Raymond7e9b4f52001-02-09 09:59:10 +0000502 clen = int(self.headers['content-length'])
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000503 except:
504 pass
505 if maxlen and clen > maxlen:
506 raise ValueError, 'Maximum content length exceeded'
507 self.length = clen
Guido van Rossum7aee3841996-03-07 18:00:44 +0000508
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000509 self.list = self.file = None
510 self.done = 0
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000511 if ctype == 'application/x-www-form-urlencoded':
512 self.read_urlencoded()
513 elif ctype[:10] == 'multipart/':
Guido van Rossumf5745001998-10-20 14:43:02 +0000514 self.read_multi(environ, keep_blank_values, strict_parsing)
Barry Warsaw302331a1999-01-08 17:42:03 +0000515 else:
Guido van Rossum60a3bd81999-06-11 18:26:09 +0000516 self.read_single()
Guido van Rossum7aee3841996-03-07 18:00:44 +0000517
518 def __repr__(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000519 """Return a printable representation."""
520 return "FieldStorage(%s, %s, %s)" % (
521 `self.name`, `self.filename`, `self.value`)
Guido van Rossum7aee3841996-03-07 18:00:44 +0000522
523 def __getattr__(self, name):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000524 if name != 'value':
525 raise AttributeError, name
526 if self.file:
527 self.file.seek(0)
528 value = self.file.read()
529 self.file.seek(0)
530 elif self.list is not None:
531 value = self.list
532 else:
533 value = None
534 return value
Guido van Rossum7aee3841996-03-07 18:00:44 +0000535
536 def __getitem__(self, key):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000537 """Dictionary style indexing."""
538 if self.list is None:
539 raise TypeError, "not indexable"
540 found = []
541 for item in self.list:
542 if item.name == key: found.append(item)
543 if not found:
544 raise KeyError, key
545 if len(found) == 1:
546 return found[0]
547 else:
548 return found
Guido van Rossum7aee3841996-03-07 18:00:44 +0000549
Moshe Zadkaa1a4b592000-08-25 21:47:56 +0000550 def getvalue(self, key, default=None):
551 """Dictionary style get() method, including 'value' lookup."""
552 if self.has_key(key):
553 value = self[key]
554 if type(value) is type([]):
555 return map(lambda v: v.value, value)
556 else:
557 return value.value
558 else:
559 return default
560
Guido van Rossum7aee3841996-03-07 18:00:44 +0000561 def keys(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000562 """Dictionary style keys() method."""
563 if self.list is None:
564 raise TypeError, "not indexable"
565 keys = []
566 for item in self.list:
567 if item.name not in keys: keys.append(item.name)
568 return keys
Guido van Rossum7aee3841996-03-07 18:00:44 +0000569
Guido van Rossum0147db01996-03-09 03:16:04 +0000570 def has_key(self, key):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000571 """Dictionary style has_key() method."""
572 if self.list is None:
573 raise TypeError, "not indexable"
574 for item in self.list:
575 if item.name == key: return 1
576 return 0
Guido van Rossum0147db01996-03-09 03:16:04 +0000577
Guido van Rossum88b85d41997-01-11 19:21:33 +0000578 def __len__(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000579 """Dictionary style len(x) support."""
580 return len(self.keys())
Guido van Rossum88b85d41997-01-11 19:21:33 +0000581
Guido van Rossum7aee3841996-03-07 18:00:44 +0000582 def read_urlencoded(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000583 """Internal: read data in query string format."""
584 qs = self.fp.read(self.length)
Guido van Rossum1946f0d1999-06-04 17:54:39 +0000585 self.list = list = []
586 for key, value in parse_qsl(qs, self.keep_blank_values,
587 self.strict_parsing):
588 list.append(MiniFieldStorage(key, value))
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000589 self.skip_lines()
Guido van Rossum7aee3841996-03-07 18:00:44 +0000590
Guido van Rossum030d2ec1998-12-09 22:16:46 +0000591 FieldStorageClass = None
592
Guido van Rossumf5745001998-10-20 14:43:02 +0000593 def read_multi(self, environ, keep_blank_values, strict_parsing):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000594 """Internal: read a part that is itself multipart."""
595 self.list = []
Guido van Rossum030d2ec1998-12-09 22:16:46 +0000596 klass = self.FieldStorageClass or self.__class__
597 part = klass(self.fp, {}, self.innerboundary,
598 environ, keep_blank_values, strict_parsing)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000599 # Throw first part away
600 while not part.done:
601 headers = rfc822.Message(self.fp)
Guido van Rossum030d2ec1998-12-09 22:16:46 +0000602 part = klass(self.fp, headers, self.innerboundary,
603 environ, keep_blank_values, strict_parsing)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000604 self.list.append(part)
605 self.skip_lines()
Guido van Rossum7aee3841996-03-07 18:00:44 +0000606
607 def read_single(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000608 """Internal: read an atomic part."""
609 if self.length >= 0:
610 self.read_binary()
611 self.skip_lines()
612 else:
613 self.read_lines()
614 self.file.seek(0)
Guido van Rossum7aee3841996-03-07 18:00:44 +0000615
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000616 bufsize = 8*1024 # I/O buffering size for copy to file
Guido van Rossum7aee3841996-03-07 18:00:44 +0000617
618 def read_binary(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000619 """Internal: read binary data."""
620 self.file = self.make_file('b')
621 todo = self.length
622 if todo >= 0:
623 while todo > 0:
624 data = self.fp.read(min(todo, self.bufsize))
625 if not data:
626 self.done = -1
627 break
628 self.file.write(data)
629 todo = todo - len(data)
Guido van Rossum7aee3841996-03-07 18:00:44 +0000630
631 def read_lines(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000632 """Internal: read lines until EOF or outerboundary."""
633 self.file = self.make_file('')
634 if self.outerboundary:
635 self.read_lines_to_outerboundary()
636 else:
637 self.read_lines_to_eof()
Guido van Rossum7aee3841996-03-07 18:00:44 +0000638
639 def read_lines_to_eof(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000640 """Internal: read lines until EOF."""
641 while 1:
642 line = self.fp.readline()
643 if not line:
644 self.done = -1
645 break
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000646 self.file.write(line)
Guido van Rossum7aee3841996-03-07 18:00:44 +0000647
648 def read_lines_to_outerboundary(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000649 """Internal: read lines until outerboundary."""
650 next = "--" + self.outerboundary
651 last = next + "--"
652 delim = ""
653 while 1:
654 line = self.fp.readline()
655 if not line:
656 self.done = -1
657 break
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000658 if line[:2] == "--":
Eric S. Raymond7e9b4f52001-02-09 09:59:10 +0000659 strippedline = line.strip()
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000660 if strippedline == next:
661 break
662 if strippedline == last:
663 self.done = 1
664 break
665 odelim = delim
666 if line[-2:] == "\r\n":
667 delim = "\r\n"
668 line = line[:-2]
669 elif line[-1] == "\n":
670 delim = "\n"
671 line = line[:-1]
672 else:
673 delim = ""
674 self.file.write(odelim + line)
Guido van Rossum7aee3841996-03-07 18:00:44 +0000675
676 def skip_lines(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000677 """Internal: skip lines until outer boundary if defined."""
678 if not self.outerboundary or self.done:
679 return
680 next = "--" + self.outerboundary
681 last = next + "--"
682 while 1:
683 line = self.fp.readline()
684 if not line:
685 self.done = -1
686 break
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000687 if line[:2] == "--":
Eric S. Raymond7e9b4f52001-02-09 09:59:10 +0000688 strippedline = line.strip()
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000689 if strippedline == next:
690 break
691 if strippedline == last:
692 self.done = 1
693 break
Guido van Rossum7aee3841996-03-07 18:00:44 +0000694
Guido van Rossuma5e9fb61997-08-12 18:18:13 +0000695 def make_file(self, binary=None):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000696 """Overridable: return a readable & writable file.
Guido van Rossum7aee3841996-03-07 18:00:44 +0000697
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000698 The file will be used as follows:
699 - data is written to it
700 - seek(0)
701 - data is read from it
Guido van Rossum7aee3841996-03-07 18:00:44 +0000702
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000703 The 'binary' argument is unused -- the file is always opened
704 in binary mode.
Guido van Rossum7aee3841996-03-07 18:00:44 +0000705
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000706 This version opens a temporary file for reading and writing,
707 and immediately deletes (unlinks) it. The trick (on Unix!) is
708 that the file can still be used, but it can't be opened by
709 another process, and it will automatically be deleted when it
710 is closed or when the current process terminates.
Guido van Rossum4032c2c1996-03-09 04:04:35 +0000711
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000712 If you want a more permanent file, you derive a class which
713 overrides this method. If you want a visible temporary file
714 that is nevertheless automatically deleted when the script
715 terminates, try defining a __del__ method in a derived class
716 which unlinks the temporary files you have created.
Guido van Rossum7aee3841996-03-07 18:00:44 +0000717
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000718 """
719 import tempfile
720 return tempfile.TemporaryFile("w+b")
Tim Peters88869f92001-01-14 23:36:06 +0000721
Guido van Rossum243ddcd1996-03-07 06:33:07 +0000722
723
Guido van Rossum4032c2c1996-03-09 04:04:35 +0000724# Backwards Compatibility Classes
725# ===============================
Guido van Rossum9a22de11995-01-12 12:29:47 +0000726
Moshe Zadkaa1a4b592000-08-25 21:47:56 +0000727class FormContentDict(UserDict.UserDict):
Guido van Rossuma3c6a8a2000-09-19 04:11:46 +0000728 """Form content as dictionary with a list of values per field.
Guido van Rossum72755611996-03-06 07:20:06 +0000729
Guido van Rossum7aee3841996-03-07 18:00:44 +0000730 form = FormContentDict()
731
732 form[key] -> [value, value, ...]
733 form.has_key(key) -> Boolean
734 form.keys() -> [key, key, ...]
735 form.values() -> [[val, val, ...], [val, val, ...], ...]
736 form.items() -> [(key, [val, val, ...]), (key, [val, val, ...]), ...]
737 form.dict == {key: [val, val, ...], ...}
738
739 """
Guido van Rossum773ab271996-07-23 03:46:24 +0000740 def __init__(self, environ=os.environ):
Moshe Zadkaa1a4b592000-08-25 21:47:56 +0000741 self.dict = self.data = parse(environ=environ)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000742 self.query_string = environ['QUERY_STRING']
Guido van Rossum9a22de11995-01-12 12:29:47 +0000743
744
Guido van Rossum9a22de11995-01-12 12:29:47 +0000745class SvFormContentDict(FormContentDict):
Guido van Rossuma3c6a8a2000-09-19 04:11:46 +0000746 """Form content as dictionary expecting a single value per field.
Guido van Rossum7aee3841996-03-07 18:00:44 +0000747
Guido van Rossuma3c6a8a2000-09-19 04:11:46 +0000748 If you only expect a single value for each field, then form[key]
Guido van Rossum7aee3841996-03-07 18:00:44 +0000749 will return that single value. It will raise an IndexError if
Guido van Rossuma3c6a8a2000-09-19 04:11:46 +0000750 that expectation is not true. If you expect a field to have
Guido van Rossum7aee3841996-03-07 18:00:44 +0000751 possible multiple values, than you can use form.getlist(key) to
752 get all of the values. values() and items() are a compromise:
753 they return single strings where there is a single value, and
754 lists of strings otherwise.
755
756 """
757 def __getitem__(self, key):
Tim Peters88869f92001-01-14 23:36:06 +0000758 if len(self.dict[key]) > 1:
759 raise IndexError, 'expecting a single value'
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000760 return self.dict[key][0]
Guido van Rossum7aee3841996-03-07 18:00:44 +0000761 def getlist(self, key):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000762 return self.dict[key]
Guido van Rossum7aee3841996-03-07 18:00:44 +0000763 def values(self):
Guido van Rossuma3c6a8a2000-09-19 04:11:46 +0000764 result = []
765 for value in self.dict.values():
766 if len(value) == 1:
767 result.append(value[0])
768 else: result.append(value)
769 return result
Guido van Rossum7aee3841996-03-07 18:00:44 +0000770 def items(self):
Guido van Rossuma3c6a8a2000-09-19 04:11:46 +0000771 result = []
772 for key, value in self.dict.items():
773 if len(value) == 1:
774 result.append((key, value[0]))
775 else: result.append((key, value))
776 return result
Guido van Rossum9a22de11995-01-12 12:29:47 +0000777
778
Guido van Rossum9a22de11995-01-12 12:29:47 +0000779class InterpFormContentDict(SvFormContentDict):
Tim Peters88869f92001-01-14 23:36:06 +0000780 """This class is present for backwards compatibility only."""
Guido van Rossuma3c6a8a2000-09-19 04:11:46 +0000781 def __getitem__(self, key):
782 v = SvFormContentDict.__getitem__(self, key)
Eric S. Raymond7e9b4f52001-02-09 09:59:10 +0000783 if v[0] in '0123456789+-.':
784 try: return int(v)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000785 except ValueError:
Eric S. Raymond7e9b4f52001-02-09 09:59:10 +0000786 try: return float(v)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000787 except ValueError: pass
Eric S. Raymond7e9b4f52001-02-09 09:59:10 +0000788 return v.strip()
Guido van Rossuma3c6a8a2000-09-19 04:11:46 +0000789 def values(self):
790 result = []
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000791 for key in self.keys():
792 try:
Guido van Rossuma3c6a8a2000-09-19 04:11:46 +0000793 result.append(self[key])
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000794 except IndexError:
Guido van Rossuma3c6a8a2000-09-19 04:11:46 +0000795 result.append(self.dict[key])
796 return result
797 def items(self):
798 result = []
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000799 for key in self.keys():
800 try:
Guido van Rossuma3c6a8a2000-09-19 04:11:46 +0000801 result.append((key, self[key]))
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000802 except IndexError:
Guido van Rossuma3c6a8a2000-09-19 04:11:46 +0000803 result.append((key, self.dict[key]))
804 return result
Guido van Rossum9a22de11995-01-12 12:29:47 +0000805
806
Guido van Rossum9a22de11995-01-12 12:29:47 +0000807class FormContent(FormContentDict):
Tim Peters88869f92001-01-14 23:36:06 +0000808 """This class is present for backwards compatibility only."""
Guido van Rossum0147db01996-03-09 03:16:04 +0000809 def values(self, key):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000810 if self.dict.has_key(key) :return self.dict[key]
811 else: return None
Guido van Rossum0147db01996-03-09 03:16:04 +0000812 def indexed_value(self, key, location):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000813 if self.dict.has_key(key):
Guido van Rossuma3c6a8a2000-09-19 04:11:46 +0000814 if len(self.dict[key]) > location:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000815 return self.dict[key][location]
816 else: return None
817 else: return None
Guido van Rossum0147db01996-03-09 03:16:04 +0000818 def value(self, key):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000819 if self.dict.has_key(key): return self.dict[key][0]
820 else: return None
Guido van Rossum0147db01996-03-09 03:16:04 +0000821 def length(self, key):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000822 return len(self.dict[key])
Guido van Rossum0147db01996-03-09 03:16:04 +0000823 def stripped(self, key):
Eric S. Raymond7e9b4f52001-02-09 09:59:10 +0000824 if self.dict.has_key(key): return self.dict[key][0].strip()
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000825 else: return None
Guido van Rossum7aee3841996-03-07 18:00:44 +0000826 def pars(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000827 return self.dict
Guido van Rossum9a22de11995-01-12 12:29:47 +0000828
829
Guido van Rossum72755611996-03-06 07:20:06 +0000830# Test/debug code
831# ===============
Guido van Rossum9a22de11995-01-12 12:29:47 +0000832
Guido van Rossum773ab271996-07-23 03:46:24 +0000833def test(environ=os.environ):
Guido van Rossum7aee3841996-03-07 18:00:44 +0000834 """Robust test CGI script, usable as main program.
Guido van Rossum9a22de11995-01-12 12:29:47 +0000835
Guido van Rossum7aee3841996-03-07 18:00:44 +0000836 Write minimal HTTP headers and dump all information provided to
837 the script in HTML form.
838
839 """
840 import traceback
841 print "Content-type: text/html"
842 print
843 sys.stderr = sys.stdout
844 try:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000845 form = FieldStorage() # Replace with other classes to test those
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000846 print_directory()
847 print_arguments()
Guido van Rossuma3c6a8a2000-09-19 04:11:46 +0000848 print_form(form)
849 print_environ(environ)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000850 print_environ_usage()
851 def f():
852 exec "testing print_exception() -- <I>italics?</I>"
853 def g(f=f):
854 f()
855 print "<H3>What follows is a test, not an actual exception:</H3>"
856 g()
Guido van Rossum7aee3841996-03-07 18:00:44 +0000857 except:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000858 print_exception()
Guido van Rossumf85de8a1996-08-20 20:22:39 +0000859
Guido van Rossum57d51f22000-09-16 21:16:01 +0000860 print "<H1>Second try with a small maxlen...</H1>"
861
Guido van Rossumad164711997-05-13 19:03:23 +0000862 global maxlen
863 maxlen = 50
864 try:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000865 form = FieldStorage() # Replace with other classes to test those
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000866 print_directory()
867 print_arguments()
Guido van Rossuma3c6a8a2000-09-19 04:11:46 +0000868 print_form(form)
869 print_environ(environ)
Guido van Rossumad164711997-05-13 19:03:23 +0000870 except:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000871 print_exception()
Guido van Rossumad164711997-05-13 19:03:23 +0000872
Guido van Rossumf85de8a1996-08-20 20:22:39 +0000873def print_exception(type=None, value=None, tb=None, limit=None):
874 if type is None:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000875 type, value, tb = sys.exc_info()
Guido van Rossumf85de8a1996-08-20 20:22:39 +0000876 import traceback
877 print
Guido van Rossum7dd06962000-12-27 19:12:58 +0000878 print "<H3>Traceback (most recent call last):</H3>"
Guido van Rossumf85de8a1996-08-20 20:22:39 +0000879 list = traceback.format_tb(tb, limit) + \
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000880 traceback.format_exception_only(type, value)
Guido van Rossumf85de8a1996-08-20 20:22:39 +0000881 print "<PRE>%s<B>%s</B></PRE>" % (
Eric S. Raymond7e9b4f52001-02-09 09:59:10 +0000882 escape("".join(list[:-1])),
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000883 escape(list[-1]),
884 )
Guido van Rossumf15d1591997-09-29 23:22:12 +0000885 del tb
Guido van Rossum9a22de11995-01-12 12:29:47 +0000886
Guido van Rossum773ab271996-07-23 03:46:24 +0000887def print_environ(environ=os.environ):
Guido van Rossum7aee3841996-03-07 18:00:44 +0000888 """Dump the shell environment as HTML."""
889 keys = environ.keys()
890 keys.sort()
891 print
Guido van Rossum503e50b1996-05-28 22:57:20 +0000892 print "<H3>Shell Environment:</H3>"
Guido van Rossum7aee3841996-03-07 18:00:44 +0000893 print "<DL>"
894 for key in keys:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000895 print "<DT>", escape(key), "<DD>", escape(environ[key])
Tim Peters88869f92001-01-14 23:36:06 +0000896 print "</DL>"
Guido van Rossum7aee3841996-03-07 18:00:44 +0000897 print
Guido van Rossum72755611996-03-06 07:20:06 +0000898
899def print_form(form):
Guido van Rossum7aee3841996-03-07 18:00:44 +0000900 """Dump the contents of a form as HTML."""
901 keys = form.keys()
902 keys.sort()
903 print
Guido van Rossum503e50b1996-05-28 22:57:20 +0000904 print "<H3>Form Contents:</H3>"
Guido van Rossum57d51f22000-09-16 21:16:01 +0000905 if not keys:
906 print "<P>No form fields."
Guido van Rossum7aee3841996-03-07 18:00:44 +0000907 print "<DL>"
908 for key in keys:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000909 print "<DT>" + escape(key) + ":",
910 value = form[key]
911 print "<i>" + escape(`type(value)`) + "</i>"
912 print "<DD>" + escape(`value`)
Guido van Rossum7aee3841996-03-07 18:00:44 +0000913 print "</DL>"
914 print
915
916def print_directory():
917 """Dump the current directory as HTML."""
918 print
919 print "<H3>Current Working Directory:</H3>"
920 try:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000921 pwd = os.getcwd()
Guido van Rossum7aee3841996-03-07 18:00:44 +0000922 except os.error, msg:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000923 print "os.error:", escape(str(msg))
Guido van Rossum7aee3841996-03-07 18:00:44 +0000924 else:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000925 print escape(pwd)
Guido van Rossum7aee3841996-03-07 18:00:44 +0000926 print
Guido van Rossum9a22de11995-01-12 12:29:47 +0000927
Guido van Rossuma8738a51996-03-14 21:30:28 +0000928def print_arguments():
929 print
Guido van Rossum503e50b1996-05-28 22:57:20 +0000930 print "<H3>Command Line Arguments:</H3>"
Guido van Rossuma8738a51996-03-14 21:30:28 +0000931 print
932 print sys.argv
933 print
934
Guido van Rossum9a22de11995-01-12 12:29:47 +0000935def print_environ_usage():
Guido van Rossum7aee3841996-03-07 18:00:44 +0000936 """Dump a list of environment variables used by CGI as HTML."""
937 print """
Guido van Rossum72755611996-03-06 07:20:06 +0000938<H3>These environment variables could have been set:</H3>
939<UL>
Guido van Rossum9a22de11995-01-12 12:29:47 +0000940<LI>AUTH_TYPE
941<LI>CONTENT_LENGTH
942<LI>CONTENT_TYPE
943<LI>DATE_GMT
944<LI>DATE_LOCAL
945<LI>DOCUMENT_NAME
946<LI>DOCUMENT_ROOT
947<LI>DOCUMENT_URI
948<LI>GATEWAY_INTERFACE
949<LI>LAST_MODIFIED
950<LI>PATH
951<LI>PATH_INFO
952<LI>PATH_TRANSLATED
953<LI>QUERY_STRING
954<LI>REMOTE_ADDR
955<LI>REMOTE_HOST
956<LI>REMOTE_IDENT
957<LI>REMOTE_USER
958<LI>REQUEST_METHOD
959<LI>SCRIPT_NAME
960<LI>SERVER_NAME
961<LI>SERVER_PORT
962<LI>SERVER_PROTOCOL
963<LI>SERVER_ROOT
964<LI>SERVER_SOFTWARE
965</UL>
Guido van Rossum7aee3841996-03-07 18:00:44 +0000966In addition, HTTP headers sent by the server may be passed in the
967environment as well. Here are some common variable names:
968<UL>
969<LI>HTTP_ACCEPT
970<LI>HTTP_CONNECTION
971<LI>HTTP_HOST
972<LI>HTTP_PRAGMA
973<LI>HTTP_REFERER
974<LI>HTTP_USER_AGENT
975</UL>
Guido van Rossum9a22de11995-01-12 12:29:47 +0000976"""
977
Guido van Rossum9a22de11995-01-12 12:29:47 +0000978
Guido van Rossum72755611996-03-06 07:20:06 +0000979# Utilities
980# =========
Guido van Rossum9a22de11995-01-12 12:29:47 +0000981
Guido van Rossum64c66201997-07-19 20:11:53 +0000982def escape(s, quote=None):
Guido van Rossum7aee3841996-03-07 18:00:44 +0000983 """Replace special characters '&', '<' and '>' by SGML entities."""
Eric S. Raymond7e9b4f52001-02-09 09:59:10 +0000984 s = s.replace("&", "&amp;") # Must be done first!
985 s = s.replace("<", "&lt;")
986 s = s.replace(">", "&gt;")
Guido van Rossum64c66201997-07-19 20:11:53 +0000987 if quote:
Eric S. Raymond7e9b4f52001-02-09 09:59:10 +0000988 s = s.replace('"', "&quot;")
Guido van Rossum7aee3841996-03-07 18:00:44 +0000989 return s
Guido van Rossum9a22de11995-01-12 12:29:47 +0000990
Guido van Rossum9a22de11995-01-12 12:29:47 +0000991
Guido van Rossum72755611996-03-06 07:20:06 +0000992# Invoke mainline
993# ===============
994
995# Call test() when this file is run as a script (not imported as a module)
Tim Peters88869f92001-01-14 23:36:06 +0000996if __name__ == '__main__':
Guido van Rossum7aee3841996-03-07 18:00:44 +0000997 test()