blob: e62fcf2c7fc20ce350b81c033ed7d7509b28dc34 [file] [log] [blame]
Guido van Rossum51914632000-10-03 13:51:09 +00001#! /usr/local/bin/python
Guido van Rossum1c9daa81995-09-18 21:52:37 +00002
Guido van Rossum467d7232001-02-13 13:13:33 +00003# NOTE: the above "/usr/local/bin/python" is NOT a mistake. It is
4# intentionally NOT "/usr/bin/env python". On many systems
5# (e.g. Solaris), /usr/local/bin is not in $PATH as passed to CGI
6# scripts, and /usr/local/bin is the default directory where Python is
7# installed, so /usr/bin/env would be unable to find python. Granted,
8# binary installations by Linux vendors often install Python in
9# /usr/bin. So let those vendors patch cgi.py to match their choice
10# of installation.
11
Guido van Rossum72755611996-03-06 07:20:06 +000012"""Support module for CGI (Common Gateway Interface) scripts.
Guido van Rossum1c9daa81995-09-18 21:52:37 +000013
Guido van Rossum7aee3841996-03-07 18:00:44 +000014This module defines a number of utilities for use by CGI scripts
15written in Python.
Guido van Rossum72755611996-03-06 07:20:06 +000016"""
17
Guido van Rossum98d9fd32000-02-28 15:12:25 +000018# History
19# -------
Tim Peters88869f92001-01-14 23:36:06 +000020#
Guido van Rossum98d9fd32000-02-28 15:12:25 +000021# Michael McLay started this module. Steve Majewski changed the
22# interface to SvFormContentDict and FormContentDict. The multipart
23# parsing was inspired by code submitted by Andreas Paepcke. Guido van
24# Rossum rewrote, reformatted and documented the module and is currently
25# responsible for its maintenance.
Tim Peters88869f92001-01-14 23:36:06 +000026#
Guido van Rossum98d9fd32000-02-28 15:12:25 +000027
Guido van Rossum52b8c292001-06-29 13:06:06 +000028__version__ = "2.6"
Guido van Rossum0147db01996-03-09 03:16:04 +000029
Guido van Rossum72755611996-03-06 07:20:06 +000030
31# Imports
32# =======
33
Raymond Hettingerf871d832004-12-31 21:59:02 +000034from operator import attrgetter
Barry Warsaw596097e2008-06-12 02:38:51 +000035from io import StringIO
Guido van Rossum72755611996-03-06 07:20:06 +000036import sys
37import os
Jeremy Hylton1afc1692008-06-18 20:49:58 +000038import urllib.parse
Barry Warsaw596097e2008-06-12 02:38:51 +000039import email.parser
Facundo Batistac469d4c2008-09-03 22:49:01 +000040from warnings import warn
Guido van Rossum72755611996-03-06 07:20:06 +000041
Georg Brandl49d1b4f2008-05-11 21:42:51 +000042__all__ = ["MiniFieldStorage", "FieldStorage",
Guido van Rossuma8423a92001-03-19 13:40:44 +000043 "parse", "parse_qs", "parse_qsl", "parse_multipart",
44 "parse_header", "print_exception", "print_environ",
45 "print_form", "print_directory", "print_arguments",
46 "print_environ_usage", "escape"]
Guido van Rossumc204c701996-09-05 19:07:11 +000047
48# Logging support
49# ===============
50
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000051logfile = "" # Filename to log to, if not empty
52logfp = None # File object to log to, if not None
Guido van Rossumc204c701996-09-05 19:07:11 +000053
54def initlog(*allargs):
55 """Write a log message, if there is a log file.
56
57 Even though this function is called initlog(), you should always
58 use log(); log is a variable that is set either to initlog
59 (initially), to dolog (once the log file has been opened), or to
60 nolog (when logging is disabled).
61
62 The first argument is a format string; the remaining arguments (if
63 any) are arguments to the % operator, so e.g.
64 log("%s: %s", "a", "b")
65 will write "a: b" to the log file, followed by a newline.
66
67 If the global logfp is not None, it should be a file object to
68 which log data is written.
69
70 If the global logfp is None, the global logfile may be a string
71 giving a filename to open, in append mode. This file should be
72 world writable!!! If the file can't be opened, logging is
73 silently disabled (since there is no safe place where we could
74 send an error message).
75
76 """
77 global logfp, log
78 if logfile and not logfp:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000079 try:
80 logfp = open(logfile, "a")
81 except IOError:
82 pass
Guido van Rossumc204c701996-09-05 19:07:11 +000083 if not logfp:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000084 log = nolog
Guido van Rossumc204c701996-09-05 19:07:11 +000085 else:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000086 log = dolog
Guido van Rossum68468eb2003-02-27 20:14:51 +000087 log(*allargs)
Guido van Rossumc204c701996-09-05 19:07:11 +000088
89def dolog(fmt, *args):
90 """Write a log message to the log file. See initlog() for docs."""
91 logfp.write(fmt%args + "\n")
92
93def nolog(*allargs):
94 """Dummy function, assigned to log when logging is disabled."""
95 pass
96
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000097log = initlog # The current logging function
Guido van Rossumc204c701996-09-05 19:07:11 +000098
99
Guido van Rossum72755611996-03-06 07:20:06 +0000100# Parsing functions
101# =================
102
Guido van Rossumad164711997-05-13 19:03:23 +0000103# Maximum input we will accept when REQUEST_METHOD is POST
104# 0 ==> unlimited input
105maxlen = 0
106
Guido van Rossume08c04c1996-11-11 19:29:11 +0000107def parse(fp=None, environ=os.environ, keep_blank_values=0, strict_parsing=0):
Guido van Rossum773ab271996-07-23 03:46:24 +0000108 """Parse a query in the environment or from a file (default stdin)
109
110 Arguments, all optional:
111
112 fp : file pointer; default: sys.stdin
113
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000114 environ : environment dictionary; default: os.environ
Guido van Rossum773ab271996-07-23 03:46:24 +0000115
116 keep_blank_values: flag indicating whether blank values in
Tim Peters88869f92001-01-14 23:36:06 +0000117 URL encoded forms should be treated as blank strings.
118 A true value indicates that blanks should be retained as
Guido van Rossum773ab271996-07-23 03:46:24 +0000119 blank strings. The default false value indicates that
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000120 blank values are to be ignored and treated as if they were
121 not included.
Guido van Rossume08c04c1996-11-11 19:29:11 +0000122
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000123 strict_parsing: flag indicating what to do with parsing errors.
124 If false (the default), errors are silently ignored.
125 If true, errors raise a ValueError exception.
Guido van Rossum773ab271996-07-23 03:46:24 +0000126 """
Raymond Hettingera1449002002-05-31 23:54:44 +0000127 if fp is None:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000128 fp = sys.stdin
Raymond Hettinger54f02222002-06-01 14:18:47 +0000129 if not 'REQUEST_METHOD' in environ:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000130 environ['REQUEST_METHOD'] = 'GET' # For testing stand-alone
Guido van Rossum7aee3841996-03-07 18:00:44 +0000131 if environ['REQUEST_METHOD'] == 'POST':
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000132 ctype, pdict = parse_header(environ['CONTENT_TYPE'])
133 if ctype == 'multipart/form-data':
134 return parse_multipart(fp, pdict)
135 elif ctype == 'application/x-www-form-urlencoded':
Eric S. Raymond7e9b4f52001-02-09 09:59:10 +0000136 clength = int(environ['CONTENT_LENGTH'])
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000137 if maxlen and clength > maxlen:
Collin Winterce36ad82007-08-30 01:19:48 +0000138 raise ValueError('Maximum content length exceeded')
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000139 qs = fp.read(clength)
140 else:
141 qs = '' # Unknown content-type
Raymond Hettinger54f02222002-06-01 14:18:47 +0000142 if 'QUERY_STRING' in environ:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000143 if qs: qs = qs + '&'
144 qs = qs + environ['QUERY_STRING']
Tim Peters88869f92001-01-14 23:36:06 +0000145 elif sys.argv[1:]:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000146 if qs: qs = qs + '&'
147 qs = qs + sys.argv[1]
148 environ['QUERY_STRING'] = qs # XXX Shouldn't, really
Raymond Hettinger54f02222002-06-01 14:18:47 +0000149 elif 'QUERY_STRING' in environ:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000150 qs = environ['QUERY_STRING']
Guido van Rossum7aee3841996-03-07 18:00:44 +0000151 else:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000152 if sys.argv[1:]:
153 qs = sys.argv[1]
154 else:
155 qs = ""
156 environ['QUERY_STRING'] = qs # XXX Shouldn't, really
Facundo Batistac469d4c2008-09-03 22:49:01 +0000157 return urllib.parse.parse_qs(qs, keep_blank_values, strict_parsing)
Guido van Rossume7808771995-08-07 20:12:09 +0000158
159
Facundo Batistac469d4c2008-09-03 22:49:01 +0000160# parse query string function called from urlparse,
161# this is done in order to maintain backward compatiblity.
162
Guido van Rossume08c04c1996-11-11 19:29:11 +0000163def parse_qs(qs, keep_blank_values=0, strict_parsing=0):
Facundo Batistac469d4c2008-09-03 22:49:01 +0000164 """Parse a query given as a string argument."""
165 warn("cgi.parse_qs is deprecated, use urllib.parse.parse_qs instead",
166 DeprecationWarning)
167 return urllib.parse.parse_qs(qs, keep_blank_values, strict_parsing)
Guido van Rossum1946f0d1999-06-04 17:54:39 +0000168
169def parse_qsl(qs, keep_blank_values=0, strict_parsing=0):
Facundo Batistac469d4c2008-09-03 22:49:01 +0000170 """Parse a query given as a string argument."""
Facundo Batistaa27244b2008-09-09 02:43:19 +0000171 warn("cgi.parse_qsl is deprecated, use urllib.parse.parse_qsl instead",
Facundo Batistac469d4c2008-09-03 22:49:01 +0000172 DeprecationWarning)
173 return urllib.parse.parse_qsl(qs, keep_blank_values, strict_parsing)
Guido van Rossum9a22de11995-01-12 12:29:47 +0000174
Guido van Rossum0147db01996-03-09 03:16:04 +0000175def parse_multipart(fp, pdict):
Guido van Rossum7aee3841996-03-07 18:00:44 +0000176 """Parse multipart input.
Guido van Rossum9a22de11995-01-12 12:29:47 +0000177
Guido van Rossum7aee3841996-03-07 18:00:44 +0000178 Arguments:
179 fp : input file
Johannes Gijsbersc7fc10a2005-01-08 13:56:36 +0000180 pdict: dictionary containing other parameters of content-type header
Guido van Rossum72755611996-03-06 07:20:06 +0000181
Tim Peters88869f92001-01-14 23:36:06 +0000182 Returns a dictionary just like parse_qs(): keys are the field names, each
183 value is a list of values for that field. This is easy to use but not
184 much good if you are expecting megabytes to be uploaded -- in that case,
185 use the FieldStorage class instead which is much more flexible. Note
186 that content-type is the raw, unparsed contents of the content-type
Guido van Rossum0147db01996-03-09 03:16:04 +0000187 header.
Tim Peters88869f92001-01-14 23:36:06 +0000188
189 XXX This does not parse nested multipart parts -- use FieldStorage for
Guido van Rossum0147db01996-03-09 03:16:04 +0000190 that.
Tim Peters88869f92001-01-14 23:36:06 +0000191
192 XXX This should really be subsumed by FieldStorage altogether -- no
Guido van Rossum0147db01996-03-09 03:16:04 +0000193 point in having two implementations of the same parsing algorithm.
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000194 Also, FieldStorage protects itself better against certain DoS attacks
195 by limiting the size of the data read in one chunk. The API here
196 does not support that kind of protection. This also affects parse()
197 since it can call parse_multipart().
Guido van Rossum72755611996-03-06 07:20:06 +0000198
Guido van Rossum7aee3841996-03-07 18:00:44 +0000199 """
Barry Warsaw820c1202008-06-12 04:06:45 +0000200 import http.client
201
Guido van Rossum2e441f72001-07-25 21:00:19 +0000202 boundary = ""
Raymond Hettinger54f02222002-06-01 14:18:47 +0000203 if 'boundary' in pdict:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000204 boundary = pdict['boundary']
Guido van Rossum2e441f72001-07-25 21:00:19 +0000205 if not valid_boundary(boundary):
Collin Winterce36ad82007-08-30 01:19:48 +0000206 raise ValueError('Invalid boundary in multipart form: %r'
Walter Dörwald70a6b492004-02-12 17:35:32 +0000207 % (boundary,))
Tim Petersab9ba272001-08-09 21:40:30 +0000208
Guido van Rossum7aee3841996-03-07 18:00:44 +0000209 nextpart = "--" + boundary
210 lastpart = "--" + boundary + "--"
211 partdict = {}
212 terminator = ""
213
214 while terminator != lastpart:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000215 bytes = -1
216 data = None
217 if terminator:
218 # At start of next part. Read headers first.
Barry Warsaw820c1202008-06-12 04:06:45 +0000219 headers = http.client.parse_headers(fp)
220 clength = headers.get('content-length')
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000221 if clength:
222 try:
Eric S. Raymond7e9b4f52001-02-09 09:59:10 +0000223 bytes = int(clength)
224 except ValueError:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000225 pass
226 if bytes > 0:
227 if maxlen and bytes > maxlen:
Collin Winterce36ad82007-08-30 01:19:48 +0000228 raise ValueError('Maximum content length exceeded')
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000229 data = fp.read(bytes)
230 else:
231 data = ""
232 # Read lines until end of part.
233 lines = []
234 while 1:
235 line = fp.readline()
236 if not line:
237 terminator = lastpart # End outer loop
238 break
239 if line[:2] == "--":
Eric S. Raymond7e9b4f52001-02-09 09:59:10 +0000240 terminator = line.strip()
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000241 if terminator in (nextpart, lastpart):
242 break
243 lines.append(line)
244 # Done with part.
245 if data is None:
246 continue
247 if bytes < 0:
248 if lines:
249 # Strip final line terminator
250 line = lines[-1]
251 if line[-2:] == "\r\n":
252 line = line[:-2]
253 elif line[-1:] == "\n":
254 line = line[:-1]
255 lines[-1] = line
Eric S. Raymond7e9b4f52001-02-09 09:59:10 +0000256 data = "".join(lines)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000257 line = headers['content-disposition']
258 if not line:
259 continue
260 key, params = parse_header(line)
261 if key != 'form-data':
262 continue
Raymond Hettinger54f02222002-06-01 14:18:47 +0000263 if 'name' in params:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000264 name = params['name']
265 else:
266 continue
Raymond Hettinger54f02222002-06-01 14:18:47 +0000267 if name in partdict:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000268 partdict[name].append(data)
269 else:
270 partdict[name] = [data]
Guido van Rossum72755611996-03-06 07:20:06 +0000271
Guido van Rossum7aee3841996-03-07 18:00:44 +0000272 return partdict
Guido van Rossum9a22de11995-01-12 12:29:47 +0000273
274
Guido van Rossum72755611996-03-06 07:20:06 +0000275def parse_header(line):
Guido van Rossum7aee3841996-03-07 18:00:44 +0000276 """Parse a Content-type like header.
277
278 Return the main content-type and a dictionary of options.
279
280 """
Raymond Hettingerf871d832004-12-31 21:59:02 +0000281 plist = [x.strip() for x in line.split(';')]
Raymond Hettinger46ac8eb2002-06-30 03:39:14 +0000282 key = plist.pop(0).lower()
Guido van Rossum7aee3841996-03-07 18:00:44 +0000283 pdict = {}
284 for p in plist:
Eric S. Raymond7e9b4f52001-02-09 09:59:10 +0000285 i = p.find('=')
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000286 if i >= 0:
Eric S. Raymond7e9b4f52001-02-09 09:59:10 +0000287 name = p[:i].strip().lower()
288 value = p[i+1:].strip()
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000289 if len(value) >= 2 and value[0] == value[-1] == '"':
290 value = value[1:-1]
Johannes Gijsbers9e15dd62004-08-14 15:39:34 +0000291 value = value.replace('\\\\', '\\').replace('\\"', '"')
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000292 pdict[name] = value
Guido van Rossum7aee3841996-03-07 18:00:44 +0000293 return key, pdict
Guido van Rossum72755611996-03-06 07:20:06 +0000294
295
Guido van Rossum243ddcd1996-03-07 06:33:07 +0000296# Classes for field storage
297# =========================
298
299class MiniFieldStorage:
300
Guido van Rossum0147db01996-03-09 03:16:04 +0000301 """Like FieldStorage, for use when no file uploads are possible."""
Guido van Rossum243ddcd1996-03-07 06:33:07 +0000302
Guido van Rossum7aee3841996-03-07 18:00:44 +0000303 # Dummy attributes
304 filename = None
305 list = None
306 type = None
Guido van Rossum773ab271996-07-23 03:46:24 +0000307 file = None
Guido van Rossum4032c2c1996-03-09 04:04:35 +0000308 type_options = {}
Guido van Rossum7aee3841996-03-07 18:00:44 +0000309 disposition = None
310 disposition_options = {}
311 headers = {}
Guido van Rossum243ddcd1996-03-07 06:33:07 +0000312
Guido van Rossum7aee3841996-03-07 18:00:44 +0000313 def __init__(self, name, value):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000314 """Constructor from field name and value."""
315 self.name = name
316 self.value = value
Guido van Rossum773ab271996-07-23 03:46:24 +0000317 # self.file = StringIO(value)
Guido van Rossum7aee3841996-03-07 18:00:44 +0000318
319 def __repr__(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000320 """Return printable representation."""
Walter Dörwald70a6b492004-02-12 17:35:32 +0000321 return "MiniFieldStorage(%r, %r)" % (self.name, self.value)
Guido van Rossum243ddcd1996-03-07 06:33:07 +0000322
323
324class FieldStorage:
325
Guido van Rossum7aee3841996-03-07 18:00:44 +0000326 """Store a sequence of fields, reading multipart/form-data.
Guido van Rossum243ddcd1996-03-07 06:33:07 +0000327
Guido van Rossum7aee3841996-03-07 18:00:44 +0000328 This class provides naming, typing, files stored on disk, and
329 more. At the top level, it is accessible like a dictionary, whose
330 keys are the field names. (Note: None can occur as a field name.)
331 The items are either a Python list (if there's multiple values) or
332 another FieldStorage or MiniFieldStorage object. If it's a single
333 object, it has the following attributes:
Guido van Rossum243ddcd1996-03-07 06:33:07 +0000334
Guido van Rossum7aee3841996-03-07 18:00:44 +0000335 name: the field name, if specified; otherwise None
Guido van Rossum243ddcd1996-03-07 06:33:07 +0000336
Guido van Rossum7aee3841996-03-07 18:00:44 +0000337 filename: the filename, if specified; otherwise None; this is the
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000338 client side filename, *not* the file name on which it is
339 stored (that's a temporary file you don't deal with)
Guido van Rossum243ddcd1996-03-07 06:33:07 +0000340
Guido van Rossum7aee3841996-03-07 18:00:44 +0000341 value: the value as a *string*; for file uploads, this
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000342 transparently reads the file every time you request the value
Guido van Rossum7aee3841996-03-07 18:00:44 +0000343
344 file: the file(-like) object from which you can read the data;
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000345 None if the data is stored a simple string
Guido van Rossum7aee3841996-03-07 18:00:44 +0000346
347 type: the content-type, or None if not specified
348
349 type_options: dictionary of options specified on the content-type
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000350 line
Guido van Rossum7aee3841996-03-07 18:00:44 +0000351
352 disposition: content-disposition, or None if not specified
353
354 disposition_options: dictionary of corresponding options
355
Barry Warsaw596097e2008-06-12 02:38:51 +0000356 headers: a dictionary(-like) object (sometimes email.message.Message or a
Armin Rigo3a703b62005-09-19 09:11:04 +0000357 subclass thereof) containing *all* headers
Guido van Rossum7aee3841996-03-07 18:00:44 +0000358
359 The class is subclassable, mostly for the purpose of overriding
360 the make_file() method, which is called internally to come up with
361 a file open for reading and writing. This makes it possible to
362 override the default choice of storing all files in a temporary
363 directory and unlinking them as soon as they have been opened.
364
365 """
366
Guido van Rossum773ab271996-07-23 03:46:24 +0000367 def __init__(self, fp=None, headers=None, outerboundary="",
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000368 environ=os.environ, keep_blank_values=0, strict_parsing=0):
369 """Constructor. Read multipart/* until last part.
Guido van Rossum7aee3841996-03-07 18:00:44 +0000370
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000371 Arguments, all optional:
Guido van Rossum7aee3841996-03-07 18:00:44 +0000372
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000373 fp : file pointer; default: sys.stdin
Guido van Rossumb1b4f941998-05-08 19:55:51 +0000374 (not used when the request method is GET)
Guido van Rossum7aee3841996-03-07 18:00:44 +0000375
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000376 headers : header dictionary-like object; default:
377 taken from environ as per CGI spec
Guido van Rossum7aee3841996-03-07 18:00:44 +0000378
Guido van Rossum773ab271996-07-23 03:46:24 +0000379 outerboundary : terminating multipart boundary
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000380 (for internal use only)
Guido van Rossum7aee3841996-03-07 18:00:44 +0000381
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000382 environ : environment dictionary; default: os.environ
Guido van Rossum773ab271996-07-23 03:46:24 +0000383
384 keep_blank_values: flag indicating whether blank values in
Tim Peters88869f92001-01-14 23:36:06 +0000385 URL encoded forms should be treated as blank strings.
386 A true value indicates that blanks should be retained as
Guido van Rossum773ab271996-07-23 03:46:24 +0000387 blank strings. The default false value indicates that
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000388 blank values are to be ignored and treated as if they were
389 not included.
Guido van Rossum773ab271996-07-23 03:46:24 +0000390
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000391 strict_parsing: flag indicating what to do with parsing errors.
392 If false (the default), errors are silently ignored.
393 If true, errors raise a ValueError exception.
Guido van Rossume08c04c1996-11-11 19:29:11 +0000394
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000395 """
396 method = 'GET'
397 self.keep_blank_values = keep_blank_values
398 self.strict_parsing = strict_parsing
Raymond Hettinger54f02222002-06-01 14:18:47 +0000399 if 'REQUEST_METHOD' in environ:
Eric S. Raymond7e9b4f52001-02-09 09:59:10 +0000400 method = environ['REQUEST_METHOD'].upper()
Benjamin Petersondcf97b92008-07-02 17:30:14 +0000401 self.qs_on_post = None
Guido van Rossum01852831998-06-25 02:40:17 +0000402 if method == 'GET' or method == 'HEAD':
Raymond Hettinger54f02222002-06-01 14:18:47 +0000403 if 'QUERY_STRING' in environ:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000404 qs = environ['QUERY_STRING']
405 elif sys.argv[1:]:
406 qs = sys.argv[1]
407 else:
408 qs = ""
409 fp = StringIO(qs)
410 if headers is None:
411 headers = {'content-type':
412 "application/x-www-form-urlencoded"}
413 if headers is None:
Guido van Rossumcff311a1998-06-11 14:06:59 +0000414 headers = {}
415 if method == 'POST':
416 # Set default content-type for POST to what's traditional
417 headers['content-type'] = "application/x-www-form-urlencoded"
Raymond Hettinger54f02222002-06-01 14:18:47 +0000418 if 'CONTENT_TYPE' in environ:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000419 headers['content-type'] = environ['CONTENT_TYPE']
Benjamin Petersondcf97b92008-07-02 17:30:14 +0000420 if 'QUERY_STRING' in environ:
421 self.qs_on_post = environ['QUERY_STRING']
Raymond Hettinger54f02222002-06-01 14:18:47 +0000422 if 'CONTENT_LENGTH' in environ:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000423 headers['content-length'] = environ['CONTENT_LENGTH']
424 self.fp = fp or sys.stdin
425 self.headers = headers
426 self.outerboundary = outerboundary
Guido van Rossum7aee3841996-03-07 18:00:44 +0000427
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000428 # Process content-disposition header
429 cdisp, pdict = "", {}
Raymond Hettinger54f02222002-06-01 14:18:47 +0000430 if 'content-disposition' in self.headers:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000431 cdisp, pdict = parse_header(self.headers['content-disposition'])
432 self.disposition = cdisp
433 self.disposition_options = pdict
434 self.name = None
Raymond Hettinger54f02222002-06-01 14:18:47 +0000435 if 'name' in pdict:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000436 self.name = pdict['name']
437 self.filename = None
Raymond Hettinger54f02222002-06-01 14:18:47 +0000438 if 'filename' in pdict:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000439 self.filename = pdict['filename']
Guido van Rossum7aee3841996-03-07 18:00:44 +0000440
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000441 # Process content-type header
Barry Warsaw302331a1999-01-08 17:42:03 +0000442 #
443 # Honor any existing content-type header. But if there is no
444 # content-type header, use some sensible defaults. Assume
445 # outerboundary is "" at the outer level, but something non-false
446 # inside a multi-part. The default for an inner part is text/plain,
447 # but for an outer part it should be urlencoded. This should catch
448 # bogus clients which erroneously forget to include a content-type
449 # header.
450 #
451 # See below for what we do if there does exist a content-type header,
452 # but it happens to be something we don't understand.
Raymond Hettinger54f02222002-06-01 14:18:47 +0000453 if 'content-type' in self.headers:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000454 ctype, pdict = parse_header(self.headers['content-type'])
Guido van Rossumce900de1999-06-02 18:44:22 +0000455 elif self.outerboundary or method != 'POST':
Barry Warsaw302331a1999-01-08 17:42:03 +0000456 ctype, pdict = "text/plain", {}
457 else:
458 ctype, pdict = 'application/x-www-form-urlencoded', {}
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000459 self.type = ctype
460 self.type_options = pdict
461 self.innerboundary = ""
Raymond Hettinger54f02222002-06-01 14:18:47 +0000462 if 'boundary' in pdict:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000463 self.innerboundary = pdict['boundary']
464 clen = -1
Raymond Hettinger54f02222002-06-01 14:18:47 +0000465 if 'content-length' in self.headers:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000466 try:
Eric S. Raymond7e9b4f52001-02-09 09:59:10 +0000467 clen = int(self.headers['content-length'])
Skip Montanarodb5d1442002-03-23 05:50:17 +0000468 except ValueError:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000469 pass
470 if maxlen and clen > maxlen:
Collin Winterce36ad82007-08-30 01:19:48 +0000471 raise ValueError('Maximum content length exceeded')
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000472 self.length = clen
Guido van Rossum7aee3841996-03-07 18:00:44 +0000473
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000474 self.list = self.file = None
475 self.done = 0
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000476 if ctype == 'application/x-www-form-urlencoded':
477 self.read_urlencoded()
478 elif ctype[:10] == 'multipart/':
Guido van Rossumf5745001998-10-20 14:43:02 +0000479 self.read_multi(environ, keep_blank_values, strict_parsing)
Barry Warsaw302331a1999-01-08 17:42:03 +0000480 else:
Guido van Rossum60a3bd81999-06-11 18:26:09 +0000481 self.read_single()
Guido van Rossum7aee3841996-03-07 18:00:44 +0000482
483 def __repr__(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000484 """Return a printable representation."""
Walter Dörwald70a6b492004-02-12 17:35:32 +0000485 return "FieldStorage(%r, %r, %r)" % (
486 self.name, self.filename, self.value)
Guido van Rossum7aee3841996-03-07 18:00:44 +0000487
Guido van Rossum4061cbe2002-09-11 18:20:34 +0000488 def __iter__(self):
489 return iter(self.keys())
490
Guido van Rossum7aee3841996-03-07 18:00:44 +0000491 def __getattr__(self, name):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000492 if name != 'value':
Collin Winterce36ad82007-08-30 01:19:48 +0000493 raise AttributeError(name)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000494 if self.file:
495 self.file.seek(0)
496 value = self.file.read()
497 self.file.seek(0)
498 elif self.list is not None:
499 value = self.list
500 else:
501 value = None
502 return value
Guido van Rossum7aee3841996-03-07 18:00:44 +0000503
504 def __getitem__(self, key):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000505 """Dictionary style indexing."""
506 if self.list is None:
Collin Winterce36ad82007-08-30 01:19:48 +0000507 raise TypeError("not indexable")
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000508 found = []
509 for item in self.list:
510 if item.name == key: found.append(item)
511 if not found:
Collin Winterce36ad82007-08-30 01:19:48 +0000512 raise KeyError(key)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000513 if len(found) == 1:
514 return found[0]
515 else:
516 return found
Guido van Rossum7aee3841996-03-07 18:00:44 +0000517
Moshe Zadkaa1a4b592000-08-25 21:47:56 +0000518 def getvalue(self, key, default=None):
519 """Dictionary style get() method, including 'value' lookup."""
Raymond Hettinger54f02222002-06-01 14:18:47 +0000520 if key in self:
Moshe Zadkaa1a4b592000-08-25 21:47:56 +0000521 value = self[key]
522 if type(value) is type([]):
Guido van Rossumc1f779c2007-07-03 08:25:58 +0000523 return [x.value for x in value]
Moshe Zadkaa1a4b592000-08-25 21:47:56 +0000524 else:
525 return value.value
526 else:
527 return default
528
Guido van Rossum1bfb3882001-09-05 19:45:34 +0000529 def getfirst(self, key, default=None):
530 """ Return the first value received."""
Raymond Hettinger54f02222002-06-01 14:18:47 +0000531 if key in self:
Guido van Rossum1bfb3882001-09-05 19:45:34 +0000532 value = self[key]
533 if type(value) is type([]):
534 return value[0].value
535 else:
536 return value.value
537 else:
538 return default
539
540 def getlist(self, key):
541 """ Return list of received values."""
Raymond Hettinger54f02222002-06-01 14:18:47 +0000542 if key in self:
Guido van Rossum1bfb3882001-09-05 19:45:34 +0000543 value = self[key]
544 if type(value) is type([]):
Guido van Rossumc1f779c2007-07-03 08:25:58 +0000545 return [x.value for x in value]
Guido van Rossum1bfb3882001-09-05 19:45:34 +0000546 else:
547 return [value.value]
548 else:
549 return []
550
Guido van Rossum7aee3841996-03-07 18:00:44 +0000551 def keys(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000552 """Dictionary style keys() method."""
553 if self.list is None:
Collin Winterce36ad82007-08-30 01:19:48 +0000554 raise TypeError("not indexable")
Thomas Wouters8ce81f72007-09-20 18:22:40 +0000555 return list(set(item.name for item in self.list))
Guido van Rossum7aee3841996-03-07 18:00:44 +0000556
Raymond Hettinger54f02222002-06-01 14:18:47 +0000557 def __contains__(self, key):
558 """Dictionary style __contains__ method."""
559 if self.list is None:
Collin Winterce36ad82007-08-30 01:19:48 +0000560 raise TypeError("not indexable")
Thomas Wouters8ce81f72007-09-20 18:22:40 +0000561 return any(item.name == key for item in self.list)
Raymond Hettinger54f02222002-06-01 14:18:47 +0000562
Guido van Rossum88b85d41997-01-11 19:21:33 +0000563 def __len__(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000564 """Dictionary style len(x) support."""
565 return len(self.keys())
Guido van Rossum88b85d41997-01-11 19:21:33 +0000566
Thomas Wouters8ce81f72007-09-20 18:22:40 +0000567 def __nonzero__(self):
568 return bool(self.list)
569
Guido van Rossum7aee3841996-03-07 18:00:44 +0000570 def read_urlencoded(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000571 """Internal: read data in query string format."""
572 qs = self.fp.read(self.length)
Benjamin Petersondcf97b92008-07-02 17:30:14 +0000573 if self.qs_on_post:
574 qs += '&' + self.qs_on_post
Guido van Rossum1946f0d1999-06-04 17:54:39 +0000575 self.list = list = []
Facundo Batistac469d4c2008-09-03 22:49:01 +0000576 for key, value in urllib.parse.parse_qsl(qs, self.keep_blank_values,
577 self.strict_parsing):
Guido van Rossum1946f0d1999-06-04 17:54:39 +0000578 list.append(MiniFieldStorage(key, value))
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000579 self.skip_lines()
Guido van Rossum7aee3841996-03-07 18:00:44 +0000580
Guido van Rossum030d2ec1998-12-09 22:16:46 +0000581 FieldStorageClass = None
582
Guido van Rossumf5745001998-10-20 14:43:02 +0000583 def read_multi(self, environ, keep_blank_values, strict_parsing):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000584 """Internal: read a part that is itself multipart."""
Guido van Rossum2e441f72001-07-25 21:00:19 +0000585 ib = self.innerboundary
586 if not valid_boundary(ib):
Collin Winterce36ad82007-08-30 01:19:48 +0000587 raise ValueError('Invalid boundary in multipart form: %r' % (ib,))
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000588 self.list = []
Benjamin Petersondcf97b92008-07-02 17:30:14 +0000589 if self.qs_on_post:
Facundo Batistac469d4c2008-09-03 22:49:01 +0000590 for key, value in urllib.parse.parse_qsl(self.qs_on_post,
591 self.keep_blank_values, self.strict_parsing):
Benjamin Petersondcf97b92008-07-02 17:30:14 +0000592 self.list.append(MiniFieldStorage(key, value))
593 FieldStorageClass = None
594
Guido van Rossum030d2ec1998-12-09 22:16:46 +0000595 klass = self.FieldStorageClass or self.__class__
Barry Warsaw596097e2008-06-12 02:38:51 +0000596 parser = email.parser.FeedParser()
597 # Create bogus content-type header for proper multipart parsing
598 parser.feed('Content-Type: %s; boundary=%s\r\n\r\n' % (self.type, ib))
599 parser.feed(self.fp.read())
600 full_msg = parser.close()
601 # Get subparts
602 msgs = full_msg.get_payload()
603 for msg in msgs:
604 fp = StringIO(msg.get_payload())
605 part = klass(fp, msg, ib, environ, keep_blank_values,
606 strict_parsing)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000607 self.list.append(part)
608 self.skip_lines()
Guido van Rossum7aee3841996-03-07 18:00:44 +0000609
610 def read_single(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000611 """Internal: read an atomic part."""
612 if self.length >= 0:
613 self.read_binary()
614 self.skip_lines()
615 else:
616 self.read_lines()
617 self.file.seek(0)
Guido van Rossum7aee3841996-03-07 18:00:44 +0000618
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000619 bufsize = 8*1024 # I/O buffering size for copy to file
Guido van Rossum7aee3841996-03-07 18:00:44 +0000620
621 def read_binary(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000622 """Internal: read binary data."""
Guido van Rossuma1a68522007-08-28 03:11:34 +0000623 self.file = self.make_file()
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000624 todo = self.length
625 if todo >= 0:
626 while todo > 0:
627 data = self.fp.read(min(todo, self.bufsize))
628 if not data:
629 self.done = -1
630 break
631 self.file.write(data)
632 todo = todo - len(data)
Guido van Rossum7aee3841996-03-07 18:00:44 +0000633
634 def read_lines(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000635 """Internal: read lines until EOF or outerboundary."""
Guido van Rossum52b8c292001-06-29 13:06:06 +0000636 self.file = self.__file = StringIO()
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000637 if self.outerboundary:
638 self.read_lines_to_outerboundary()
639 else:
640 self.read_lines_to_eof()
Guido van Rossum7aee3841996-03-07 18:00:44 +0000641
Guido van Rossum52b8c292001-06-29 13:06:06 +0000642 def __write(self, line):
643 if self.__file is not None:
644 if self.__file.tell() + len(line) > 1000:
Guido van Rossuma1a68522007-08-28 03:11:34 +0000645 self.file = self.make_file()
646 data = self.__file.getvalue()
647 self.file.write(data)
Guido van Rossum52b8c292001-06-29 13:06:06 +0000648 self.__file = None
649 self.file.write(line)
650
Guido van Rossum7aee3841996-03-07 18:00:44 +0000651 def read_lines_to_eof(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000652 """Internal: read lines until EOF."""
653 while 1:
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000654 line = self.fp.readline(1<<16)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000655 if not line:
656 self.done = -1
657 break
Guido van Rossum52b8c292001-06-29 13:06:06 +0000658 self.__write(line)
Guido van Rossum7aee3841996-03-07 18:00:44 +0000659
660 def read_lines_to_outerboundary(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000661 """Internal: read lines until outerboundary."""
662 next = "--" + self.outerboundary
663 last = next + "--"
664 delim = ""
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000665 last_line_lfend = True
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000666 while 1:
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000667 line = self.fp.readline(1<<16)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000668 if not line:
669 self.done = -1
670 break
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000671 if line[:2] == "--" and last_line_lfend:
Eric S. Raymond7e9b4f52001-02-09 09:59:10 +0000672 strippedline = line.strip()
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000673 if strippedline == next:
674 break
675 if strippedline == last:
676 self.done = 1
677 break
678 odelim = delim
679 if line[-2:] == "\r\n":
680 delim = "\r\n"
681 line = line[:-2]
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000682 last_line_lfend = True
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000683 elif line[-1] == "\n":
684 delim = "\n"
685 line = line[:-1]
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000686 last_line_lfend = True
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000687 else:
688 delim = ""
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000689 last_line_lfend = False
Guido van Rossum52b8c292001-06-29 13:06:06 +0000690 self.__write(odelim + line)
Guido van Rossum7aee3841996-03-07 18:00:44 +0000691
692 def skip_lines(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000693 """Internal: skip lines until outer boundary if defined."""
694 if not self.outerboundary or self.done:
695 return
696 next = "--" + self.outerboundary
697 last = next + "--"
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000698 last_line_lfend = True
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000699 while 1:
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000700 line = self.fp.readline(1<<16)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000701 if not line:
702 self.done = -1
703 break
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000704 if line[:2] == "--" and last_line_lfend:
Eric S. Raymond7e9b4f52001-02-09 09:59:10 +0000705 strippedline = line.strip()
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000706 if strippedline == next:
707 break
708 if strippedline == last:
709 self.done = 1
710 break
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000711 last_line_lfend = line.endswith('\n')
Guido van Rossum7aee3841996-03-07 18:00:44 +0000712
Guido van Rossuma1a68522007-08-28 03:11:34 +0000713 def make_file(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000714 """Overridable: return a readable & writable file.
Guido van Rossum7aee3841996-03-07 18:00:44 +0000715
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000716 The file will be used as follows:
717 - data is written to it
718 - seek(0)
719 - data is read from it
Guido van Rossum7aee3841996-03-07 18:00:44 +0000720
Guido van Rossuma1a68522007-08-28 03:11:34 +0000721 The file is always opened in text mode.
Guido van Rossum7aee3841996-03-07 18:00:44 +0000722
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000723 This version opens a temporary file for reading and writing,
724 and immediately deletes (unlinks) it. The trick (on Unix!) is
725 that the file can still be used, but it can't be opened by
726 another process, and it will automatically be deleted when it
727 is closed or when the current process terminates.
Guido van Rossum4032c2c1996-03-09 04:04:35 +0000728
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000729 If you want a more permanent file, you derive a class which
730 overrides this method. If you want a visible temporary file
731 that is nevertheless automatically deleted when the script
732 terminates, try defining a __del__ method in a derived class
733 which unlinks the temporary files you have created.
Guido van Rossum7aee3841996-03-07 18:00:44 +0000734
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000735 """
736 import tempfile
Guido van Rossum92bab812007-08-28 03:32:38 +0000737 return tempfile.TemporaryFile("w+", encoding="utf-8", newline="\n")
Tim Peters88869f92001-01-14 23:36:06 +0000738
Guido van Rossum243ddcd1996-03-07 06:33:07 +0000739
Guido van Rossum72755611996-03-06 07:20:06 +0000740# Test/debug code
741# ===============
Guido van Rossum9a22de11995-01-12 12:29:47 +0000742
Guido van Rossum773ab271996-07-23 03:46:24 +0000743def test(environ=os.environ):
Guido van Rossum7aee3841996-03-07 18:00:44 +0000744 """Robust test CGI script, usable as main program.
Guido van Rossum9a22de11995-01-12 12:29:47 +0000745
Guido van Rossum7aee3841996-03-07 18:00:44 +0000746 Write minimal HTTP headers and dump all information provided to
747 the script in HTML form.
748
749 """
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000750 print("Content-type: text/html")
751 print()
Guido van Rossum7aee3841996-03-07 18:00:44 +0000752 sys.stderr = sys.stdout
753 try:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000754 form = FieldStorage() # Replace with other classes to test those
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000755 print_directory()
756 print_arguments()
Guido van Rossuma3c6a8a2000-09-19 04:11:46 +0000757 print_form(form)
758 print_environ(environ)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000759 print_environ_usage()
760 def f():
Georg Brandl7cae87c2006-09-06 06:51:57 +0000761 exec("testing print_exception() -- <I>italics?</I>")
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000762 def g(f=f):
763 f()
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000764 print("<H3>What follows is a test, not an actual exception:</H3>")
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000765 g()
Guido van Rossum7aee3841996-03-07 18:00:44 +0000766 except:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000767 print_exception()
Guido van Rossumf85de8a1996-08-20 20:22:39 +0000768
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000769 print("<H1>Second try with a small maxlen...</H1>")
Guido van Rossum57d51f22000-09-16 21:16:01 +0000770
Guido van Rossumad164711997-05-13 19:03:23 +0000771 global maxlen
772 maxlen = 50
773 try:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000774 form = FieldStorage() # Replace with other classes to test those
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000775 print_directory()
776 print_arguments()
Guido van Rossuma3c6a8a2000-09-19 04:11:46 +0000777 print_form(form)
778 print_environ(environ)
Guido van Rossumad164711997-05-13 19:03:23 +0000779 except:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000780 print_exception()
Guido van Rossumad164711997-05-13 19:03:23 +0000781
Guido van Rossumf85de8a1996-08-20 20:22:39 +0000782def print_exception(type=None, value=None, tb=None, limit=None):
783 if type is None:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000784 type, value, tb = sys.exc_info()
Guido van Rossumf85de8a1996-08-20 20:22:39 +0000785 import traceback
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000786 print()
787 print("<H3>Traceback (most recent call last):</H3>")
Guido van Rossumf85de8a1996-08-20 20:22:39 +0000788 list = traceback.format_tb(tb, limit) + \
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000789 traceback.format_exception_only(type, value)
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000790 print("<PRE>%s<B>%s</B></PRE>" % (
Eric S. Raymond7e9b4f52001-02-09 09:59:10 +0000791 escape("".join(list[:-1])),
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000792 escape(list[-1]),
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000793 ))
Guido van Rossumf15d1591997-09-29 23:22:12 +0000794 del tb
Guido van Rossum9a22de11995-01-12 12:29:47 +0000795
Guido van Rossum773ab271996-07-23 03:46:24 +0000796def print_environ(environ=os.environ):
Guido van Rossum7aee3841996-03-07 18:00:44 +0000797 """Dump the shell environment as HTML."""
Guido van Rossuma1a68522007-08-28 03:11:34 +0000798 keys = sorted(environ.keys())
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000799 print()
800 print("<H3>Shell Environment:</H3>")
801 print("<DL>")
Guido van Rossum7aee3841996-03-07 18:00:44 +0000802 for key in keys:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000803 print("<DT>", escape(key), "<DD>", escape(environ[key]))
804 print("</DL>")
805 print()
Guido van Rossum72755611996-03-06 07:20:06 +0000806
807def print_form(form):
Guido van Rossum7aee3841996-03-07 18:00:44 +0000808 """Dump the contents of a form as HTML."""
Guido van Rossuma1a68522007-08-28 03:11:34 +0000809 keys = sorted(form.keys())
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000810 print()
811 print("<H3>Form Contents:</H3>")
Guido van Rossum57d51f22000-09-16 21:16:01 +0000812 if not keys:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000813 print("<P>No form fields.")
814 print("<DL>")
Guido van Rossum7aee3841996-03-07 18:00:44 +0000815 for key in keys:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000816 print("<DT>" + escape(key) + ":", end=' ')
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000817 value = form[key]
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000818 print("<i>" + escape(repr(type(value))) + "</i>")
819 print("<DD>" + escape(repr(value)))
820 print("</DL>")
821 print()
Guido van Rossum7aee3841996-03-07 18:00:44 +0000822
823def print_directory():
824 """Dump the current directory as HTML."""
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000825 print()
826 print("<H3>Current Working Directory:</H3>")
Guido van Rossum7aee3841996-03-07 18:00:44 +0000827 try:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000828 pwd = os.getcwd()
Guido van Rossumb940e112007-01-10 16:19:56 +0000829 except os.error as msg:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000830 print("os.error:", escape(str(msg)))
Guido van Rossum7aee3841996-03-07 18:00:44 +0000831 else:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000832 print(escape(pwd))
833 print()
Guido van Rossum9a22de11995-01-12 12:29:47 +0000834
Guido van Rossuma8738a51996-03-14 21:30:28 +0000835def print_arguments():
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000836 print()
837 print("<H3>Command Line Arguments:</H3>")
838 print()
839 print(sys.argv)
840 print()
Guido van Rossuma8738a51996-03-14 21:30:28 +0000841
Guido van Rossum9a22de11995-01-12 12:29:47 +0000842def print_environ_usage():
Guido van Rossum7aee3841996-03-07 18:00:44 +0000843 """Dump a list of environment variables used by CGI as HTML."""
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000844 print("""
Guido van Rossum72755611996-03-06 07:20:06 +0000845<H3>These environment variables could have been set:</H3>
846<UL>
Guido van Rossum9a22de11995-01-12 12:29:47 +0000847<LI>AUTH_TYPE
848<LI>CONTENT_LENGTH
849<LI>CONTENT_TYPE
850<LI>DATE_GMT
851<LI>DATE_LOCAL
852<LI>DOCUMENT_NAME
853<LI>DOCUMENT_ROOT
854<LI>DOCUMENT_URI
855<LI>GATEWAY_INTERFACE
856<LI>LAST_MODIFIED
857<LI>PATH
858<LI>PATH_INFO
859<LI>PATH_TRANSLATED
860<LI>QUERY_STRING
861<LI>REMOTE_ADDR
862<LI>REMOTE_HOST
863<LI>REMOTE_IDENT
864<LI>REMOTE_USER
865<LI>REQUEST_METHOD
866<LI>SCRIPT_NAME
867<LI>SERVER_NAME
868<LI>SERVER_PORT
869<LI>SERVER_PROTOCOL
870<LI>SERVER_ROOT
871<LI>SERVER_SOFTWARE
872</UL>
Guido van Rossum7aee3841996-03-07 18:00:44 +0000873In addition, HTTP headers sent by the server may be passed in the
874environment as well. Here are some common variable names:
875<UL>
876<LI>HTTP_ACCEPT
877<LI>HTTP_CONNECTION
878<LI>HTTP_HOST
879<LI>HTTP_PRAGMA
880<LI>HTTP_REFERER
881<LI>HTTP_USER_AGENT
882</UL>
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000883""")
Guido van Rossum9a22de11995-01-12 12:29:47 +0000884
Guido van Rossum9a22de11995-01-12 12:29:47 +0000885
Guido van Rossum72755611996-03-06 07:20:06 +0000886# Utilities
887# =========
Guido van Rossum9a22de11995-01-12 12:29:47 +0000888
Guido van Rossum64c66201997-07-19 20:11:53 +0000889def escape(s, quote=None):
Skip Montanaro97b2fa22005-08-02 02:50:25 +0000890 '''Replace special characters "&", "<" and ">" to HTML-safe sequences.
891 If the optional flag quote is true, the quotation mark character (")
892 is also translated.'''
Eric S. Raymond7e9b4f52001-02-09 09:59:10 +0000893 s = s.replace("&", "&amp;") # Must be done first!
894 s = s.replace("<", "&lt;")
895 s = s.replace(">", "&gt;")
Guido van Rossum64c66201997-07-19 20:11:53 +0000896 if quote:
Eric S. Raymond7e9b4f52001-02-09 09:59:10 +0000897 s = s.replace('"', "&quot;")
Guido van Rossum7aee3841996-03-07 18:00:44 +0000898 return s
Guido van Rossum9a22de11995-01-12 12:29:47 +0000899
Guido van Rossum2e441f72001-07-25 21:00:19 +0000900def valid_boundary(s, _vb_pattern="^[ -~]{0,200}[!-~]$"):
901 import re
902 return re.match(_vb_pattern, s)
Guido van Rossum9a22de11995-01-12 12:29:47 +0000903
Guido van Rossum72755611996-03-06 07:20:06 +0000904# Invoke mainline
905# ===============
906
907# Call test() when this file is run as a script (not imported as a module)
Tim Peters88869f92001-01-14 23:36:06 +0000908if __name__ == '__main__':
Guido van Rossum7aee3841996-03-07 18:00:44 +0000909 test()