blob: 2a214050c703d476e0c72eefeb4c4fb386e4ca31 [file] [log] [blame]
Guido van Rossum152f9d91997-02-18 16:55:33 +00001#! /usr/local/bin/python
Guido van Rossum1c9daa81995-09-18 21:52:37 +00002
Guido van Rossum72755611996-03-06 07:20:06 +00003"""Support module for CGI (Common Gateway Interface) scripts.
Guido van Rossum1c9daa81995-09-18 21:52:37 +00004
Guido van Rossum7aee3841996-03-07 18:00:44 +00005This module defines a number of utilities for use by CGI scripts
6written in Python.
Guido van Rossum72755611996-03-06 07:20:06 +00007"""
8
Jeremy Hyltonc253d9a2000-08-03 20:57:44 +00009# XXX Perhaps there should be a slimmed version that doesn't contain
10# all those backwards compatible and debugging classes and functions?
Guido van Rossum98d9fd32000-02-28 15:12:25 +000011
12# History
13# -------
14#
15# Michael McLay started this module. Steve Majewski changed the
16# interface to SvFormContentDict and FormContentDict. The multipart
17# parsing was inspired by code submitted by Andreas Paepcke. Guido van
18# Rossum rewrote, reformatted and documented the module and is currently
19# responsible for its maintenance.
20#
21
Moshe Zadkaa1a4b592000-08-25 21:47:56 +000022__version__ = "2.3"
Guido van Rossum0147db01996-03-09 03:16:04 +000023
Guido van Rossum72755611996-03-06 07:20:06 +000024
25# Imports
26# =======
27
28import string
Guido van Rossum72755611996-03-06 07:20:06 +000029import sys
30import os
Guido van Rossuma5e9fb61997-08-12 18:18:13 +000031import urllib
Guido van Rossuma5e9fb61997-08-12 18:18:13 +000032import mimetools
33import rfc822
Moshe Zadkaa1a4b592000-08-25 21:47:56 +000034import UserDict
Guido van Rossuma5e9fb61997-08-12 18:18:13 +000035from StringIO import StringIO
Guido van Rossum72755611996-03-06 07:20:06 +000036
Guido van Rossumc204c701996-09-05 19:07:11 +000037
38# Logging support
39# ===============
40
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000041logfile = "" # Filename to log to, if not empty
42logfp = None # File object to log to, if not None
Guido van Rossumc204c701996-09-05 19:07:11 +000043
44def initlog(*allargs):
45 """Write a log message, if there is a log file.
46
47 Even though this function is called initlog(), you should always
48 use log(); log is a variable that is set either to initlog
49 (initially), to dolog (once the log file has been opened), or to
50 nolog (when logging is disabled).
51
52 The first argument is a format string; the remaining arguments (if
53 any) are arguments to the % operator, so e.g.
54 log("%s: %s", "a", "b")
55 will write "a: b" to the log file, followed by a newline.
56
57 If the global logfp is not None, it should be a file object to
58 which log data is written.
59
60 If the global logfp is None, the global logfile may be a string
61 giving a filename to open, in append mode. This file should be
62 world writable!!! If the file can't be opened, logging is
63 silently disabled (since there is no safe place where we could
64 send an error message).
65
66 """
67 global logfp, log
68 if logfile and not logfp:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000069 try:
70 logfp = open(logfile, "a")
71 except IOError:
72 pass
Guido van Rossumc204c701996-09-05 19:07:11 +000073 if not logfp:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000074 log = nolog
Guido van Rossumc204c701996-09-05 19:07:11 +000075 else:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000076 log = dolog
Guido van Rossumc204c701996-09-05 19:07:11 +000077 apply(log, allargs)
78
79def dolog(fmt, *args):
80 """Write a log message to the log file. See initlog() for docs."""
81 logfp.write(fmt%args + "\n")
82
83def nolog(*allargs):
84 """Dummy function, assigned to log when logging is disabled."""
85 pass
86
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000087log = initlog # The current logging function
Guido van Rossumc204c701996-09-05 19:07:11 +000088
89
Guido van Rossum72755611996-03-06 07:20:06 +000090# Parsing functions
91# =================
92
Guido van Rossumad164711997-05-13 19:03:23 +000093# Maximum input we will accept when REQUEST_METHOD is POST
94# 0 ==> unlimited input
95maxlen = 0
96
Guido van Rossume08c04c1996-11-11 19:29:11 +000097def parse(fp=None, environ=os.environ, keep_blank_values=0, strict_parsing=0):
Guido van Rossum773ab271996-07-23 03:46:24 +000098 """Parse a query in the environment or from a file (default stdin)
99
100 Arguments, all optional:
101
102 fp : file pointer; default: sys.stdin
103
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000104 environ : environment dictionary; default: os.environ
Guido van Rossum773ab271996-07-23 03:46:24 +0000105
106 keep_blank_values: flag indicating whether blank values in
107 URL encoded forms should be treated as blank strings.
Thomas Wouters7e474022000-07-16 12:04:32 +0000108 A true value indicates that blanks should be retained as
Guido van Rossum773ab271996-07-23 03:46:24 +0000109 blank strings. The default false value indicates that
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000110 blank values are to be ignored and treated as if they were
111 not included.
Guido van Rossume08c04c1996-11-11 19:29:11 +0000112
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000113 strict_parsing: flag indicating what to do with parsing errors.
114 If false (the default), errors are silently ignored.
115 If true, errors raise a ValueError exception.
Guido van Rossum773ab271996-07-23 03:46:24 +0000116 """
Guido van Rossum7aee3841996-03-07 18:00:44 +0000117 if not fp:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000118 fp = sys.stdin
Guido van Rossum7aee3841996-03-07 18:00:44 +0000119 if not environ.has_key('REQUEST_METHOD'):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000120 environ['REQUEST_METHOD'] = 'GET' # For testing stand-alone
Guido van Rossum7aee3841996-03-07 18:00:44 +0000121 if environ['REQUEST_METHOD'] == 'POST':
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000122 ctype, pdict = parse_header(environ['CONTENT_TYPE'])
123 if ctype == 'multipart/form-data':
124 return parse_multipart(fp, pdict)
125 elif ctype == 'application/x-www-form-urlencoded':
126 clength = string.atoi(environ['CONTENT_LENGTH'])
127 if maxlen and clength > maxlen:
128 raise ValueError, 'Maximum content length exceeded'
129 qs = fp.read(clength)
130 else:
131 qs = '' # Unknown content-type
132 if environ.has_key('QUERY_STRING'):
133 if qs: qs = qs + '&'
134 qs = qs + environ['QUERY_STRING']
135 elif sys.argv[1:]:
136 if qs: qs = qs + '&'
137 qs = qs + sys.argv[1]
138 environ['QUERY_STRING'] = qs # XXX Shouldn't, really
Guido van Rossum7aee3841996-03-07 18:00:44 +0000139 elif environ.has_key('QUERY_STRING'):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000140 qs = environ['QUERY_STRING']
Guido van Rossum7aee3841996-03-07 18:00:44 +0000141 else:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000142 if sys.argv[1:]:
143 qs = sys.argv[1]
144 else:
145 qs = ""
146 environ['QUERY_STRING'] = qs # XXX Shouldn't, really
Guido van Rossume08c04c1996-11-11 19:29:11 +0000147 return parse_qs(qs, keep_blank_values, strict_parsing)
Guido van Rossume7808771995-08-07 20:12:09 +0000148
149
Guido van Rossume08c04c1996-11-11 19:29:11 +0000150def parse_qs(qs, keep_blank_values=0, strict_parsing=0):
151 """Parse a query given as a string argument.
Guido van Rossum773ab271996-07-23 03:46:24 +0000152
153 Arguments:
154
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000155 qs: URL-encoded query string to be parsed
Guido van Rossum773ab271996-07-23 03:46:24 +0000156
157 keep_blank_values: flag indicating whether blank values in
158 URL encoded queries should be treated as blank strings.
Thomas Wouters7e474022000-07-16 12:04:32 +0000159 A true value indicates that blanks should be retained as
Guido van Rossum773ab271996-07-23 03:46:24 +0000160 blank strings. The default false value indicates that
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000161 blank values are to be ignored and treated as if they were
162 not included.
Guido van Rossume08c04c1996-11-11 19:29:11 +0000163
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000164 strict_parsing: flag indicating what to do with parsing errors.
165 If false (the default), errors are silently ignored.
166 If true, errors raise a ValueError exception.
Guido van Rossum773ab271996-07-23 03:46:24 +0000167 """
Guido van Rossum7aee3841996-03-07 18:00:44 +0000168 dict = {}
Guido van Rossum1946f0d1999-06-04 17:54:39 +0000169 for name, value in parse_qsl(qs, keep_blank_values, strict_parsing):
Moshe Zadkaa1a4b592000-08-25 21:47:56 +0000170 if dict.has_key(name):
171 dict[name].append(value)
172 else:
173 dict[name] = [value]
Guido van Rossum1946f0d1999-06-04 17:54:39 +0000174 return dict
175
176def parse_qsl(qs, keep_blank_values=0, strict_parsing=0):
177 """Parse a query given as a string argument.
178
179 Arguments:
180
181 qs: URL-encoded query string to be parsed
182
183 keep_blank_values: flag indicating whether blank values in
184 URL encoded queries should be treated as blank strings.
Thomas Wouters7e474022000-07-16 12:04:32 +0000185 A true value indicates that blanks should be retained as
Guido van Rossum1946f0d1999-06-04 17:54:39 +0000186 blank strings. The default false value indicates that
187 blank values are to be ignored and treated as if they were
188 not included.
189
190 strict_parsing: flag indicating what to do with parsing errors.
191 If false (the default), errors are silently ignored.
192 If true, errors raise a ValueError exception.
193
194 Returns a list, as God intended.
195 """
196 name_value_pairs = string.splitfields(qs, '&')
197 r=[]
Guido van Rossum7aee3841996-03-07 18:00:44 +0000198 for name_value in name_value_pairs:
Jeremy Hyltonc253d9a2000-08-03 20:57:44 +0000199 nv = string.splitfields(name_value, '=', 1)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000200 if len(nv) != 2:
201 if strict_parsing:
202 raise ValueError, "bad query field: %s" % `name_value`
203 continue
Moshe Zadkaa1a4b592000-08-25 21:47:56 +0000204 if len(nv[1]) or keep_blank_values:
205 name = urllib.unquote(string.replace(nv[0], '+', ' '))
206 value = urllib.unquote(string.replace(nv[1], '+', ' '))
207 r.append((name, value))
Guido van Rossum1946f0d1999-06-04 17:54:39 +0000208
209 return r
Guido van Rossum9a22de11995-01-12 12:29:47 +0000210
211
Guido van Rossum0147db01996-03-09 03:16:04 +0000212def parse_multipart(fp, pdict):
Guido van Rossum7aee3841996-03-07 18:00:44 +0000213 """Parse multipart input.
Guido van Rossum9a22de11995-01-12 12:29:47 +0000214
Guido van Rossum7aee3841996-03-07 18:00:44 +0000215 Arguments:
216 fp : input file
Guido van Rossum7aee3841996-03-07 18:00:44 +0000217 pdict: dictionary containing other parameters of conten-type header
Guido van Rossum72755611996-03-06 07:20:06 +0000218
Guido van Rossum0147db01996-03-09 03:16:04 +0000219 Returns a dictionary just like parse_qs(): keys are the field names, each
220 value is a list of values for that field. This is easy to use but not
221 much good if you are expecting megabytes to be uploaded -- in that case,
222 use the FieldStorage class instead which is much more flexible. Note
223 that content-type is the raw, unparsed contents of the content-type
224 header.
225
226 XXX This does not parse nested multipart parts -- use FieldStorage for
227 that.
228
229 XXX This should really be subsumed by FieldStorage altogether -- no
230 point in having two implementations of the same parsing algorithm.
Guido van Rossum72755611996-03-06 07:20:06 +0000231
Guido van Rossum7aee3841996-03-07 18:00:44 +0000232 """
Guido van Rossum7aee3841996-03-07 18:00:44 +0000233 if pdict.has_key('boundary'):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000234 boundary = pdict['boundary']
Guido van Rossum7aee3841996-03-07 18:00:44 +0000235 else:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000236 boundary = ""
Guido van Rossum7aee3841996-03-07 18:00:44 +0000237 nextpart = "--" + boundary
238 lastpart = "--" + boundary + "--"
239 partdict = {}
240 terminator = ""
241
242 while terminator != lastpart:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000243 bytes = -1
244 data = None
245 if terminator:
246 # At start of next part. Read headers first.
247 headers = mimetools.Message(fp)
248 clength = headers.getheader('content-length')
249 if clength:
250 try:
251 bytes = string.atoi(clength)
252 except string.atoi_error:
253 pass
254 if bytes > 0:
255 if maxlen and bytes > maxlen:
256 raise ValueError, 'Maximum content length exceeded'
257 data = fp.read(bytes)
258 else:
259 data = ""
260 # Read lines until end of part.
261 lines = []
262 while 1:
263 line = fp.readline()
264 if not line:
265 terminator = lastpart # End outer loop
266 break
267 if line[:2] == "--":
268 terminator = string.strip(line)
269 if terminator in (nextpart, lastpart):
270 break
271 lines.append(line)
272 # Done with part.
273 if data is None:
274 continue
275 if bytes < 0:
276 if lines:
277 # Strip final line terminator
278 line = lines[-1]
279 if line[-2:] == "\r\n":
280 line = line[:-2]
281 elif line[-1:] == "\n":
282 line = line[:-1]
283 lines[-1] = line
284 data = string.joinfields(lines, "")
285 line = headers['content-disposition']
286 if not line:
287 continue
288 key, params = parse_header(line)
289 if key != 'form-data':
290 continue
291 if params.has_key('name'):
292 name = params['name']
293 else:
294 continue
295 if partdict.has_key(name):
296 partdict[name].append(data)
297 else:
298 partdict[name] = [data]
Guido van Rossum72755611996-03-06 07:20:06 +0000299
Guido van Rossum7aee3841996-03-07 18:00:44 +0000300 return partdict
Guido van Rossum9a22de11995-01-12 12:29:47 +0000301
302
Guido van Rossum72755611996-03-06 07:20:06 +0000303def parse_header(line):
Guido van Rossum7aee3841996-03-07 18:00:44 +0000304 """Parse a Content-type like header.
305
306 Return the main content-type and a dictionary of options.
307
308 """
309 plist = map(string.strip, string.splitfields(line, ';'))
310 key = string.lower(plist[0])
311 del plist[0]
312 pdict = {}
313 for p in plist:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000314 i = string.find(p, '=')
315 if i >= 0:
316 name = string.lower(string.strip(p[:i]))
317 value = string.strip(p[i+1:])
318 if len(value) >= 2 and value[0] == value[-1] == '"':
319 value = value[1:-1]
320 pdict[name] = value
Guido van Rossum7aee3841996-03-07 18:00:44 +0000321 return key, pdict
Guido van Rossum72755611996-03-06 07:20:06 +0000322
323
Guido van Rossum243ddcd1996-03-07 06:33:07 +0000324# Classes for field storage
325# =========================
326
327class MiniFieldStorage:
328
Guido van Rossum0147db01996-03-09 03:16:04 +0000329 """Like FieldStorage, for use when no file uploads are possible."""
Guido van Rossum243ddcd1996-03-07 06:33:07 +0000330
Guido van Rossum7aee3841996-03-07 18:00:44 +0000331 # Dummy attributes
332 filename = None
333 list = None
334 type = None
Guido van Rossum773ab271996-07-23 03:46:24 +0000335 file = None
Guido van Rossum4032c2c1996-03-09 04:04:35 +0000336 type_options = {}
Guido van Rossum7aee3841996-03-07 18:00:44 +0000337 disposition = None
338 disposition_options = {}
339 headers = {}
Guido van Rossum243ddcd1996-03-07 06:33:07 +0000340
Guido van Rossum7aee3841996-03-07 18:00:44 +0000341 def __init__(self, name, value):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000342 """Constructor from field name and value."""
343 self.name = name
344 self.value = value
Guido van Rossum773ab271996-07-23 03:46:24 +0000345 # self.file = StringIO(value)
Guido van Rossum7aee3841996-03-07 18:00:44 +0000346
347 def __repr__(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000348 """Return printable representation."""
349 return "MiniFieldStorage(%s, %s)" % (`self.name`, `self.value`)
Guido van Rossum243ddcd1996-03-07 06:33:07 +0000350
351
352class FieldStorage:
353
Guido van Rossum7aee3841996-03-07 18:00:44 +0000354 """Store a sequence of fields, reading multipart/form-data.
Guido van Rossum243ddcd1996-03-07 06:33:07 +0000355
Guido van Rossum7aee3841996-03-07 18:00:44 +0000356 This class provides naming, typing, files stored on disk, and
357 more. At the top level, it is accessible like a dictionary, whose
358 keys are the field names. (Note: None can occur as a field name.)
359 The items are either a Python list (if there's multiple values) or
360 another FieldStorage or MiniFieldStorage object. If it's a single
361 object, it has the following attributes:
Guido van Rossum243ddcd1996-03-07 06:33:07 +0000362
Guido van Rossum7aee3841996-03-07 18:00:44 +0000363 name: the field name, if specified; otherwise None
Guido van Rossum243ddcd1996-03-07 06:33:07 +0000364
Guido van Rossum7aee3841996-03-07 18:00:44 +0000365 filename: the filename, if specified; otherwise None; this is the
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000366 client side filename, *not* the file name on which it is
367 stored (that's a temporary file you don't deal with)
Guido van Rossum243ddcd1996-03-07 06:33:07 +0000368
Guido van Rossum7aee3841996-03-07 18:00:44 +0000369 value: the value as a *string*; for file uploads, this
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000370 transparently reads the file every time you request the value
Guido van Rossum7aee3841996-03-07 18:00:44 +0000371
372 file: the file(-like) object from which you can read the data;
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000373 None if the data is stored a simple string
Guido van Rossum7aee3841996-03-07 18:00:44 +0000374
375 type: the content-type, or None if not specified
376
377 type_options: dictionary of options specified on the content-type
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000378 line
Guido van Rossum7aee3841996-03-07 18:00:44 +0000379
380 disposition: content-disposition, or None if not specified
381
382 disposition_options: dictionary of corresponding options
383
384 headers: a dictionary(-like) object (sometimes rfc822.Message or a
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000385 subclass thereof) containing *all* headers
Guido van Rossum7aee3841996-03-07 18:00:44 +0000386
387 The class is subclassable, mostly for the purpose of overriding
388 the make_file() method, which is called internally to come up with
389 a file open for reading and writing. This makes it possible to
390 override the default choice of storing all files in a temporary
391 directory and unlinking them as soon as they have been opened.
392
393 """
394
Guido van Rossum773ab271996-07-23 03:46:24 +0000395 def __init__(self, fp=None, headers=None, outerboundary="",
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000396 environ=os.environ, keep_blank_values=0, strict_parsing=0):
397 """Constructor. Read multipart/* until last part.
Guido van Rossum7aee3841996-03-07 18:00:44 +0000398
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000399 Arguments, all optional:
Guido van Rossum7aee3841996-03-07 18:00:44 +0000400
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000401 fp : file pointer; default: sys.stdin
Guido van Rossumb1b4f941998-05-08 19:55:51 +0000402 (not used when the request method is GET)
Guido van Rossum7aee3841996-03-07 18:00:44 +0000403
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000404 headers : header dictionary-like object; default:
405 taken from environ as per CGI spec
Guido van Rossum7aee3841996-03-07 18:00:44 +0000406
Guido van Rossum773ab271996-07-23 03:46:24 +0000407 outerboundary : terminating multipart boundary
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000408 (for internal use only)
Guido van Rossum7aee3841996-03-07 18:00:44 +0000409
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000410 environ : environment dictionary; default: os.environ
Guido van Rossum773ab271996-07-23 03:46:24 +0000411
412 keep_blank_values: flag indicating whether blank values in
413 URL encoded forms should be treated as blank strings.
Thomas Wouters7e474022000-07-16 12:04:32 +0000414 A true value indicates that blanks should be retained as
Guido van Rossum773ab271996-07-23 03:46:24 +0000415 blank strings. The default false value indicates that
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000416 blank values are to be ignored and treated as if they were
417 not included.
Guido van Rossum773ab271996-07-23 03:46:24 +0000418
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000419 strict_parsing: flag indicating what to do with parsing errors.
420 If false (the default), errors are silently ignored.
421 If true, errors raise a ValueError exception.
Guido van Rossume08c04c1996-11-11 19:29:11 +0000422
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000423 """
424 method = 'GET'
425 self.keep_blank_values = keep_blank_values
426 self.strict_parsing = strict_parsing
427 if environ.has_key('REQUEST_METHOD'):
428 method = string.upper(environ['REQUEST_METHOD'])
Guido van Rossum01852831998-06-25 02:40:17 +0000429 if method == 'GET' or method == 'HEAD':
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000430 if environ.has_key('QUERY_STRING'):
431 qs = environ['QUERY_STRING']
432 elif sys.argv[1:]:
433 qs = sys.argv[1]
434 else:
435 qs = ""
436 fp = StringIO(qs)
437 if headers is None:
438 headers = {'content-type':
439 "application/x-www-form-urlencoded"}
440 if headers is None:
Guido van Rossumcff311a1998-06-11 14:06:59 +0000441 headers = {}
442 if method == 'POST':
443 # Set default content-type for POST to what's traditional
444 headers['content-type'] = "application/x-www-form-urlencoded"
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000445 if environ.has_key('CONTENT_TYPE'):
446 headers['content-type'] = environ['CONTENT_TYPE']
447 if environ.has_key('CONTENT_LENGTH'):
448 headers['content-length'] = environ['CONTENT_LENGTH']
449 self.fp = fp or sys.stdin
450 self.headers = headers
451 self.outerboundary = outerboundary
Guido van Rossum7aee3841996-03-07 18:00:44 +0000452
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000453 # Process content-disposition header
454 cdisp, pdict = "", {}
455 if self.headers.has_key('content-disposition'):
456 cdisp, pdict = parse_header(self.headers['content-disposition'])
457 self.disposition = cdisp
458 self.disposition_options = pdict
459 self.name = None
460 if pdict.has_key('name'):
461 self.name = pdict['name']
462 self.filename = None
463 if pdict.has_key('filename'):
464 self.filename = pdict['filename']
Guido van Rossum7aee3841996-03-07 18:00:44 +0000465
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000466 # Process content-type header
Barry Warsaw302331a1999-01-08 17:42:03 +0000467 #
468 # Honor any existing content-type header. But if there is no
469 # content-type header, use some sensible defaults. Assume
470 # outerboundary is "" at the outer level, but something non-false
471 # inside a multi-part. The default for an inner part is text/plain,
472 # but for an outer part it should be urlencoded. This should catch
473 # bogus clients which erroneously forget to include a content-type
474 # header.
475 #
476 # See below for what we do if there does exist a content-type header,
477 # but it happens to be something we don't understand.
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000478 if self.headers.has_key('content-type'):
479 ctype, pdict = parse_header(self.headers['content-type'])
Guido van Rossumce900de1999-06-02 18:44:22 +0000480 elif self.outerboundary or method != 'POST':
Barry Warsaw302331a1999-01-08 17:42:03 +0000481 ctype, pdict = "text/plain", {}
482 else:
483 ctype, pdict = 'application/x-www-form-urlencoded', {}
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000484 self.type = ctype
485 self.type_options = pdict
486 self.innerboundary = ""
487 if pdict.has_key('boundary'):
488 self.innerboundary = pdict['boundary']
489 clen = -1
490 if self.headers.has_key('content-length'):
491 try:
492 clen = string.atoi(self.headers['content-length'])
493 except:
494 pass
495 if maxlen and clen > maxlen:
496 raise ValueError, 'Maximum content length exceeded'
497 self.length = clen
Guido van Rossum7aee3841996-03-07 18:00:44 +0000498
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000499 self.list = self.file = None
500 self.done = 0
501 self.lines = []
502 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
637 self.lines.append(line)
638 self.file.write(line)
Guido van Rossum7aee3841996-03-07 18:00:44 +0000639
640 def read_lines_to_outerboundary(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000641 """Internal: read lines until outerboundary."""
642 next = "--" + self.outerboundary
643 last = next + "--"
644 delim = ""
645 while 1:
646 line = self.fp.readline()
647 if not line:
648 self.done = -1
649 break
650 self.lines.append(line)
651 if line[:2] == "--":
652 strippedline = string.strip(line)
653 if strippedline == next:
654 break
655 if strippedline == last:
656 self.done = 1
657 break
658 odelim = delim
659 if line[-2:] == "\r\n":
660 delim = "\r\n"
661 line = line[:-2]
662 elif line[-1] == "\n":
663 delim = "\n"
664 line = line[:-1]
665 else:
666 delim = ""
667 self.file.write(odelim + line)
Guido van Rossum7aee3841996-03-07 18:00:44 +0000668
669 def skip_lines(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000670 """Internal: skip lines until outer boundary if defined."""
671 if not self.outerboundary or self.done:
672 return
673 next = "--" + self.outerboundary
674 last = next + "--"
675 while 1:
676 line = self.fp.readline()
677 if not line:
678 self.done = -1
679 break
680 self.lines.append(line)
681 if line[:2] == "--":
682 strippedline = string.strip(line)
683 if strippedline == next:
684 break
685 if strippedline == last:
686 self.done = 1
687 break
Guido van Rossum7aee3841996-03-07 18:00:44 +0000688
Guido van Rossuma5e9fb61997-08-12 18:18:13 +0000689 def make_file(self, binary=None):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000690 """Overridable: return a readable & writable file.
Guido van Rossum7aee3841996-03-07 18:00:44 +0000691
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000692 The file will be used as follows:
693 - data is written to it
694 - seek(0)
695 - data is read from it
Guido van Rossum7aee3841996-03-07 18:00:44 +0000696
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000697 The 'binary' argument is unused -- the file is always opened
698 in binary mode.
Guido van Rossum7aee3841996-03-07 18:00:44 +0000699
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000700 This version opens a temporary file for reading and writing,
701 and immediately deletes (unlinks) it. The trick (on Unix!) is
702 that the file can still be used, but it can't be opened by
703 another process, and it will automatically be deleted when it
704 is closed or when the current process terminates.
Guido van Rossum4032c2c1996-03-09 04:04:35 +0000705
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000706 If you want a more permanent file, you derive a class which
707 overrides this method. If you want a visible temporary file
708 that is nevertheless automatically deleted when the script
709 terminates, try defining a __del__ method in a derived class
710 which unlinks the temporary files you have created.
Guido van Rossum7aee3841996-03-07 18:00:44 +0000711
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000712 """
713 import tempfile
714 return tempfile.TemporaryFile("w+b")
715
Guido van Rossum243ddcd1996-03-07 06:33:07 +0000716
717
Guido van Rossum4032c2c1996-03-09 04:04:35 +0000718# Backwards Compatibility Classes
719# ===============================
Guido van Rossum9a22de11995-01-12 12:29:47 +0000720
Moshe Zadkaa1a4b592000-08-25 21:47:56 +0000721class FormContentDict(UserDict.UserDict):
Guido van Rossum7aee3841996-03-07 18:00:44 +0000722 """Basic (multiple values per field) form content as dictionary.
Guido van Rossum72755611996-03-06 07:20:06 +0000723
Guido van Rossum7aee3841996-03-07 18:00:44 +0000724 form = FormContentDict()
725
726 form[key] -> [value, value, ...]
727 form.has_key(key) -> Boolean
728 form.keys() -> [key, key, ...]
729 form.values() -> [[val, val, ...], [val, val, ...], ...]
730 form.items() -> [(key, [val, val, ...]), (key, [val, val, ...]), ...]
731 form.dict == {key: [val, val, ...], ...}
732
733 """
Guido van Rossum773ab271996-07-23 03:46:24 +0000734 def __init__(self, environ=os.environ):
Moshe Zadkaa1a4b592000-08-25 21:47:56 +0000735 self.dict = self.data = parse(environ=environ)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000736 self.query_string = environ['QUERY_STRING']
Guido van Rossum9a22de11995-01-12 12:29:47 +0000737
738
Guido van Rossum9a22de11995-01-12 12:29:47 +0000739class SvFormContentDict(FormContentDict):
Guido van Rossum7aee3841996-03-07 18:00:44 +0000740 """Strict single-value expecting form content as dictionary.
741
742 IF you only expect a single value for each field, then form[key]
743 will return that single value. It will raise an IndexError if
744 that expectation is not true. IF you expect a field to have
745 possible multiple values, than you can use form.getlist(key) to
746 get all of the values. values() and items() are a compromise:
747 they return single strings where there is a single value, and
748 lists of strings otherwise.
749
750 """
751 def __getitem__(self, key):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000752 if len(self.dict[key]) > 1:
753 raise IndexError, 'expecting a single value'
754 return self.dict[key][0]
Guido van Rossum7aee3841996-03-07 18:00:44 +0000755 def getlist(self, key):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000756 return self.dict[key]
Guido van Rossum7aee3841996-03-07 18:00:44 +0000757 def values(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000758 lis = []
759 for each in self.dict.values():
760 if len( each ) == 1 :
761 lis.append(each[0])
762 else: lis.append(each)
763 return lis
Guido van Rossum7aee3841996-03-07 18:00:44 +0000764 def items(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000765 lis = []
766 for key,value in self.dict.items():
767 if len(value) == 1 :
768 lis.append((key, value[0]))
769 else: lis.append((key, value))
770 return lis
Guido van Rossum9a22de11995-01-12 12:29:47 +0000771
772
Guido van Rossum9a22de11995-01-12 12:29:47 +0000773class InterpFormContentDict(SvFormContentDict):
Guido van Rossum7aee3841996-03-07 18:00:44 +0000774 """This class is present for backwards compatibility only."""
775 def __getitem__( self, key ):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000776 v = SvFormContentDict.__getitem__( self, key )
777 if v[0] in string.digits+'+-.' :
778 try: return string.atoi( v )
779 except ValueError:
780 try: return string.atof( v )
781 except ValueError: pass
782 return string.strip(v)
Guido van Rossum7aee3841996-03-07 18:00:44 +0000783 def values( self ):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000784 lis = []
785 for key in self.keys():
786 try:
787 lis.append( self[key] )
788 except IndexError:
789 lis.append( self.dict[key] )
790 return lis
Guido van Rossum7aee3841996-03-07 18:00:44 +0000791 def items( self ):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000792 lis = []
793 for key in self.keys():
794 try:
795 lis.append( (key, self[key]) )
796 except IndexError:
797 lis.append( (key, self.dict[key]) )
798 return lis
Guido van Rossum9a22de11995-01-12 12:29:47 +0000799
800
Guido van Rossum9a22de11995-01-12 12:29:47 +0000801class FormContent(FormContentDict):
Guido van Rossum7aee3841996-03-07 18:00:44 +0000802 """This class is present for backwards compatibility only."""
Guido van Rossum0147db01996-03-09 03:16:04 +0000803 def values(self, key):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000804 if self.dict.has_key(key) :return self.dict[key]
805 else: return None
Guido van Rossum0147db01996-03-09 03:16:04 +0000806 def indexed_value(self, key, location):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000807 if self.dict.has_key(key):
808 if len (self.dict[key]) > location:
809 return self.dict[key][location]
810 else: return None
811 else: return None
Guido van Rossum0147db01996-03-09 03:16:04 +0000812 def value(self, key):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000813 if self.dict.has_key(key): return self.dict[key][0]
814 else: return None
Guido van Rossum0147db01996-03-09 03:16:04 +0000815 def length(self, key):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000816 return len(self.dict[key])
Guido van Rossum0147db01996-03-09 03:16:04 +0000817 def stripped(self, key):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000818 if self.dict.has_key(key): return string.strip(self.dict[key][0])
819 else: return None
Guido van Rossum7aee3841996-03-07 18:00:44 +0000820 def pars(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000821 return self.dict
Guido van Rossum9a22de11995-01-12 12:29:47 +0000822
823
Guido van Rossum72755611996-03-06 07:20:06 +0000824# Test/debug code
825# ===============
Guido van Rossum9a22de11995-01-12 12:29:47 +0000826
Guido van Rossum773ab271996-07-23 03:46:24 +0000827def test(environ=os.environ):
Guido van Rossum7aee3841996-03-07 18:00:44 +0000828 """Robust test CGI script, usable as main program.
Guido van Rossum9a22de11995-01-12 12:29:47 +0000829
Guido van Rossum7aee3841996-03-07 18:00:44 +0000830 Write minimal HTTP headers and dump all information provided to
831 the script in HTML form.
832
833 """
834 import traceback
835 print "Content-type: text/html"
836 print
837 sys.stderr = sys.stdout
838 try:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000839 form = FieldStorage() # Replace with other classes to test those
840 print_form(form)
Guido van Rossum773ab271996-07-23 03:46:24 +0000841 print_environ(environ)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000842 print_directory()
843 print_arguments()
844 print_environ_usage()
845 def f():
846 exec "testing print_exception() -- <I>italics?</I>"
847 def g(f=f):
848 f()
849 print "<H3>What follows is a test, not an actual exception:</H3>"
850 g()
Guido van Rossum7aee3841996-03-07 18:00:44 +0000851 except:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000852 print_exception()
Guido van Rossumf85de8a1996-08-20 20:22:39 +0000853
Guido van Rossumad164711997-05-13 19:03:23 +0000854 # Second try with a small maxlen...
855 global maxlen
856 maxlen = 50
857 try:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000858 form = FieldStorage() # Replace with other classes to test those
859 print_form(form)
860 print_environ(environ)
861 print_directory()
862 print_arguments()
863 print_environ_usage()
Guido van Rossumad164711997-05-13 19:03:23 +0000864 except:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000865 print_exception()
Guido van Rossumad164711997-05-13 19:03:23 +0000866
Guido van Rossumf85de8a1996-08-20 20:22:39 +0000867def print_exception(type=None, value=None, tb=None, limit=None):
868 if type is None:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000869 type, value, tb = sys.exc_info()
Guido van Rossumf85de8a1996-08-20 20:22:39 +0000870 import traceback
871 print
872 print "<H3>Traceback (innermost last):</H3>"
873 list = traceback.format_tb(tb, limit) + \
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000874 traceback.format_exception_only(type, value)
Guido van Rossumf85de8a1996-08-20 20:22:39 +0000875 print "<PRE>%s<B>%s</B></PRE>" % (
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000876 escape(string.join(list[:-1], "")),
877 escape(list[-1]),
878 )
Guido van Rossumf15d1591997-09-29 23:22:12 +0000879 del tb
Guido van Rossum9a22de11995-01-12 12:29:47 +0000880
Guido van Rossum773ab271996-07-23 03:46:24 +0000881def print_environ(environ=os.environ):
Guido van Rossum7aee3841996-03-07 18:00:44 +0000882 """Dump the shell environment as HTML."""
883 keys = environ.keys()
884 keys.sort()
885 print
Guido van Rossum503e50b1996-05-28 22:57:20 +0000886 print "<H3>Shell Environment:</H3>"
Guido van Rossum7aee3841996-03-07 18:00:44 +0000887 print "<DL>"
888 for key in keys:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000889 print "<DT>", escape(key), "<DD>", escape(environ[key])
Guido van Rossum7aee3841996-03-07 18:00:44 +0000890 print "</DL>"
891 print
Guido van Rossum72755611996-03-06 07:20:06 +0000892
893def print_form(form):
Guido van Rossum7aee3841996-03-07 18:00:44 +0000894 """Dump the contents of a form as HTML."""
895 keys = form.keys()
896 keys.sort()
897 print
Guido van Rossum503e50b1996-05-28 22:57:20 +0000898 print "<H3>Form Contents:</H3>"
Guido van Rossum7aee3841996-03-07 18:00:44 +0000899 print "<DL>"
900 for key in keys:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000901 print "<DT>" + escape(key) + ":",
902 value = form[key]
903 print "<i>" + escape(`type(value)`) + "</i>"
904 print "<DD>" + escape(`value`)
Guido van Rossum7aee3841996-03-07 18:00:44 +0000905 print "</DL>"
906 print
907
908def print_directory():
909 """Dump the current directory as HTML."""
910 print
911 print "<H3>Current Working Directory:</H3>"
912 try:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000913 pwd = os.getcwd()
Guido van Rossum7aee3841996-03-07 18:00:44 +0000914 except os.error, msg:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000915 print "os.error:", escape(str(msg))
Guido van Rossum7aee3841996-03-07 18:00:44 +0000916 else:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000917 print escape(pwd)
Guido van Rossum7aee3841996-03-07 18:00:44 +0000918 print
Guido van Rossum9a22de11995-01-12 12:29:47 +0000919
Guido van Rossuma8738a51996-03-14 21:30:28 +0000920def print_arguments():
921 print
Guido van Rossum503e50b1996-05-28 22:57:20 +0000922 print "<H3>Command Line Arguments:</H3>"
Guido van Rossuma8738a51996-03-14 21:30:28 +0000923 print
924 print sys.argv
925 print
926
Guido van Rossum9a22de11995-01-12 12:29:47 +0000927def print_environ_usage():
Guido van Rossum7aee3841996-03-07 18:00:44 +0000928 """Dump a list of environment variables used by CGI as HTML."""
929 print """
Guido van Rossum72755611996-03-06 07:20:06 +0000930<H3>These environment variables could have been set:</H3>
931<UL>
Guido van Rossum9a22de11995-01-12 12:29:47 +0000932<LI>AUTH_TYPE
933<LI>CONTENT_LENGTH
934<LI>CONTENT_TYPE
935<LI>DATE_GMT
936<LI>DATE_LOCAL
937<LI>DOCUMENT_NAME
938<LI>DOCUMENT_ROOT
939<LI>DOCUMENT_URI
940<LI>GATEWAY_INTERFACE
941<LI>LAST_MODIFIED
942<LI>PATH
943<LI>PATH_INFO
944<LI>PATH_TRANSLATED
945<LI>QUERY_STRING
946<LI>REMOTE_ADDR
947<LI>REMOTE_HOST
948<LI>REMOTE_IDENT
949<LI>REMOTE_USER
950<LI>REQUEST_METHOD
951<LI>SCRIPT_NAME
952<LI>SERVER_NAME
953<LI>SERVER_PORT
954<LI>SERVER_PROTOCOL
955<LI>SERVER_ROOT
956<LI>SERVER_SOFTWARE
957</UL>
Guido van Rossum7aee3841996-03-07 18:00:44 +0000958In addition, HTTP headers sent by the server may be passed in the
959environment as well. Here are some common variable names:
960<UL>
961<LI>HTTP_ACCEPT
962<LI>HTTP_CONNECTION
963<LI>HTTP_HOST
964<LI>HTTP_PRAGMA
965<LI>HTTP_REFERER
966<LI>HTTP_USER_AGENT
967</UL>
Guido van Rossum9a22de11995-01-12 12:29:47 +0000968"""
969
Guido van Rossum9a22de11995-01-12 12:29:47 +0000970
Guido van Rossum72755611996-03-06 07:20:06 +0000971# Utilities
972# =========
Guido van Rossum9a22de11995-01-12 12:29:47 +0000973
Guido van Rossum64c66201997-07-19 20:11:53 +0000974def escape(s, quote=None):
Guido van Rossum7aee3841996-03-07 18:00:44 +0000975 """Replace special characters '&', '<' and '>' by SGML entities."""
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000976 s = string.replace(s, "&", "&amp;") # Must be done first!
Guido van Rossum00f9fea1997-12-24 21:18:41 +0000977 s = string.replace(s, "<", "&lt;")
978 s = string.replace(s, ">", "&gt;",)
Guido van Rossum64c66201997-07-19 20:11:53 +0000979 if quote:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000980 s = string.replace(s, '"', "&quot;")
Guido van Rossum7aee3841996-03-07 18:00:44 +0000981 return s
Guido van Rossum9a22de11995-01-12 12:29:47 +0000982
Guido van Rossum9a22de11995-01-12 12:29:47 +0000983
Guido van Rossum72755611996-03-06 07:20:06 +0000984# Invoke mainline
985# ===============
986
987# Call test() when this file is run as a script (not imported as a module)
988if __name__ == '__main__':
Guido van Rossum7aee3841996-03-07 18:00:44 +0000989 test()