blob: 0e808a5acb97524871eca75212ef5a3f32c76d36 [file] [log] [blame]
Guido van Rossum51914632000-10-03 13:51:09 +00001#! /usr/local/bin/python
Guido van Rossum1c9daa81995-09-18 21:52:37 +00002
Guido van Rossum72755611996-03-06 07:20:06 +00003"""Support module for CGI (Common Gateway Interface) scripts.
Guido van Rossum1c9daa81995-09-18 21:52:37 +00004
Guido van Rossum7aee3841996-03-07 18:00:44 +00005This module defines a number of utilities for use by CGI scripts
6written in Python.
Guido van Rossum72755611996-03-06 07:20:06 +00007"""
8
Jeremy Hyltonc253d9a2000-08-03 20:57:44 +00009# XXX Perhaps there should be a slimmed version that doesn't contain
10# all those backwards compatible and debugging classes and functions?
Guido van Rossum98d9fd32000-02-28 15:12:25 +000011
12# History
13# -------
Tim Peters88869f92001-01-14 23:36:06 +000014#
Guido van Rossum98d9fd32000-02-28 15:12:25 +000015# Michael McLay started this module. Steve Majewski changed the
16# interface to SvFormContentDict and FormContentDict. The multipart
17# parsing was inspired by code submitted by Andreas Paepcke. Guido van
18# Rossum rewrote, reformatted and documented the module and is currently
19# responsible for its maintenance.
Tim Peters88869f92001-01-14 23:36:06 +000020#
Guido van Rossum98d9fd32000-02-28 15:12:25 +000021
Barry Warsaw7fed2172000-11-06 18:46:09 +000022__version__ = "2.5"
Guido van Rossum0147db01996-03-09 03:16:04 +000023
Guido van Rossum72755611996-03-06 07:20:06 +000024
25# Imports
26# =======
27
28import string
Guido van Rossum72755611996-03-06 07:20:06 +000029import sys
30import os
Guido van Rossuma5e9fb61997-08-12 18:18:13 +000031import urllib
Guido van Rossuma5e9fb61997-08-12 18:18:13 +000032import mimetools
33import rfc822
Moshe Zadkaa1a4b592000-08-25 21:47:56 +000034import UserDict
Guido van Rossuma5e9fb61997-08-12 18:18:13 +000035from StringIO import StringIO
Guido van Rossum72755611996-03-06 07:20:06 +000036
Skip Montanaroe99d5ea2001-01-20 19:54:20 +000037__all__ = ["MiniFieldStorage","FieldStorage","FormContentDict",
38 "SvFormContentDict","InterpFormContentDict","FormContent"]
Guido van Rossumc204c701996-09-05 19:07:11 +000039
40# Logging support
41# ===============
42
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000043logfile = "" # Filename to log to, if not empty
44logfp = None # File object to log to, if not None
Guido van Rossumc204c701996-09-05 19:07:11 +000045
46def initlog(*allargs):
47 """Write a log message, if there is a log file.
48
49 Even though this function is called initlog(), you should always
50 use log(); log is a variable that is set either to initlog
51 (initially), to dolog (once the log file has been opened), or to
52 nolog (when logging is disabled).
53
54 The first argument is a format string; the remaining arguments (if
55 any) are arguments to the % operator, so e.g.
56 log("%s: %s", "a", "b")
57 will write "a: b" to the log file, followed by a newline.
58
59 If the global logfp is not None, it should be a file object to
60 which log data is written.
61
62 If the global logfp is None, the global logfile may be a string
63 giving a filename to open, in append mode. This file should be
64 world writable!!! If the file can't be opened, logging is
65 silently disabled (since there is no safe place where we could
66 send an error message).
67
68 """
69 global logfp, log
70 if logfile and not logfp:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000071 try:
72 logfp = open(logfile, "a")
73 except IOError:
74 pass
Guido van Rossumc204c701996-09-05 19:07:11 +000075 if not logfp:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000076 log = nolog
Guido van Rossumc204c701996-09-05 19:07:11 +000077 else:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000078 log = dolog
Guido van Rossumc204c701996-09-05 19:07:11 +000079 apply(log, allargs)
80
81def dolog(fmt, *args):
82 """Write a log message to the log file. See initlog() for docs."""
83 logfp.write(fmt%args + "\n")
84
85def nolog(*allargs):
86 """Dummy function, assigned to log when logging is disabled."""
87 pass
88
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000089log = initlog # The current logging function
Guido van Rossumc204c701996-09-05 19:07:11 +000090
91
Guido van Rossum72755611996-03-06 07:20:06 +000092# Parsing functions
93# =================
94
Guido van Rossumad164711997-05-13 19:03:23 +000095# Maximum input we will accept when REQUEST_METHOD is POST
96# 0 ==> unlimited input
97maxlen = 0
98
Guido van Rossume08c04c1996-11-11 19:29:11 +000099def parse(fp=None, environ=os.environ, keep_blank_values=0, strict_parsing=0):
Guido van Rossum773ab271996-07-23 03:46:24 +0000100 """Parse a query in the environment or from a file (default stdin)
101
102 Arguments, all optional:
103
104 fp : file pointer; default: sys.stdin
105
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000106 environ : environment dictionary; default: os.environ
Guido van Rossum773ab271996-07-23 03:46:24 +0000107
108 keep_blank_values: flag indicating whether blank values in
Tim Peters88869f92001-01-14 23:36:06 +0000109 URL encoded forms should be treated as blank strings.
110 A true value indicates that blanks should be retained as
Guido van Rossum773ab271996-07-23 03:46:24 +0000111 blank strings. The default false value indicates that
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000112 blank values are to be ignored and treated as if they were
113 not included.
Guido van Rossume08c04c1996-11-11 19:29:11 +0000114
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000115 strict_parsing: flag indicating what to do with parsing errors.
116 If false (the default), errors are silently ignored.
117 If true, errors raise a ValueError exception.
Guido van Rossum773ab271996-07-23 03:46:24 +0000118 """
Guido van Rossum7aee3841996-03-07 18:00:44 +0000119 if not fp:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000120 fp = sys.stdin
Guido van Rossum7aee3841996-03-07 18:00:44 +0000121 if not environ.has_key('REQUEST_METHOD'):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000122 environ['REQUEST_METHOD'] = 'GET' # For testing stand-alone
Guido van Rossum7aee3841996-03-07 18:00:44 +0000123 if environ['REQUEST_METHOD'] == 'POST':
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000124 ctype, pdict = parse_header(environ['CONTENT_TYPE'])
125 if ctype == 'multipart/form-data':
126 return parse_multipart(fp, pdict)
127 elif ctype == 'application/x-www-form-urlencoded':
128 clength = string.atoi(environ['CONTENT_LENGTH'])
129 if maxlen and clength > maxlen:
130 raise ValueError, 'Maximum content length exceeded'
131 qs = fp.read(clength)
132 else:
133 qs = '' # Unknown content-type
Tim Peters88869f92001-01-14 23:36:06 +0000134 if environ.has_key('QUERY_STRING'):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000135 if qs: qs = qs + '&'
136 qs = qs + environ['QUERY_STRING']
Tim Peters88869f92001-01-14 23:36:06 +0000137 elif sys.argv[1:]:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000138 if qs: qs = qs + '&'
139 qs = qs + sys.argv[1]
140 environ['QUERY_STRING'] = qs # XXX Shouldn't, really
Guido van Rossum7aee3841996-03-07 18:00:44 +0000141 elif environ.has_key('QUERY_STRING'):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000142 qs = environ['QUERY_STRING']
Guido van Rossum7aee3841996-03-07 18:00:44 +0000143 else:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000144 if sys.argv[1:]:
145 qs = sys.argv[1]
146 else:
147 qs = ""
148 environ['QUERY_STRING'] = qs # XXX Shouldn't, really
Guido van Rossume08c04c1996-11-11 19:29:11 +0000149 return parse_qs(qs, keep_blank_values, strict_parsing)
Guido van Rossume7808771995-08-07 20:12:09 +0000150
151
Guido van Rossume08c04c1996-11-11 19:29:11 +0000152def parse_qs(qs, keep_blank_values=0, strict_parsing=0):
153 """Parse a query given as a string argument.
Guido van Rossum773ab271996-07-23 03:46:24 +0000154
155 Arguments:
156
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000157 qs: URL-encoded query string to be parsed
Guido van Rossum773ab271996-07-23 03:46:24 +0000158
159 keep_blank_values: flag indicating whether blank values in
Tim Peters88869f92001-01-14 23:36:06 +0000160 URL encoded queries should be treated as blank strings.
161 A true value indicates that blanks should be retained as
Guido van Rossum773ab271996-07-23 03:46:24 +0000162 blank strings. The default false value indicates that
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000163 blank values are to be ignored and treated as if they were
164 not included.
Guido van Rossume08c04c1996-11-11 19:29:11 +0000165
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000166 strict_parsing: flag indicating what to do with parsing errors.
167 If false (the default), errors are silently ignored.
168 If true, errors raise a ValueError exception.
Guido van Rossum773ab271996-07-23 03:46:24 +0000169 """
Guido van Rossum7aee3841996-03-07 18:00:44 +0000170 dict = {}
Guido van Rossum1946f0d1999-06-04 17:54:39 +0000171 for name, value in parse_qsl(qs, keep_blank_values, strict_parsing):
Moshe Zadkaa1a4b592000-08-25 21:47:56 +0000172 if dict.has_key(name):
173 dict[name].append(value)
174 else:
175 dict[name] = [value]
Guido van Rossum1946f0d1999-06-04 17:54:39 +0000176 return dict
177
178def parse_qsl(qs, keep_blank_values=0, strict_parsing=0):
179 """Parse a query given as a string argument.
180
Jeremy Hyltonafde7e22000-09-15 20:06:57 +0000181 Arguments:
Guido van Rossum1946f0d1999-06-04 17:54:39 +0000182
Jeremy Hyltonafde7e22000-09-15 20:06:57 +0000183 qs: URL-encoded query string to be parsed
Guido van Rossum1946f0d1999-06-04 17:54:39 +0000184
Jeremy Hyltonafde7e22000-09-15 20:06:57 +0000185 keep_blank_values: flag indicating whether blank values in
186 URL encoded queries should be treated as blank strings. A
187 true value indicates that blanks should be retained as blank
188 strings. The default false value indicates that blank values
189 are to be ignored and treated as if they were not included.
Guido van Rossum1946f0d1999-06-04 17:54:39 +0000190
Jeremy Hyltonafde7e22000-09-15 20:06:57 +0000191 strict_parsing: flag indicating what to do with parsing errors. If
192 false (the default), errors are silently ignored. If true,
Tim Peters88869f92001-01-14 23:36:06 +0000193 errors raise a ValueError exception.
Guido van Rossum1946f0d1999-06-04 17:54:39 +0000194
Jeremy Hyltonafde7e22000-09-15 20:06:57 +0000195 Returns a list, as G-d intended.
Guido van Rossum1946f0d1999-06-04 17:54:39 +0000196 """
Jeremy Hyltonafde7e22000-09-15 20:06:57 +0000197 pairs = [s2 for s1 in qs.split('&') for s2 in s1.split(';')]
198 r = []
199 for name_value in pairs:
200 nv = name_value.split('=', 1)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000201 if len(nv) != 2:
202 if strict_parsing:
203 raise ValueError, "bad query field: %s" % `name_value`
204 continue
Moshe Zadkaa1a4b592000-08-25 21:47:56 +0000205 if len(nv[1]) or keep_blank_values:
206 name = urllib.unquote(string.replace(nv[0], '+', ' '))
207 value = urllib.unquote(string.replace(nv[1], '+', ' '))
208 r.append((name, value))
Guido van Rossum1946f0d1999-06-04 17:54:39 +0000209
210 return r
Guido van Rossum9a22de11995-01-12 12:29:47 +0000211
212
Guido van Rossum0147db01996-03-09 03:16:04 +0000213def parse_multipart(fp, pdict):
Guido van Rossum7aee3841996-03-07 18:00:44 +0000214 """Parse multipart input.
Guido van Rossum9a22de11995-01-12 12:29:47 +0000215
Guido van Rossum7aee3841996-03-07 18:00:44 +0000216 Arguments:
217 fp : input file
Guido van Rossum7aee3841996-03-07 18:00:44 +0000218 pdict: dictionary containing other parameters of conten-type header
Guido van Rossum72755611996-03-06 07:20:06 +0000219
Tim Peters88869f92001-01-14 23:36:06 +0000220 Returns a dictionary just like parse_qs(): keys are the field names, each
221 value is a list of values for that field. This is easy to use but not
222 much good if you are expecting megabytes to be uploaded -- in that case,
223 use the FieldStorage class instead which is much more flexible. Note
224 that content-type is the raw, unparsed contents of the content-type
Guido van Rossum0147db01996-03-09 03:16:04 +0000225 header.
Tim Peters88869f92001-01-14 23:36:06 +0000226
227 XXX This does not parse nested multipart parts -- use FieldStorage for
Guido van Rossum0147db01996-03-09 03:16:04 +0000228 that.
Tim Peters88869f92001-01-14 23:36:06 +0000229
230 XXX This should really be subsumed by FieldStorage altogether -- no
Guido van Rossum0147db01996-03-09 03:16:04 +0000231 point in having two implementations of the same parsing algorithm.
Guido van Rossum72755611996-03-06 07:20:06 +0000232
Guido van Rossum7aee3841996-03-07 18:00:44 +0000233 """
Guido van Rossum7aee3841996-03-07 18:00:44 +0000234 if pdict.has_key('boundary'):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000235 boundary = pdict['boundary']
Guido van Rossum7aee3841996-03-07 18:00:44 +0000236 else:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000237 boundary = ""
Guido van Rossum7aee3841996-03-07 18:00:44 +0000238 nextpart = "--" + boundary
239 lastpart = "--" + boundary + "--"
240 partdict = {}
241 terminator = ""
242
243 while terminator != lastpart:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000244 bytes = -1
245 data = None
246 if terminator:
247 # At start of next part. Read headers first.
248 headers = mimetools.Message(fp)
249 clength = headers.getheader('content-length')
250 if clength:
251 try:
252 bytes = string.atoi(clength)
253 except string.atoi_error:
254 pass
255 if bytes > 0:
256 if maxlen and bytes > maxlen:
257 raise ValueError, 'Maximum content length exceeded'
258 data = fp.read(bytes)
259 else:
260 data = ""
261 # Read lines until end of part.
262 lines = []
263 while 1:
264 line = fp.readline()
265 if not line:
266 terminator = lastpart # End outer loop
267 break
268 if line[:2] == "--":
269 terminator = string.strip(line)
270 if terminator in (nextpart, lastpart):
271 break
272 lines.append(line)
273 # Done with part.
274 if data is None:
275 continue
276 if bytes < 0:
277 if lines:
278 # Strip final line terminator
279 line = lines[-1]
280 if line[-2:] == "\r\n":
281 line = line[:-2]
282 elif line[-1:] == "\n":
283 line = line[:-1]
284 lines[-1] = line
285 data = string.joinfields(lines, "")
286 line = headers['content-disposition']
287 if not line:
288 continue
289 key, params = parse_header(line)
290 if key != 'form-data':
291 continue
292 if params.has_key('name'):
293 name = params['name']
294 else:
295 continue
296 if partdict.has_key(name):
297 partdict[name].append(data)
298 else:
299 partdict[name] = [data]
Guido van Rossum72755611996-03-06 07:20:06 +0000300
Guido van Rossum7aee3841996-03-07 18:00:44 +0000301 return partdict
Guido van Rossum9a22de11995-01-12 12:29:47 +0000302
303
Guido van Rossum72755611996-03-06 07:20:06 +0000304def parse_header(line):
Guido van Rossum7aee3841996-03-07 18:00:44 +0000305 """Parse a Content-type like header.
306
307 Return the main content-type and a dictionary of options.
308
309 """
310 plist = map(string.strip, string.splitfields(line, ';'))
311 key = string.lower(plist[0])
312 del plist[0]
313 pdict = {}
314 for p in plist:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000315 i = string.find(p, '=')
316 if i >= 0:
317 name = string.lower(string.strip(p[:i]))
318 value = string.strip(p[i+1:])
319 if len(value) >= 2 and value[0] == value[-1] == '"':
320 value = value[1:-1]
321 pdict[name] = value
Guido van Rossum7aee3841996-03-07 18:00:44 +0000322 return key, pdict
Guido van Rossum72755611996-03-06 07:20:06 +0000323
324
Guido van Rossum243ddcd1996-03-07 06:33:07 +0000325# Classes for field storage
326# =========================
327
328class MiniFieldStorage:
329
Guido van Rossum0147db01996-03-09 03:16:04 +0000330 """Like FieldStorage, for use when no file uploads are possible."""
Guido van Rossum243ddcd1996-03-07 06:33:07 +0000331
Guido van Rossum7aee3841996-03-07 18:00:44 +0000332 # Dummy attributes
333 filename = None
334 list = None
335 type = None
Guido van Rossum773ab271996-07-23 03:46:24 +0000336 file = None
Guido van Rossum4032c2c1996-03-09 04:04:35 +0000337 type_options = {}
Guido van Rossum7aee3841996-03-07 18:00:44 +0000338 disposition = None
339 disposition_options = {}
340 headers = {}
Guido van Rossum243ddcd1996-03-07 06:33:07 +0000341
Guido van Rossum7aee3841996-03-07 18:00:44 +0000342 def __init__(self, name, value):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000343 """Constructor from field name and value."""
344 self.name = name
345 self.value = value
Guido van Rossum773ab271996-07-23 03:46:24 +0000346 # self.file = StringIO(value)
Guido van Rossum7aee3841996-03-07 18:00:44 +0000347
348 def __repr__(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000349 """Return printable representation."""
350 return "MiniFieldStorage(%s, %s)" % (`self.name`, `self.value`)
Guido van Rossum243ddcd1996-03-07 06:33:07 +0000351
352
353class FieldStorage:
354
Guido van Rossum7aee3841996-03-07 18:00:44 +0000355 """Store a sequence of fields, reading multipart/form-data.
Guido van Rossum243ddcd1996-03-07 06:33:07 +0000356
Guido van Rossum7aee3841996-03-07 18:00:44 +0000357 This class provides naming, typing, files stored on disk, and
358 more. At the top level, it is accessible like a dictionary, whose
359 keys are the field names. (Note: None can occur as a field name.)
360 The items are either a Python list (if there's multiple values) or
361 another FieldStorage or MiniFieldStorage object. If it's a single
362 object, it has the following attributes:
Guido van Rossum243ddcd1996-03-07 06:33:07 +0000363
Guido van Rossum7aee3841996-03-07 18:00:44 +0000364 name: the field name, if specified; otherwise None
Guido van Rossum243ddcd1996-03-07 06:33:07 +0000365
Guido van Rossum7aee3841996-03-07 18:00:44 +0000366 filename: the filename, if specified; otherwise None; this is the
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000367 client side filename, *not* the file name on which it is
368 stored (that's a temporary file you don't deal with)
Guido van Rossum243ddcd1996-03-07 06:33:07 +0000369
Guido van Rossum7aee3841996-03-07 18:00:44 +0000370 value: the value as a *string*; for file uploads, this
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000371 transparently reads the file every time you request the value
Guido van Rossum7aee3841996-03-07 18:00:44 +0000372
373 file: the file(-like) object from which you can read the data;
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000374 None if the data is stored a simple string
Guido van Rossum7aee3841996-03-07 18:00:44 +0000375
376 type: the content-type, or None if not specified
377
378 type_options: dictionary of options specified on the content-type
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000379 line
Guido van Rossum7aee3841996-03-07 18:00:44 +0000380
381 disposition: content-disposition, or None if not specified
382
383 disposition_options: dictionary of corresponding options
384
385 headers: a dictionary(-like) object (sometimes rfc822.Message or a
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000386 subclass thereof) containing *all* headers
Guido van Rossum7aee3841996-03-07 18:00:44 +0000387
388 The class is subclassable, mostly for the purpose of overriding
389 the make_file() method, which is called internally to come up with
390 a file open for reading and writing. This makes it possible to
391 override the default choice of storing all files in a temporary
392 directory and unlinking them as soon as they have been opened.
393
394 """
395
Guido van Rossum773ab271996-07-23 03:46:24 +0000396 def __init__(self, fp=None, headers=None, outerboundary="",
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000397 environ=os.environ, keep_blank_values=0, strict_parsing=0):
398 """Constructor. Read multipart/* until last part.
Guido van Rossum7aee3841996-03-07 18:00:44 +0000399
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000400 Arguments, all optional:
Guido van Rossum7aee3841996-03-07 18:00:44 +0000401
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000402 fp : file pointer; default: sys.stdin
Guido van Rossumb1b4f941998-05-08 19:55:51 +0000403 (not used when the request method is GET)
Guido van Rossum7aee3841996-03-07 18:00:44 +0000404
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000405 headers : header dictionary-like object; default:
406 taken from environ as per CGI spec
Guido van Rossum7aee3841996-03-07 18:00:44 +0000407
Guido van Rossum773ab271996-07-23 03:46:24 +0000408 outerboundary : terminating multipart boundary
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000409 (for internal use only)
Guido van Rossum7aee3841996-03-07 18:00:44 +0000410
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000411 environ : environment dictionary; default: os.environ
Guido van Rossum773ab271996-07-23 03:46:24 +0000412
413 keep_blank_values: flag indicating whether blank values in
Tim Peters88869f92001-01-14 23:36:06 +0000414 URL encoded forms should be treated as blank strings.
415 A true value indicates that blanks should be retained as
Guido van Rossum773ab271996-07-23 03:46:24 +0000416 blank strings. The default false value indicates that
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000417 blank values are to be ignored and treated as if they were
418 not included.
Guido van Rossum773ab271996-07-23 03:46:24 +0000419
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000420 strict_parsing: flag indicating what to do with parsing errors.
421 If false (the default), errors are silently ignored.
422 If true, errors raise a ValueError exception.
Guido van Rossume08c04c1996-11-11 19:29:11 +0000423
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000424 """
425 method = 'GET'
426 self.keep_blank_values = keep_blank_values
427 self.strict_parsing = strict_parsing
428 if environ.has_key('REQUEST_METHOD'):
429 method = string.upper(environ['REQUEST_METHOD'])
Guido van Rossum01852831998-06-25 02:40:17 +0000430 if method == 'GET' or method == 'HEAD':
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000431 if environ.has_key('QUERY_STRING'):
432 qs = environ['QUERY_STRING']
433 elif sys.argv[1:]:
434 qs = sys.argv[1]
435 else:
436 qs = ""
437 fp = StringIO(qs)
438 if headers is None:
439 headers = {'content-type':
440 "application/x-www-form-urlencoded"}
441 if headers is None:
Guido van Rossumcff311a1998-06-11 14:06:59 +0000442 headers = {}
443 if method == 'POST':
444 # Set default content-type for POST to what's traditional
445 headers['content-type'] = "application/x-www-form-urlencoded"
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000446 if environ.has_key('CONTENT_TYPE'):
447 headers['content-type'] = environ['CONTENT_TYPE']
448 if environ.has_key('CONTENT_LENGTH'):
449 headers['content-length'] = environ['CONTENT_LENGTH']
450 self.fp = fp or sys.stdin
451 self.headers = headers
452 self.outerboundary = outerboundary
Guido van Rossum7aee3841996-03-07 18:00:44 +0000453
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000454 # Process content-disposition header
455 cdisp, pdict = "", {}
456 if self.headers.has_key('content-disposition'):
457 cdisp, pdict = parse_header(self.headers['content-disposition'])
458 self.disposition = cdisp
459 self.disposition_options = pdict
460 self.name = None
461 if pdict.has_key('name'):
462 self.name = pdict['name']
463 self.filename = None
464 if pdict.has_key('filename'):
465 self.filename = pdict['filename']
Guido van Rossum7aee3841996-03-07 18:00:44 +0000466
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000467 # Process content-type header
Barry Warsaw302331a1999-01-08 17:42:03 +0000468 #
469 # Honor any existing content-type header. But if there is no
470 # content-type header, use some sensible defaults. Assume
471 # outerboundary is "" at the outer level, but something non-false
472 # inside a multi-part. The default for an inner part is text/plain,
473 # but for an outer part it should be urlencoded. This should catch
474 # bogus clients which erroneously forget to include a content-type
475 # header.
476 #
477 # See below for what we do if there does exist a content-type header,
478 # but it happens to be something we don't understand.
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000479 if self.headers.has_key('content-type'):
480 ctype, pdict = parse_header(self.headers['content-type'])
Guido van Rossumce900de1999-06-02 18:44:22 +0000481 elif self.outerboundary or method != 'POST':
Barry Warsaw302331a1999-01-08 17:42:03 +0000482 ctype, pdict = "text/plain", {}
483 else:
484 ctype, pdict = 'application/x-www-form-urlencoded', {}
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000485 self.type = ctype
486 self.type_options = pdict
487 self.innerboundary = ""
488 if pdict.has_key('boundary'):
489 self.innerboundary = pdict['boundary']
490 clen = -1
491 if self.headers.has_key('content-length'):
492 try:
493 clen = string.atoi(self.headers['content-length'])
494 except:
495 pass
496 if maxlen and clen > maxlen:
497 raise ValueError, 'Maximum content length exceeded'
498 self.length = clen
Guido van Rossum7aee3841996-03-07 18:00:44 +0000499
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000500 self.list = self.file = None
501 self.done = 0
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000502 if ctype == 'application/x-www-form-urlencoded':
503 self.read_urlencoded()
504 elif ctype[:10] == 'multipart/':
Guido van Rossumf5745001998-10-20 14:43:02 +0000505 self.read_multi(environ, keep_blank_values, strict_parsing)
Barry Warsaw302331a1999-01-08 17:42:03 +0000506 else:
Guido van Rossum60a3bd81999-06-11 18:26:09 +0000507 self.read_single()
Guido van Rossum7aee3841996-03-07 18:00:44 +0000508
509 def __repr__(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000510 """Return a printable representation."""
511 return "FieldStorage(%s, %s, %s)" % (
512 `self.name`, `self.filename`, `self.value`)
Guido van Rossum7aee3841996-03-07 18:00:44 +0000513
514 def __getattr__(self, name):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000515 if name != 'value':
516 raise AttributeError, name
517 if self.file:
518 self.file.seek(0)
519 value = self.file.read()
520 self.file.seek(0)
521 elif self.list is not None:
522 value = self.list
523 else:
524 value = None
525 return value
Guido van Rossum7aee3841996-03-07 18:00:44 +0000526
527 def __getitem__(self, key):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000528 """Dictionary style indexing."""
529 if self.list is None:
530 raise TypeError, "not indexable"
531 found = []
532 for item in self.list:
533 if item.name == key: found.append(item)
534 if not found:
535 raise KeyError, key
536 if len(found) == 1:
537 return found[0]
538 else:
539 return found
Guido van Rossum7aee3841996-03-07 18:00:44 +0000540
Moshe Zadkaa1a4b592000-08-25 21:47:56 +0000541 def getvalue(self, key, default=None):
542 """Dictionary style get() method, including 'value' lookup."""
543 if self.has_key(key):
544 value = self[key]
545 if type(value) is type([]):
546 return map(lambda v: v.value, value)
547 else:
548 return value.value
549 else:
550 return default
551
Guido van Rossum7aee3841996-03-07 18:00:44 +0000552 def keys(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000553 """Dictionary style keys() method."""
554 if self.list is None:
555 raise TypeError, "not indexable"
556 keys = []
557 for item in self.list:
558 if item.name not in keys: keys.append(item.name)
559 return keys
Guido van Rossum7aee3841996-03-07 18:00:44 +0000560
Guido van Rossum0147db01996-03-09 03:16:04 +0000561 def has_key(self, key):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000562 """Dictionary style has_key() method."""
563 if self.list is None:
564 raise TypeError, "not indexable"
565 for item in self.list:
566 if item.name == key: return 1
567 return 0
Guido van Rossum0147db01996-03-09 03:16:04 +0000568
Guido van Rossum88b85d41997-01-11 19:21:33 +0000569 def __len__(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000570 """Dictionary style len(x) support."""
571 return len(self.keys())
Guido van Rossum88b85d41997-01-11 19:21:33 +0000572
Guido van Rossum7aee3841996-03-07 18:00:44 +0000573 def read_urlencoded(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000574 """Internal: read data in query string format."""
575 qs = self.fp.read(self.length)
Guido van Rossum1946f0d1999-06-04 17:54:39 +0000576 self.list = list = []
577 for key, value in parse_qsl(qs, self.keep_blank_values,
578 self.strict_parsing):
579 list.append(MiniFieldStorage(key, value))
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000580 self.skip_lines()
Guido van Rossum7aee3841996-03-07 18:00:44 +0000581
Guido van Rossum030d2ec1998-12-09 22:16:46 +0000582 FieldStorageClass = None
583
Guido van Rossumf5745001998-10-20 14:43:02 +0000584 def read_multi(self, environ, keep_blank_values, strict_parsing):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000585 """Internal: read a part that is itself multipart."""
586 self.list = []
Guido van Rossum030d2ec1998-12-09 22:16:46 +0000587 klass = self.FieldStorageClass or self.__class__
588 part = klass(self.fp, {}, self.innerboundary,
589 environ, keep_blank_values, strict_parsing)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000590 # Throw first part away
591 while not part.done:
592 headers = rfc822.Message(self.fp)
Guido van Rossum030d2ec1998-12-09 22:16:46 +0000593 part = klass(self.fp, headers, self.innerboundary,
594 environ, keep_blank_values, strict_parsing)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000595 self.list.append(part)
596 self.skip_lines()
Guido van Rossum7aee3841996-03-07 18:00:44 +0000597
598 def read_single(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000599 """Internal: read an atomic part."""
600 if self.length >= 0:
601 self.read_binary()
602 self.skip_lines()
603 else:
604 self.read_lines()
605 self.file.seek(0)
Guido van Rossum7aee3841996-03-07 18:00:44 +0000606
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000607 bufsize = 8*1024 # I/O buffering size for copy to file
Guido van Rossum7aee3841996-03-07 18:00:44 +0000608
609 def read_binary(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000610 """Internal: read binary data."""
611 self.file = self.make_file('b')
612 todo = self.length
613 if todo >= 0:
614 while todo > 0:
615 data = self.fp.read(min(todo, self.bufsize))
616 if not data:
617 self.done = -1
618 break
619 self.file.write(data)
620 todo = todo - len(data)
Guido van Rossum7aee3841996-03-07 18:00:44 +0000621
622 def read_lines(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000623 """Internal: read lines until EOF or outerboundary."""
624 self.file = self.make_file('')
625 if self.outerboundary:
626 self.read_lines_to_outerboundary()
627 else:
628 self.read_lines_to_eof()
Guido van Rossum7aee3841996-03-07 18:00:44 +0000629
630 def read_lines_to_eof(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000631 """Internal: read lines until EOF."""
632 while 1:
633 line = self.fp.readline()
634 if not line:
635 self.done = -1
636 break
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000637 self.file.write(line)
Guido van Rossum7aee3841996-03-07 18:00:44 +0000638
639 def read_lines_to_outerboundary(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000640 """Internal: read lines until outerboundary."""
641 next = "--" + self.outerboundary
642 last = next + "--"
643 delim = ""
644 while 1:
645 line = self.fp.readline()
646 if not line:
647 self.done = -1
648 break
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000649 if line[:2] == "--":
650 strippedline = string.strip(line)
651 if strippedline == next:
652 break
653 if strippedline == last:
654 self.done = 1
655 break
656 odelim = delim
657 if line[-2:] == "\r\n":
658 delim = "\r\n"
659 line = line[:-2]
660 elif line[-1] == "\n":
661 delim = "\n"
662 line = line[:-1]
663 else:
664 delim = ""
665 self.file.write(odelim + line)
Guido van Rossum7aee3841996-03-07 18:00:44 +0000666
667 def skip_lines(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000668 """Internal: skip lines until outer boundary if defined."""
669 if not self.outerboundary or self.done:
670 return
671 next = "--" + self.outerboundary
672 last = next + "--"
673 while 1:
674 line = self.fp.readline()
675 if not line:
676 self.done = -1
677 break
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000678 if line[:2] == "--":
679 strippedline = string.strip(line)
680 if strippedline == next:
681 break
682 if strippedline == last:
683 self.done = 1
684 break
Guido van Rossum7aee3841996-03-07 18:00:44 +0000685
Guido van Rossuma5e9fb61997-08-12 18:18:13 +0000686 def make_file(self, binary=None):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000687 """Overridable: return a readable & writable file.
Guido van Rossum7aee3841996-03-07 18:00:44 +0000688
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000689 The file will be used as follows:
690 - data is written to it
691 - seek(0)
692 - data is read from it
Guido van Rossum7aee3841996-03-07 18:00:44 +0000693
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000694 The 'binary' argument is unused -- the file is always opened
695 in binary mode.
Guido van Rossum7aee3841996-03-07 18:00:44 +0000696
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000697 This version opens a temporary file for reading and writing,
698 and immediately deletes (unlinks) it. The trick (on Unix!) is
699 that the file can still be used, but it can't be opened by
700 another process, and it will automatically be deleted when it
701 is closed or when the current process terminates.
Guido van Rossum4032c2c1996-03-09 04:04:35 +0000702
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000703 If you want a more permanent file, you derive a class which
704 overrides this method. If you want a visible temporary file
705 that is nevertheless automatically deleted when the script
706 terminates, try defining a __del__ method in a derived class
707 which unlinks the temporary files you have created.
Guido van Rossum7aee3841996-03-07 18:00:44 +0000708
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000709 """
710 import tempfile
711 return tempfile.TemporaryFile("w+b")
Tim Peters88869f92001-01-14 23:36:06 +0000712
Guido van Rossum243ddcd1996-03-07 06:33:07 +0000713
714
Guido van Rossum4032c2c1996-03-09 04:04:35 +0000715# Backwards Compatibility Classes
716# ===============================
Guido van Rossum9a22de11995-01-12 12:29:47 +0000717
Moshe Zadkaa1a4b592000-08-25 21:47:56 +0000718class FormContentDict(UserDict.UserDict):
Guido van Rossuma3c6a8a2000-09-19 04:11:46 +0000719 """Form content as dictionary with a list of values per field.
Guido van Rossum72755611996-03-06 07:20:06 +0000720
Guido van Rossum7aee3841996-03-07 18:00:44 +0000721 form = FormContentDict()
722
723 form[key] -> [value, value, ...]
724 form.has_key(key) -> Boolean
725 form.keys() -> [key, key, ...]
726 form.values() -> [[val, val, ...], [val, val, ...], ...]
727 form.items() -> [(key, [val, val, ...]), (key, [val, val, ...]), ...]
728 form.dict == {key: [val, val, ...], ...}
729
730 """
Guido van Rossum773ab271996-07-23 03:46:24 +0000731 def __init__(self, environ=os.environ):
Moshe Zadkaa1a4b592000-08-25 21:47:56 +0000732 self.dict = self.data = parse(environ=environ)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000733 self.query_string = environ['QUERY_STRING']
Guido van Rossum9a22de11995-01-12 12:29:47 +0000734
735
Guido van Rossum9a22de11995-01-12 12:29:47 +0000736class SvFormContentDict(FormContentDict):
Guido van Rossuma3c6a8a2000-09-19 04:11:46 +0000737 """Form content as dictionary expecting a single value per field.
Guido van Rossum7aee3841996-03-07 18:00:44 +0000738
Guido van Rossuma3c6a8a2000-09-19 04:11:46 +0000739 If you only expect a single value for each field, then form[key]
Guido van Rossum7aee3841996-03-07 18:00:44 +0000740 will return that single value. It will raise an IndexError if
Guido van Rossuma3c6a8a2000-09-19 04:11:46 +0000741 that expectation is not true. If you expect a field to have
Guido van Rossum7aee3841996-03-07 18:00:44 +0000742 possible multiple values, than you can use form.getlist(key) to
743 get all of the values. values() and items() are a compromise:
744 they return single strings where there is a single value, and
745 lists of strings otherwise.
746
747 """
748 def __getitem__(self, key):
Tim Peters88869f92001-01-14 23:36:06 +0000749 if len(self.dict[key]) > 1:
750 raise IndexError, 'expecting a single value'
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000751 return self.dict[key][0]
Guido van Rossum7aee3841996-03-07 18:00:44 +0000752 def getlist(self, key):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000753 return self.dict[key]
Guido van Rossum7aee3841996-03-07 18:00:44 +0000754 def values(self):
Guido van Rossuma3c6a8a2000-09-19 04:11:46 +0000755 result = []
756 for value in self.dict.values():
757 if len(value) == 1:
758 result.append(value[0])
759 else: result.append(value)
760 return result
Guido van Rossum7aee3841996-03-07 18:00:44 +0000761 def items(self):
Guido van Rossuma3c6a8a2000-09-19 04:11:46 +0000762 result = []
763 for key, value in self.dict.items():
764 if len(value) == 1:
765 result.append((key, value[0]))
766 else: result.append((key, value))
767 return result
Guido van Rossum9a22de11995-01-12 12:29:47 +0000768
769
Guido van Rossum9a22de11995-01-12 12:29:47 +0000770class InterpFormContentDict(SvFormContentDict):
Tim Peters88869f92001-01-14 23:36:06 +0000771 """This class is present for backwards compatibility only."""
Guido van Rossuma3c6a8a2000-09-19 04:11:46 +0000772 def __getitem__(self, key):
773 v = SvFormContentDict.__getitem__(self, key)
774 if v[0] in string.digits + '+-.':
775 try: return string.atoi(v)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000776 except ValueError:
Guido van Rossuma3c6a8a2000-09-19 04:11:46 +0000777 try: return string.atof(v)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000778 except ValueError: pass
779 return string.strip(v)
Guido van Rossuma3c6a8a2000-09-19 04:11:46 +0000780 def values(self):
781 result = []
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000782 for key in self.keys():
783 try:
Guido van Rossuma3c6a8a2000-09-19 04:11:46 +0000784 result.append(self[key])
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000785 except IndexError:
Guido van Rossuma3c6a8a2000-09-19 04:11:46 +0000786 result.append(self.dict[key])
787 return result
788 def items(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((key, self[key]))
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000793 except IndexError:
Guido van Rossuma3c6a8a2000-09-19 04:11:46 +0000794 result.append((key, self.dict[key]))
795 return result
Guido van Rossum9a22de11995-01-12 12:29:47 +0000796
797
Guido van Rossum9a22de11995-01-12 12:29:47 +0000798class FormContent(FormContentDict):
Tim Peters88869f92001-01-14 23:36:06 +0000799 """This class is present for backwards compatibility only."""
Guido van Rossum0147db01996-03-09 03:16:04 +0000800 def values(self, key):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000801 if self.dict.has_key(key) :return self.dict[key]
802 else: return None
Guido van Rossum0147db01996-03-09 03:16:04 +0000803 def indexed_value(self, key, location):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000804 if self.dict.has_key(key):
Guido van Rossuma3c6a8a2000-09-19 04:11:46 +0000805 if len(self.dict[key]) > location:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000806 return self.dict[key][location]
807 else: return None
808 else: return None
Guido van Rossum0147db01996-03-09 03:16:04 +0000809 def value(self, key):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000810 if self.dict.has_key(key): return self.dict[key][0]
811 else: return None
Guido van Rossum0147db01996-03-09 03:16:04 +0000812 def length(self, key):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000813 return len(self.dict[key])
Guido van Rossum0147db01996-03-09 03:16:04 +0000814 def stripped(self, key):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000815 if self.dict.has_key(key): return string.strip(self.dict[key][0])
816 else: return None
Guido van Rossum7aee3841996-03-07 18:00:44 +0000817 def pars(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000818 return self.dict
Guido van Rossum9a22de11995-01-12 12:29:47 +0000819
820
Guido van Rossum72755611996-03-06 07:20:06 +0000821# Test/debug code
822# ===============
Guido van Rossum9a22de11995-01-12 12:29:47 +0000823
Guido van Rossum773ab271996-07-23 03:46:24 +0000824def test(environ=os.environ):
Guido van Rossum7aee3841996-03-07 18:00:44 +0000825 """Robust test CGI script, usable as main program.
Guido van Rossum9a22de11995-01-12 12:29:47 +0000826
Guido van Rossum7aee3841996-03-07 18:00:44 +0000827 Write minimal HTTP headers and dump all information provided to
828 the script in HTML form.
829
830 """
831 import traceback
832 print "Content-type: text/html"
833 print
834 sys.stderr = sys.stdout
835 try:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000836 form = FieldStorage() # Replace with other classes to test those
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000837 print_directory()
838 print_arguments()
Guido van Rossuma3c6a8a2000-09-19 04:11:46 +0000839 print_form(form)
840 print_environ(environ)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000841 print_environ_usage()
842 def f():
843 exec "testing print_exception() -- <I>italics?</I>"
844 def g(f=f):
845 f()
846 print "<H3>What follows is a test, not an actual exception:</H3>"
847 g()
Guido van Rossum7aee3841996-03-07 18:00:44 +0000848 except:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000849 print_exception()
Guido van Rossumf85de8a1996-08-20 20:22:39 +0000850
Guido van Rossum57d51f22000-09-16 21:16:01 +0000851 print "<H1>Second try with a small maxlen...</H1>"
852
Guido van Rossumad164711997-05-13 19:03:23 +0000853 global maxlen
854 maxlen = 50
855 try:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000856 form = FieldStorage() # Replace with other classes to test those
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000857 print_directory()
858 print_arguments()
Guido van Rossuma3c6a8a2000-09-19 04:11:46 +0000859 print_form(form)
860 print_environ(environ)
Guido van Rossumad164711997-05-13 19:03:23 +0000861 except:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000862 print_exception()
Guido van Rossumad164711997-05-13 19:03:23 +0000863
Guido van Rossumf85de8a1996-08-20 20:22:39 +0000864def print_exception(type=None, value=None, tb=None, limit=None):
865 if type is None:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000866 type, value, tb = sys.exc_info()
Guido van Rossumf85de8a1996-08-20 20:22:39 +0000867 import traceback
868 print
Guido van Rossum7dd06962000-12-27 19:12:58 +0000869 print "<H3>Traceback (most recent call last):</H3>"
Guido van Rossumf85de8a1996-08-20 20:22:39 +0000870 list = traceback.format_tb(tb, limit) + \
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000871 traceback.format_exception_only(type, value)
Guido van Rossumf85de8a1996-08-20 20:22:39 +0000872 print "<PRE>%s<B>%s</B></PRE>" % (
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000873 escape(string.join(list[:-1], "")),
874 escape(list[-1]),
875 )
Guido van Rossumf15d1591997-09-29 23:22:12 +0000876 del tb
Guido van Rossum9a22de11995-01-12 12:29:47 +0000877
Guido van Rossum773ab271996-07-23 03:46:24 +0000878def print_environ(environ=os.environ):
Guido van Rossum7aee3841996-03-07 18:00:44 +0000879 """Dump the shell environment as HTML."""
880 keys = environ.keys()
881 keys.sort()
882 print
Guido van Rossum503e50b1996-05-28 22:57:20 +0000883 print "<H3>Shell Environment:</H3>"
Guido van Rossum7aee3841996-03-07 18:00:44 +0000884 print "<DL>"
885 for key in keys:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000886 print "<DT>", escape(key), "<DD>", escape(environ[key])
Tim Peters88869f92001-01-14 23:36:06 +0000887 print "</DL>"
Guido van Rossum7aee3841996-03-07 18:00:44 +0000888 print
Guido van Rossum72755611996-03-06 07:20:06 +0000889
890def print_form(form):
Guido van Rossum7aee3841996-03-07 18:00:44 +0000891 """Dump the contents of a form as HTML."""
892 keys = form.keys()
893 keys.sort()
894 print
Guido van Rossum503e50b1996-05-28 22:57:20 +0000895 print "<H3>Form Contents:</H3>"
Guido van Rossum57d51f22000-09-16 21:16:01 +0000896 if not keys:
897 print "<P>No form fields."
Guido van Rossum7aee3841996-03-07 18:00:44 +0000898 print "<DL>"
899 for key in keys:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000900 print "<DT>" + escape(key) + ":",
901 value = form[key]
902 print "<i>" + escape(`type(value)`) + "</i>"
903 print "<DD>" + escape(`value`)
Guido van Rossum7aee3841996-03-07 18:00:44 +0000904 print "</DL>"
905 print
906
907def print_directory():
908 """Dump the current directory as HTML."""
909 print
910 print "<H3>Current Working Directory:</H3>"
911 try:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000912 pwd = os.getcwd()
Guido van Rossum7aee3841996-03-07 18:00:44 +0000913 except os.error, msg:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000914 print "os.error:", escape(str(msg))
Guido van Rossum7aee3841996-03-07 18:00:44 +0000915 else:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000916 print escape(pwd)
Guido van Rossum7aee3841996-03-07 18:00:44 +0000917 print
Guido van Rossum9a22de11995-01-12 12:29:47 +0000918
Guido van Rossuma8738a51996-03-14 21:30:28 +0000919def print_arguments():
920 print
Guido van Rossum503e50b1996-05-28 22:57:20 +0000921 print "<H3>Command Line Arguments:</H3>"
Guido van Rossuma8738a51996-03-14 21:30:28 +0000922 print
923 print sys.argv
924 print
925
Guido van Rossum9a22de11995-01-12 12:29:47 +0000926def print_environ_usage():
Guido van Rossum7aee3841996-03-07 18:00:44 +0000927 """Dump a list of environment variables used by CGI as HTML."""
928 print """
Guido van Rossum72755611996-03-06 07:20:06 +0000929<H3>These environment variables could have been set:</H3>
930<UL>
Guido van Rossum9a22de11995-01-12 12:29:47 +0000931<LI>AUTH_TYPE
932<LI>CONTENT_LENGTH
933<LI>CONTENT_TYPE
934<LI>DATE_GMT
935<LI>DATE_LOCAL
936<LI>DOCUMENT_NAME
937<LI>DOCUMENT_ROOT
938<LI>DOCUMENT_URI
939<LI>GATEWAY_INTERFACE
940<LI>LAST_MODIFIED
941<LI>PATH
942<LI>PATH_INFO
943<LI>PATH_TRANSLATED
944<LI>QUERY_STRING
945<LI>REMOTE_ADDR
946<LI>REMOTE_HOST
947<LI>REMOTE_IDENT
948<LI>REMOTE_USER
949<LI>REQUEST_METHOD
950<LI>SCRIPT_NAME
951<LI>SERVER_NAME
952<LI>SERVER_PORT
953<LI>SERVER_PROTOCOL
954<LI>SERVER_ROOT
955<LI>SERVER_SOFTWARE
956</UL>
Guido van Rossum7aee3841996-03-07 18:00:44 +0000957In addition, HTTP headers sent by the server may be passed in the
958environment as well. Here are some common variable names:
959<UL>
960<LI>HTTP_ACCEPT
961<LI>HTTP_CONNECTION
962<LI>HTTP_HOST
963<LI>HTTP_PRAGMA
964<LI>HTTP_REFERER
965<LI>HTTP_USER_AGENT
966</UL>
Guido van Rossum9a22de11995-01-12 12:29:47 +0000967"""
968
Guido van Rossum9a22de11995-01-12 12:29:47 +0000969
Guido van Rossum72755611996-03-06 07:20:06 +0000970# Utilities
971# =========
Guido van Rossum9a22de11995-01-12 12:29:47 +0000972
Guido van Rossum64c66201997-07-19 20:11:53 +0000973def escape(s, quote=None):
Guido van Rossum7aee3841996-03-07 18:00:44 +0000974 """Replace special characters '&', '<' and '>' by SGML entities."""
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000975 s = string.replace(s, "&", "&amp;") # Must be done first!
Guido van Rossum00f9fea1997-12-24 21:18:41 +0000976 s = string.replace(s, "<", "&lt;")
977 s = string.replace(s, ">", "&gt;",)
Guido van Rossum64c66201997-07-19 20:11:53 +0000978 if quote:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000979 s = string.replace(s, '"', "&quot;")
Guido van Rossum7aee3841996-03-07 18:00:44 +0000980 return s
Guido van Rossum9a22de11995-01-12 12:29:47 +0000981
Guido van Rossum9a22de11995-01-12 12:29:47 +0000982
Guido van Rossum72755611996-03-06 07:20:06 +0000983# Invoke mainline
984# ===============
985
986# Call test() when this file is run as a script (not imported as a module)
Tim Peters88869f92001-01-14 23:36:06 +0000987if __name__ == '__main__':
Guido van Rossum7aee3841996-03-07 18:00:44 +0000988 test()