Bump version number to 2.4.2 to pick up the latest minor bug fixes.
[python/dscho.git] / Lib / cgi.py
blobcf0146f407274ee797cbd548daf8bbc404787420
1 #! /usr/local/bin/python
3 # 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.
12 """Support module for CGI (Common Gateway Interface) scripts.
14 This module defines a number of utilities for use by CGI scripts
15 written in Python.
16 """
18 # XXX Perhaps there should be a slimmed version that doesn't contain
19 # all those backwards compatible and debugging classes and functions?
21 # History
22 # -------
24 # Michael McLay started this module. Steve Majewski changed the
25 # interface to SvFormContentDict and FormContentDict. The multipart
26 # parsing was inspired by code submitted by Andreas Paepcke. Guido van
27 # Rossum rewrote, reformatted and documented the module and is currently
28 # responsible for its maintenance.
31 __version__ = "2.6"
34 # Imports
35 # =======
37 import sys
38 import os
39 import urllib
40 import mimetools
41 import rfc822
42 import UserDict
43 from StringIO import StringIO
45 __all__ = ["MiniFieldStorage", "FieldStorage", "FormContentDict",
46 "SvFormContentDict", "InterpFormContentDict", "FormContent",
47 "parse", "parse_qs", "parse_qsl", "parse_multipart",
48 "parse_header", "print_exception", "print_environ",
49 "print_form", "print_directory", "print_arguments",
50 "print_environ_usage", "escape"]
52 # Logging support
53 # ===============
55 logfile = "" # Filename to log to, if not empty
56 logfp = None # File object to log to, if not None
58 def initlog(*allargs):
59 """Write a log message, if there is a log file.
61 Even though this function is called initlog(), you should always
62 use log(); log is a variable that is set either to initlog
63 (initially), to dolog (once the log file has been opened), or to
64 nolog (when logging is disabled).
66 The first argument is a format string; the remaining arguments (if
67 any) are arguments to the % operator, so e.g.
68 log("%s: %s", "a", "b")
69 will write "a: b" to the log file, followed by a newline.
71 If the global logfp is not None, it should be a file object to
72 which log data is written.
74 If the global logfp is None, the global logfile may be a string
75 giving a filename to open, in append mode. This file should be
76 world writable!!! If the file can't be opened, logging is
77 silently disabled (since there is no safe place where we could
78 send an error message).
80 """
81 global logfp, log
82 if logfile and not logfp:
83 try:
84 logfp = open(logfile, "a")
85 except IOError:
86 pass
87 if not logfp:
88 log = nolog
89 else:
90 log = dolog
91 apply(log, allargs)
93 def dolog(fmt, *args):
94 """Write a log message to the log file. See initlog() for docs."""
95 logfp.write(fmt%args + "\n")
97 def nolog(*allargs):
98 """Dummy function, assigned to log when logging is disabled."""
99 pass
101 log = initlog # The current logging function
104 # Parsing functions
105 # =================
107 # Maximum input we will accept when REQUEST_METHOD is POST
108 # 0 ==> unlimited input
109 maxlen = 0
111 def parse(fp=None, environ=os.environ, keep_blank_values=0, strict_parsing=0):
112 """Parse a query in the environment or from a file (default stdin)
114 Arguments, all optional:
116 fp : file pointer; default: sys.stdin
118 environ : environment dictionary; default: os.environ
120 keep_blank_values: flag indicating whether blank values in
121 URL encoded forms should be treated as blank strings.
122 A true value indicates that blanks should be retained as
123 blank strings. The default false value indicates that
124 blank values are to be ignored and treated as if they were
125 not included.
127 strict_parsing: flag indicating what to do with parsing errors.
128 If false (the default), errors are silently ignored.
129 If true, errors raise a ValueError exception.
131 if fp is None:
132 fp = sys.stdin
133 if not 'REQUEST_METHOD' in environ:
134 environ['REQUEST_METHOD'] = 'GET' # For testing stand-alone
135 if environ['REQUEST_METHOD'] == 'POST':
136 ctype, pdict = parse_header(environ['CONTENT_TYPE'])
137 if ctype == 'multipart/form-data':
138 return parse_multipart(fp, pdict)
139 elif ctype == 'application/x-www-form-urlencoded':
140 clength = int(environ['CONTENT_LENGTH'])
141 if maxlen and clength > maxlen:
142 raise ValueError, 'Maximum content length exceeded'
143 qs = fp.read(clength)
144 else:
145 qs = '' # Unknown content-type
146 if 'QUERY_STRING' in environ:
147 if qs: qs = qs + '&'
148 qs = qs + environ['QUERY_STRING']
149 elif sys.argv[1:]:
150 if qs: qs = qs + '&'
151 qs = qs + sys.argv[1]
152 environ['QUERY_STRING'] = qs # XXX Shouldn't, really
153 elif 'QUERY_STRING' in environ:
154 qs = environ['QUERY_STRING']
155 else:
156 if sys.argv[1:]:
157 qs = sys.argv[1]
158 else:
159 qs = ""
160 environ['QUERY_STRING'] = qs # XXX Shouldn't, really
161 return parse_qs(qs, keep_blank_values, strict_parsing)
164 def parse_qs(qs, keep_blank_values=0, strict_parsing=0):
165 """Parse a query given as a string argument.
167 Arguments:
169 qs: URL-encoded query string to be parsed
171 keep_blank_values: flag indicating whether blank values in
172 URL encoded queries should be treated as blank strings.
173 A true value indicates that blanks should be retained as
174 blank strings. The default false value indicates that
175 blank values are to be ignored and treated as if they were
176 not included.
178 strict_parsing: flag indicating what to do with parsing errors.
179 If false (the default), errors are silently ignored.
180 If true, errors raise a ValueError exception.
182 dict = {}
183 for name, value in parse_qsl(qs, keep_blank_values, strict_parsing):
184 if name in dict:
185 dict[name].append(value)
186 else:
187 dict[name] = [value]
188 return dict
190 def parse_qsl(qs, keep_blank_values=0, strict_parsing=0):
191 """Parse a query given as a string argument.
193 Arguments:
195 qs: URL-encoded query string to be parsed
197 keep_blank_values: flag indicating whether blank values in
198 URL encoded queries should be treated as blank strings. A
199 true value indicates that blanks should be retained as blank
200 strings. The default false value indicates that blank values
201 are to be ignored and treated as if they were not included.
203 strict_parsing: flag indicating what to do with parsing errors. If
204 false (the default), errors are silently ignored. If true,
205 errors raise a ValueError exception.
207 Returns a list, as G-d intended.
209 pairs = [s2 for s1 in qs.split('&') for s2 in s1.split(';')]
210 r = []
211 for name_value in pairs:
212 nv = name_value.split('=', 1)
213 if len(nv) != 2:
214 if strict_parsing:
215 raise ValueError, "bad query field: %s" % `name_value`
216 continue
217 if len(nv[1]) or keep_blank_values:
218 name = urllib.unquote(nv[0].replace('+', ' '))
219 value = urllib.unquote(nv[1].replace('+', ' '))
220 r.append((name, value))
222 return r
225 def parse_multipart(fp, pdict):
226 """Parse multipart input.
228 Arguments:
229 fp : input file
230 pdict: dictionary containing other parameters of conten-type header
232 Returns a dictionary just like parse_qs(): keys are the field names, each
233 value is a list of values for that field. This is easy to use but not
234 much good if you are expecting megabytes to be uploaded -- in that case,
235 use the FieldStorage class instead which is much more flexible. Note
236 that content-type is the raw, unparsed contents of the content-type
237 header.
239 XXX This does not parse nested multipart parts -- use FieldStorage for
240 that.
242 XXX This should really be subsumed by FieldStorage altogether -- no
243 point in having two implementations of the same parsing algorithm.
246 boundary = ""
247 if 'boundary' in pdict:
248 boundary = pdict['boundary']
249 if not valid_boundary(boundary):
250 raise ValueError, ('Invalid boundary in multipart form: %s'
251 % `boundary`)
253 nextpart = "--" + boundary
254 lastpart = "--" + boundary + "--"
255 partdict = {}
256 terminator = ""
258 while terminator != lastpart:
259 bytes = -1
260 data = None
261 if terminator:
262 # At start of next part. Read headers first.
263 headers = mimetools.Message(fp)
264 clength = headers.getheader('content-length')
265 if clength:
266 try:
267 bytes = int(clength)
268 except ValueError:
269 pass
270 if bytes > 0:
271 if maxlen and bytes > maxlen:
272 raise ValueError, 'Maximum content length exceeded'
273 data = fp.read(bytes)
274 else:
275 data = ""
276 # Read lines until end of part.
277 lines = []
278 while 1:
279 line = fp.readline()
280 if not line:
281 terminator = lastpart # End outer loop
282 break
283 if line[:2] == "--":
284 terminator = line.strip()
285 if terminator in (nextpart, lastpart):
286 break
287 lines.append(line)
288 # Done with part.
289 if data is None:
290 continue
291 if bytes < 0:
292 if lines:
293 # Strip final line terminator
294 line = lines[-1]
295 if line[-2:] == "\r\n":
296 line = line[:-2]
297 elif line[-1:] == "\n":
298 line = line[:-1]
299 lines[-1] = line
300 data = "".join(lines)
301 line = headers['content-disposition']
302 if not line:
303 continue
304 key, params = parse_header(line)
305 if key != 'form-data':
306 continue
307 if 'name' in params:
308 name = params['name']
309 else:
310 continue
311 if name in partdict:
312 partdict[name].append(data)
313 else:
314 partdict[name] = [data]
316 return partdict
319 def parse_header(line):
320 """Parse a Content-type like header.
322 Return the main content-type and a dictionary of options.
325 plist = map(lambda x: x.strip(), line.split(';'))
326 key = plist.pop(0).lower()
327 pdict = {}
328 for p in plist:
329 i = p.find('=')
330 if i >= 0:
331 name = p[:i].strip().lower()
332 value = p[i+1:].strip()
333 if len(value) >= 2 and value[0] == value[-1] == '"':
334 value = value[1:-1]
335 pdict[name] = value
336 return key, pdict
339 # Classes for field storage
340 # =========================
342 class MiniFieldStorage:
344 """Like FieldStorage, for use when no file uploads are possible."""
346 # Dummy attributes
347 filename = None
348 list = None
349 type = None
350 file = None
351 type_options = {}
352 disposition = None
353 disposition_options = {}
354 headers = {}
356 def __init__(self, name, value):
357 """Constructor from field name and value."""
358 self.name = name
359 self.value = value
360 # self.file = StringIO(value)
362 def __repr__(self):
363 """Return printable representation."""
364 return "MiniFieldStorage(%s, %s)" % (`self.name`, `self.value`)
367 class FieldStorage:
369 """Store a sequence of fields, reading multipart/form-data.
371 This class provides naming, typing, files stored on disk, and
372 more. At the top level, it is accessible like a dictionary, whose
373 keys are the field names. (Note: None can occur as a field name.)
374 The items are either a Python list (if there's multiple values) or
375 another FieldStorage or MiniFieldStorage object. If it's a single
376 object, it has the following attributes:
378 name: the field name, if specified; otherwise None
380 filename: the filename, if specified; otherwise None; this is the
381 client side filename, *not* the file name on which it is
382 stored (that's a temporary file you don't deal with)
384 value: the value as a *string*; for file uploads, this
385 transparently reads the file every time you request the value
387 file: the file(-like) object from which you can read the data;
388 None if the data is stored a simple string
390 type: the content-type, or None if not specified
392 type_options: dictionary of options specified on the content-type
393 line
395 disposition: content-disposition, or None if not specified
397 disposition_options: dictionary of corresponding options
399 headers: a dictionary(-like) object (sometimes rfc822.Message or a
400 subclass thereof) containing *all* headers
402 The class is subclassable, mostly for the purpose of overriding
403 the make_file() method, which is called internally to come up with
404 a file open for reading and writing. This makes it possible to
405 override the default choice of storing all files in a temporary
406 directory and unlinking them as soon as they have been opened.
410 def __init__(self, fp=None, headers=None, outerboundary="",
411 environ=os.environ, keep_blank_values=0, strict_parsing=0):
412 """Constructor. Read multipart/* until last part.
414 Arguments, all optional:
416 fp : file pointer; default: sys.stdin
417 (not used when the request method is GET)
419 headers : header dictionary-like object; default:
420 taken from environ as per CGI spec
422 outerboundary : terminating multipart boundary
423 (for internal use only)
425 environ : environment dictionary; default: os.environ
427 keep_blank_values: flag indicating whether blank values in
428 URL encoded forms should be treated as blank strings.
429 A true value indicates that blanks should be retained as
430 blank strings. The default false value indicates that
431 blank values are to be ignored and treated as if they were
432 not included.
434 strict_parsing: flag indicating what to do with parsing errors.
435 If false (the default), errors are silently ignored.
436 If true, errors raise a ValueError exception.
439 method = 'GET'
440 self.keep_blank_values = keep_blank_values
441 self.strict_parsing = strict_parsing
442 if 'REQUEST_METHOD' in environ:
443 method = environ['REQUEST_METHOD'].upper()
444 if method == 'GET' or method == 'HEAD':
445 if 'QUERY_STRING' in environ:
446 qs = environ['QUERY_STRING']
447 elif sys.argv[1:]:
448 qs = sys.argv[1]
449 else:
450 qs = ""
451 fp = StringIO(qs)
452 if headers is None:
453 headers = {'content-type':
454 "application/x-www-form-urlencoded"}
455 if headers is None:
456 headers = {}
457 if method == 'POST':
458 # Set default content-type for POST to what's traditional
459 headers['content-type'] = "application/x-www-form-urlencoded"
460 if 'CONTENT_TYPE' in environ:
461 headers['content-type'] = environ['CONTENT_TYPE']
462 if 'CONTENT_LENGTH' in environ:
463 headers['content-length'] = environ['CONTENT_LENGTH']
464 self.fp = fp or sys.stdin
465 self.headers = headers
466 self.outerboundary = outerboundary
468 # Process content-disposition header
469 cdisp, pdict = "", {}
470 if 'content-disposition' in self.headers:
471 cdisp, pdict = parse_header(self.headers['content-disposition'])
472 self.disposition = cdisp
473 self.disposition_options = pdict
474 self.name = None
475 if 'name' in pdict:
476 self.name = pdict['name']
477 self.filename = None
478 if 'filename' in pdict:
479 self.filename = pdict['filename']
481 # Process content-type header
483 # Honor any existing content-type header. But if there is no
484 # content-type header, use some sensible defaults. Assume
485 # outerboundary is "" at the outer level, but something non-false
486 # inside a multi-part. The default for an inner part is text/plain,
487 # but for an outer part it should be urlencoded. This should catch
488 # bogus clients which erroneously forget to include a content-type
489 # header.
491 # See below for what we do if there does exist a content-type header,
492 # but it happens to be something we don't understand.
493 if 'content-type' in self.headers:
494 ctype, pdict = parse_header(self.headers['content-type'])
495 elif self.outerboundary or method != 'POST':
496 ctype, pdict = "text/plain", {}
497 else:
498 ctype, pdict = 'application/x-www-form-urlencoded', {}
499 self.type = ctype
500 self.type_options = pdict
501 self.innerboundary = ""
502 if 'boundary' in pdict:
503 self.innerboundary = pdict['boundary']
504 clen = -1
505 if 'content-length' in self.headers:
506 try:
507 clen = int(self.headers['content-length'])
508 except ValueError:
509 pass
510 if maxlen and clen > maxlen:
511 raise ValueError, 'Maximum content length exceeded'
512 self.length = clen
514 self.list = self.file = None
515 self.done = 0
516 if ctype == 'application/x-www-form-urlencoded':
517 self.read_urlencoded()
518 elif ctype[:10] == 'multipart/':
519 self.read_multi(environ, keep_blank_values, strict_parsing)
520 else:
521 self.read_single()
523 def __repr__(self):
524 """Return a printable representation."""
525 return "FieldStorage(%s, %s, %s)" % (
526 `self.name`, `self.filename`, `self.value`)
528 def __iter__(self):
529 return iter(self.keys())
531 def __getattr__(self, name):
532 if name != 'value':
533 raise AttributeError, name
534 if self.file:
535 self.file.seek(0)
536 value = self.file.read()
537 self.file.seek(0)
538 elif self.list is not None:
539 value = self.list
540 else:
541 value = None
542 return value
544 def __getitem__(self, key):
545 """Dictionary style indexing."""
546 if self.list is None:
547 raise TypeError, "not indexable"
548 found = []
549 for item in self.list:
550 if item.name == key: found.append(item)
551 if not found:
552 raise KeyError, key
553 if len(found) == 1:
554 return found[0]
555 else:
556 return found
558 def getvalue(self, key, default=None):
559 """Dictionary style get() method, including 'value' lookup."""
560 if key in self:
561 value = self[key]
562 if type(value) is type([]):
563 return map(lambda v: v.value, value)
564 else:
565 return value.value
566 else:
567 return default
569 def getfirst(self, key, default=None):
570 """ Return the first value received."""
571 if key in self:
572 value = self[key]
573 if type(value) is type([]):
574 return value[0].value
575 else:
576 return value.value
577 else:
578 return default
580 def getlist(self, key):
581 """ Return list of received values."""
582 if key in self:
583 value = self[key]
584 if type(value) is type([]):
585 return map(lambda v: v.value, value)
586 else:
587 return [value.value]
588 else:
589 return []
591 def keys(self):
592 """Dictionary style keys() method."""
593 if self.list is None:
594 raise TypeError, "not indexable"
595 keys = []
596 for item in self.list:
597 if item.name not in keys: keys.append(item.name)
598 return keys
600 def has_key(self, key):
601 """Dictionary style has_key() method."""
602 if self.list is None:
603 raise TypeError, "not indexable"
604 for item in self.list:
605 if item.name == key: return True
606 return False
608 def __contains__(self, key):
609 """Dictionary style __contains__ method."""
610 if self.list is None:
611 raise TypeError, "not indexable"
612 for item in self.list:
613 if item.name == key: return True
614 return False
616 def __len__(self):
617 """Dictionary style len(x) support."""
618 return len(self.keys())
620 def read_urlencoded(self):
621 """Internal: read data in query string format."""
622 qs = self.fp.read(self.length)
623 self.list = list = []
624 for key, value in parse_qsl(qs, self.keep_blank_values,
625 self.strict_parsing):
626 list.append(MiniFieldStorage(key, value))
627 self.skip_lines()
629 FieldStorageClass = None
631 def read_multi(self, environ, keep_blank_values, strict_parsing):
632 """Internal: read a part that is itself multipart."""
633 ib = self.innerboundary
634 if not valid_boundary(ib):
635 raise ValueError, ('Invalid boundary in multipart form: %s'
636 % `ib`)
637 self.list = []
638 klass = self.FieldStorageClass or self.__class__
639 part = klass(self.fp, {}, ib,
640 environ, keep_blank_values, strict_parsing)
641 # Throw first part away
642 while not part.done:
643 headers = rfc822.Message(self.fp)
644 part = klass(self.fp, headers, ib,
645 environ, keep_blank_values, strict_parsing)
646 self.list.append(part)
647 self.skip_lines()
649 def read_single(self):
650 """Internal: read an atomic part."""
651 if self.length >= 0:
652 self.read_binary()
653 self.skip_lines()
654 else:
655 self.read_lines()
656 self.file.seek(0)
658 bufsize = 8*1024 # I/O buffering size for copy to file
660 def read_binary(self):
661 """Internal: read binary data."""
662 self.file = self.make_file('b')
663 todo = self.length
664 if todo >= 0:
665 while todo > 0:
666 data = self.fp.read(min(todo, self.bufsize))
667 if not data:
668 self.done = -1
669 break
670 self.file.write(data)
671 todo = todo - len(data)
673 def read_lines(self):
674 """Internal: read lines until EOF or outerboundary."""
675 self.file = self.__file = StringIO()
676 if self.outerboundary:
677 self.read_lines_to_outerboundary()
678 else:
679 self.read_lines_to_eof()
681 def __write(self, line):
682 if self.__file is not None:
683 if self.__file.tell() + len(line) > 1000:
684 self.file = self.make_file('')
685 self.file.write(self.__file.getvalue())
686 self.__file = None
687 self.file.write(line)
689 def read_lines_to_eof(self):
690 """Internal: read lines until EOF."""
691 while 1:
692 line = self.fp.readline()
693 if not line:
694 self.done = -1
695 break
696 self.__write(line)
698 def read_lines_to_outerboundary(self):
699 """Internal: read lines until outerboundary."""
700 next = "--" + self.outerboundary
701 last = next + "--"
702 delim = ""
703 while 1:
704 line = self.fp.readline()
705 if not line:
706 self.done = -1
707 break
708 if line[:2] == "--":
709 strippedline = line.strip()
710 if strippedline == next:
711 break
712 if strippedline == last:
713 self.done = 1
714 break
715 odelim = delim
716 if line[-2:] == "\r\n":
717 delim = "\r\n"
718 line = line[:-2]
719 elif line[-1] == "\n":
720 delim = "\n"
721 line = line[:-1]
722 else:
723 delim = ""
724 self.__write(odelim + line)
726 def skip_lines(self):
727 """Internal: skip lines until outer boundary if defined."""
728 if not self.outerboundary or self.done:
729 return
730 next = "--" + self.outerboundary
731 last = next + "--"
732 while 1:
733 line = self.fp.readline()
734 if not line:
735 self.done = -1
736 break
737 if line[:2] == "--":
738 strippedline = line.strip()
739 if strippedline == next:
740 break
741 if strippedline == last:
742 self.done = 1
743 break
745 def make_file(self, binary=None):
746 """Overridable: return a readable & writable file.
748 The file will be used as follows:
749 - data is written to it
750 - seek(0)
751 - data is read from it
753 The 'binary' argument is unused -- the file is always opened
754 in binary mode.
756 This version opens a temporary file for reading and writing,
757 and immediately deletes (unlinks) it. The trick (on Unix!) is
758 that the file can still be used, but it can't be opened by
759 another process, and it will automatically be deleted when it
760 is closed or when the current process terminates.
762 If you want a more permanent file, you derive a class which
763 overrides this method. If you want a visible temporary file
764 that is nevertheless automatically deleted when the script
765 terminates, try defining a __del__ method in a derived class
766 which unlinks the temporary files you have created.
769 import tempfile
770 return tempfile.TemporaryFile("w+b")
774 # Backwards Compatibility Classes
775 # ===============================
777 class FormContentDict(UserDict.UserDict):
778 """Form content as dictionary with a list of values per field.
780 form = FormContentDict()
782 form[key] -> [value, value, ...]
783 key in form -> Boolean
784 form.keys() -> [key, key, ...]
785 form.values() -> [[val, val, ...], [val, val, ...], ...]
786 form.items() -> [(key, [val, val, ...]), (key, [val, val, ...]), ...]
787 form.dict == {key: [val, val, ...], ...}
790 def __init__(self, environ=os.environ):
791 self.dict = self.data = parse(environ=environ)
792 self.query_string = environ['QUERY_STRING']
795 class SvFormContentDict(FormContentDict):
796 """Form content as dictionary expecting a single value per field.
798 If you only expect a single value for each field, then form[key]
799 will return that single value. It will raise an IndexError if
800 that expectation is not true. If you expect a field to have
801 possible multiple values, than you can use form.getlist(key) to
802 get all of the values. values() and items() are a compromise:
803 they return single strings where there is a single value, and
804 lists of strings otherwise.
807 def __getitem__(self, key):
808 if len(self.dict[key]) > 1:
809 raise IndexError, 'expecting a single value'
810 return self.dict[key][0]
811 def getlist(self, key):
812 return self.dict[key]
813 def values(self):
814 result = []
815 for value in self.dict.values():
816 if len(value) == 1:
817 result.append(value[0])
818 else: result.append(value)
819 return result
820 def items(self):
821 result = []
822 for key, value in self.dict.items():
823 if len(value) == 1:
824 result.append((key, value[0]))
825 else: result.append((key, value))
826 return result
829 class InterpFormContentDict(SvFormContentDict):
830 """This class is present for backwards compatibility only."""
831 def __getitem__(self, key):
832 v = SvFormContentDict.__getitem__(self, key)
833 if v[0] in '0123456789+-.':
834 try: return int(v)
835 except ValueError:
836 try: return float(v)
837 except ValueError: pass
838 return v.strip()
839 def values(self):
840 result = []
841 for key in self.keys():
842 try:
843 result.append(self[key])
844 except IndexError:
845 result.append(self.dict[key])
846 return result
847 def items(self):
848 result = []
849 for key in self.keys():
850 try:
851 result.append((key, self[key]))
852 except IndexError:
853 result.append((key, self.dict[key]))
854 return result
857 class FormContent(FormContentDict):
858 """This class is present for backwards compatibility only."""
859 def values(self, key):
860 if key in self.dict :return self.dict[key]
861 else: return None
862 def indexed_value(self, key, location):
863 if key in self.dict:
864 if len(self.dict[key]) > location:
865 return self.dict[key][location]
866 else: return None
867 else: return None
868 def value(self, key):
869 if key in self.dict: return self.dict[key][0]
870 else: return None
871 def length(self, key):
872 return len(self.dict[key])
873 def stripped(self, key):
874 if key in self.dict: return self.dict[key][0].strip()
875 else: return None
876 def pars(self):
877 return self.dict
880 # Test/debug code
881 # ===============
883 def test(environ=os.environ):
884 """Robust test CGI script, usable as main program.
886 Write minimal HTTP headers and dump all information provided to
887 the script in HTML form.
890 print "Content-type: text/html"
891 print
892 sys.stderr = sys.stdout
893 try:
894 form = FieldStorage() # Replace with other classes to test those
895 print_directory()
896 print_arguments()
897 print_form(form)
898 print_environ(environ)
899 print_environ_usage()
900 def f():
901 exec "testing print_exception() -- <I>italics?</I>"
902 def g(f=f):
904 print "<H3>What follows is a test, not an actual exception:</H3>"
906 except:
907 print_exception()
909 print "<H1>Second try with a small maxlen...</H1>"
911 global maxlen
912 maxlen = 50
913 try:
914 form = FieldStorage() # Replace with other classes to test those
915 print_directory()
916 print_arguments()
917 print_form(form)
918 print_environ(environ)
919 except:
920 print_exception()
922 def print_exception(type=None, value=None, tb=None, limit=None):
923 if type is None:
924 type, value, tb = sys.exc_info()
925 import traceback
926 print
927 print "<H3>Traceback (most recent call last):</H3>"
928 list = traceback.format_tb(tb, limit) + \
929 traceback.format_exception_only(type, value)
930 print "<PRE>%s<B>%s</B></PRE>" % (
931 escape("".join(list[:-1])),
932 escape(list[-1]),
934 del tb
936 def print_environ(environ=os.environ):
937 """Dump the shell environment as HTML."""
938 keys = environ.keys()
939 keys.sort()
940 print
941 print "<H3>Shell Environment:</H3>"
942 print "<DL>"
943 for key in keys:
944 print "<DT>", escape(key), "<DD>", escape(environ[key])
945 print "</DL>"
946 print
948 def print_form(form):
949 """Dump the contents of a form as HTML."""
950 keys = form.keys()
951 keys.sort()
952 print
953 print "<H3>Form Contents:</H3>"
954 if not keys:
955 print "<P>No form fields."
956 print "<DL>"
957 for key in keys:
958 print "<DT>" + escape(key) + ":",
959 value = form[key]
960 print "<i>" + escape(`type(value)`) + "</i>"
961 print "<DD>" + escape(`value`)
962 print "</DL>"
963 print
965 def print_directory():
966 """Dump the current directory as HTML."""
967 print
968 print "<H3>Current Working Directory:</H3>"
969 try:
970 pwd = os.getcwd()
971 except os.error, msg:
972 print "os.error:", escape(str(msg))
973 else:
974 print escape(pwd)
975 print
977 def print_arguments():
978 print
979 print "<H3>Command Line Arguments:</H3>"
980 print
981 print sys.argv
982 print
984 def print_environ_usage():
985 """Dump a list of environment variables used by CGI as HTML."""
986 print """
987 <H3>These environment variables could have been set:</H3>
988 <UL>
989 <LI>AUTH_TYPE
990 <LI>CONTENT_LENGTH
991 <LI>CONTENT_TYPE
992 <LI>DATE_GMT
993 <LI>DATE_LOCAL
994 <LI>DOCUMENT_NAME
995 <LI>DOCUMENT_ROOT
996 <LI>DOCUMENT_URI
997 <LI>GATEWAY_INTERFACE
998 <LI>LAST_MODIFIED
999 <LI>PATH
1000 <LI>PATH_INFO
1001 <LI>PATH_TRANSLATED
1002 <LI>QUERY_STRING
1003 <LI>REMOTE_ADDR
1004 <LI>REMOTE_HOST
1005 <LI>REMOTE_IDENT
1006 <LI>REMOTE_USER
1007 <LI>REQUEST_METHOD
1008 <LI>SCRIPT_NAME
1009 <LI>SERVER_NAME
1010 <LI>SERVER_PORT
1011 <LI>SERVER_PROTOCOL
1012 <LI>SERVER_ROOT
1013 <LI>SERVER_SOFTWARE
1014 </UL>
1015 In addition, HTTP headers sent by the server may be passed in the
1016 environment as well. Here are some common variable names:
1017 <UL>
1018 <LI>HTTP_ACCEPT
1019 <LI>HTTP_CONNECTION
1020 <LI>HTTP_HOST
1021 <LI>HTTP_PRAGMA
1022 <LI>HTTP_REFERER
1023 <LI>HTTP_USER_AGENT
1024 </UL>
1028 # Utilities
1029 # =========
1031 def escape(s, quote=None):
1032 """Replace special characters '&', '<' and '>' by SGML entities."""
1033 s = s.replace("&", "&amp;") # Must be done first!
1034 s = s.replace("<", "&lt;")
1035 s = s.replace(">", "&gt;")
1036 if quote:
1037 s = s.replace('"', "&quot;")
1038 return s
1040 def valid_boundary(s, _vb_pattern="^[ -~]{0,200}[!-~]$"):
1041 import re
1042 return re.match(_vb_pattern, s)
1044 # Invoke mainline
1045 # ===============
1047 # Call test() when this file is run as a script (not imported as a module)
1048 if __name__ == '__main__':
1049 test()