- Got rid of newmodule.c
[python/dscho.git] / Lib / cgi.py
blob88d419e0ddf056c13713f7018887ec4c248a182c
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[0].lower()
327 del plist[0]
328 pdict = {}
329 for p in plist:
330 i = p.find('=')
331 if i >= 0:
332 name = p[:i].strip().lower()
333 value = p[i+1:].strip()
334 if len(value) >= 2 and value[0] == value[-1] == '"':
335 value = value[1:-1]
336 pdict[name] = value
337 return key, pdict
340 # Classes for field storage
341 # =========================
343 class MiniFieldStorage:
345 """Like FieldStorage, for use when no file uploads are possible."""
347 # Dummy attributes
348 filename = None
349 list = None
350 type = None
351 file = None
352 type_options = {}
353 disposition = None
354 disposition_options = {}
355 headers = {}
357 def __init__(self, name, value):
358 """Constructor from field name and value."""
359 self.name = name
360 self.value = value
361 # self.file = StringIO(value)
363 def __repr__(self):
364 """Return printable representation."""
365 return "MiniFieldStorage(%s, %s)" % (`self.name`, `self.value`)
368 class FieldStorage:
370 """Store a sequence of fields, reading multipart/form-data.
372 This class provides naming, typing, files stored on disk, and
373 more. At the top level, it is accessible like a dictionary, whose
374 keys are the field names. (Note: None can occur as a field name.)
375 The items are either a Python list (if there's multiple values) or
376 another FieldStorage or MiniFieldStorage object. If it's a single
377 object, it has the following attributes:
379 name: the field name, if specified; otherwise None
381 filename: the filename, if specified; otherwise None; this is the
382 client side filename, *not* the file name on which it is
383 stored (that's a temporary file you don't deal with)
385 value: the value as a *string*; for file uploads, this
386 transparently reads the file every time you request the value
388 file: the file(-like) object from which you can read the data;
389 None if the data is stored a simple string
391 type: the content-type, or None if not specified
393 type_options: dictionary of options specified on the content-type
394 line
396 disposition: content-disposition, or None if not specified
398 disposition_options: dictionary of corresponding options
400 headers: a dictionary(-like) object (sometimes rfc822.Message or a
401 subclass thereof) containing *all* headers
403 The class is subclassable, mostly for the purpose of overriding
404 the make_file() method, which is called internally to come up with
405 a file open for reading and writing. This makes it possible to
406 override the default choice of storing all files in a temporary
407 directory and unlinking them as soon as they have been opened.
411 def __init__(self, fp=None, headers=None, outerboundary="",
412 environ=os.environ, keep_blank_values=0, strict_parsing=0):
413 """Constructor. Read multipart/* until last part.
415 Arguments, all optional:
417 fp : file pointer; default: sys.stdin
418 (not used when the request method is GET)
420 headers : header dictionary-like object; default:
421 taken from environ as per CGI spec
423 outerboundary : terminating multipart boundary
424 (for internal use only)
426 environ : environment dictionary; default: os.environ
428 keep_blank_values: flag indicating whether blank values in
429 URL encoded forms should be treated as blank strings.
430 A true value indicates that blanks should be retained as
431 blank strings. The default false value indicates that
432 blank values are to be ignored and treated as if they were
433 not included.
435 strict_parsing: flag indicating what to do with parsing errors.
436 If false (the default), errors are silently ignored.
437 If true, errors raise a ValueError exception.
440 method = 'GET'
441 self.keep_blank_values = keep_blank_values
442 self.strict_parsing = strict_parsing
443 if 'REQUEST_METHOD' in environ:
444 method = environ['REQUEST_METHOD'].upper()
445 if method == 'GET' or method == 'HEAD':
446 if 'QUERY_STRING' in environ:
447 qs = environ['QUERY_STRING']
448 elif sys.argv[1:]:
449 qs = sys.argv[1]
450 else:
451 qs = ""
452 fp = StringIO(qs)
453 if headers is None:
454 headers = {'content-type':
455 "application/x-www-form-urlencoded"}
456 if headers is None:
457 headers = {}
458 if method == 'POST':
459 # Set default content-type for POST to what's traditional
460 headers['content-type'] = "application/x-www-form-urlencoded"
461 if 'CONTENT_TYPE' in environ:
462 headers['content-type'] = environ['CONTENT_TYPE']
463 if 'CONTENT_LENGTH' in environ:
464 headers['content-length'] = environ['CONTENT_LENGTH']
465 self.fp = fp or sys.stdin
466 self.headers = headers
467 self.outerboundary = outerboundary
469 # Process content-disposition header
470 cdisp, pdict = "", {}
471 if 'content-disposition' in self.headers:
472 cdisp, pdict = parse_header(self.headers['content-disposition'])
473 self.disposition = cdisp
474 self.disposition_options = pdict
475 self.name = None
476 if 'name' in pdict:
477 self.name = pdict['name']
478 self.filename = None
479 if 'filename' in pdict:
480 self.filename = pdict['filename']
482 # Process content-type header
484 # Honor any existing content-type header. But if there is no
485 # content-type header, use some sensible defaults. Assume
486 # outerboundary is "" at the outer level, but something non-false
487 # inside a multi-part. The default for an inner part is text/plain,
488 # but for an outer part it should be urlencoded. This should catch
489 # bogus clients which erroneously forget to include a content-type
490 # header.
492 # See below for what we do if there does exist a content-type header,
493 # but it happens to be something we don't understand.
494 if 'content-type' in self.headers:
495 ctype, pdict = parse_header(self.headers['content-type'])
496 elif self.outerboundary or method != 'POST':
497 ctype, pdict = "text/plain", {}
498 else:
499 ctype, pdict = 'application/x-www-form-urlencoded', {}
500 self.type = ctype
501 self.type_options = pdict
502 self.innerboundary = ""
503 if 'boundary' in pdict:
504 self.innerboundary = pdict['boundary']
505 clen = -1
506 if 'content-length' in self.headers:
507 try:
508 clen = int(self.headers['content-length'])
509 except ValueError:
510 pass
511 if maxlen and clen > maxlen:
512 raise ValueError, 'Maximum content length exceeded'
513 self.length = clen
515 self.list = self.file = None
516 self.done = 0
517 if ctype == 'application/x-www-form-urlencoded':
518 self.read_urlencoded()
519 elif ctype[:10] == 'multipart/':
520 self.read_multi(environ, keep_blank_values, strict_parsing)
521 else:
522 self.read_single()
524 def __repr__(self):
525 """Return a printable representation."""
526 return "FieldStorage(%s, %s, %s)" % (
527 `self.name`, `self.filename`, `self.value`)
529 def __getattr__(self, name):
530 if name != 'value':
531 raise AttributeError, name
532 if self.file:
533 self.file.seek(0)
534 value = self.file.read()
535 self.file.seek(0)
536 elif self.list is not None:
537 value = self.list
538 else:
539 value = None
540 return value
542 def __getitem__(self, key):
543 """Dictionary style indexing."""
544 if self.list is None:
545 raise TypeError, "not indexable"
546 found = []
547 for item in self.list:
548 if item.name == key: found.append(item)
549 if not found:
550 raise KeyError, key
551 if len(found) == 1:
552 return found[0]
553 else:
554 return found
556 def getvalue(self, key, default=None):
557 """Dictionary style get() method, including 'value' lookup."""
558 if key in self:
559 value = self[key]
560 if type(value) is type([]):
561 return map(lambda v: v.value, value)
562 else:
563 return value.value
564 else:
565 return default
567 def getfirst(self, key, default=None):
568 """ Return the first value received."""
569 if key in self:
570 value = self[key]
571 if type(value) is type([]):
572 return value[0].value
573 else:
574 return value.value
575 else:
576 return default
578 def getlist(self, key):
579 """ Return list of received values."""
580 if key in self:
581 value = self[key]
582 if type(value) is type([]):
583 return map(lambda v: v.value, value)
584 else:
585 return [value.value]
586 else:
587 return []
589 def keys(self):
590 """Dictionary style keys() method."""
591 if self.list is None:
592 raise TypeError, "not indexable"
593 keys = []
594 for item in self.list:
595 if item.name not in keys: keys.append(item.name)
596 return keys
598 def has_key(self, key):
599 """Dictionary style has_key() method."""
600 if self.list is None:
601 raise TypeError, "not indexable"
602 for item in self.list:
603 if item.name == key: return True
604 return False
606 def __contains__(self, key):
607 """Dictionary style __contains__ method."""
608 if self.list is None:
609 raise TypeError, "not indexable"
610 for item in self.list:
611 if item.name == key: return True
612 return False
614 def __len__(self):
615 """Dictionary style len(x) support."""
616 return len(self.keys())
618 def read_urlencoded(self):
619 """Internal: read data in query string format."""
620 qs = self.fp.read(self.length)
621 self.list = list = []
622 for key, value in parse_qsl(qs, self.keep_blank_values,
623 self.strict_parsing):
624 list.append(MiniFieldStorage(key, value))
625 self.skip_lines()
627 FieldStorageClass = None
629 def read_multi(self, environ, keep_blank_values, strict_parsing):
630 """Internal: read a part that is itself multipart."""
631 ib = self.innerboundary
632 if not valid_boundary(ib):
633 raise ValueError, ('Invalid boundary in multipart form: %s'
634 % `ib`)
635 self.list = []
636 klass = self.FieldStorageClass or self.__class__
637 part = klass(self.fp, {}, ib,
638 environ, keep_blank_values, strict_parsing)
639 # Throw first part away
640 while not part.done:
641 headers = rfc822.Message(self.fp)
642 part = klass(self.fp, headers, ib,
643 environ, keep_blank_values, strict_parsing)
644 self.list.append(part)
645 self.skip_lines()
647 def read_single(self):
648 """Internal: read an atomic part."""
649 if self.length >= 0:
650 self.read_binary()
651 self.skip_lines()
652 else:
653 self.read_lines()
654 self.file.seek(0)
656 bufsize = 8*1024 # I/O buffering size for copy to file
658 def read_binary(self):
659 """Internal: read binary data."""
660 self.file = self.make_file('b')
661 todo = self.length
662 if todo >= 0:
663 while todo > 0:
664 data = self.fp.read(min(todo, self.bufsize))
665 if not data:
666 self.done = -1
667 break
668 self.file.write(data)
669 todo = todo - len(data)
671 def read_lines(self):
672 """Internal: read lines until EOF or outerboundary."""
673 self.file = self.__file = StringIO()
674 if self.outerboundary:
675 self.read_lines_to_outerboundary()
676 else:
677 self.read_lines_to_eof()
679 def __write(self, line):
680 if self.__file is not None:
681 if self.__file.tell() + len(line) > 1000:
682 self.file = self.make_file('')
683 self.file.write(self.__file.getvalue())
684 self.__file = None
685 self.file.write(line)
687 def read_lines_to_eof(self):
688 """Internal: read lines until EOF."""
689 while 1:
690 line = self.fp.readline()
691 if not line:
692 self.done = -1
693 break
694 self.__write(line)
696 def read_lines_to_outerboundary(self):
697 """Internal: read lines until outerboundary."""
698 next = "--" + self.outerboundary
699 last = next + "--"
700 delim = ""
701 while 1:
702 line = self.fp.readline()
703 if not line:
704 self.done = -1
705 break
706 if line[:2] == "--":
707 strippedline = line.strip()
708 if strippedline == next:
709 break
710 if strippedline == last:
711 self.done = 1
712 break
713 odelim = delim
714 if line[-2:] == "\r\n":
715 delim = "\r\n"
716 line = line[:-2]
717 elif line[-1] == "\n":
718 delim = "\n"
719 line = line[:-1]
720 else:
721 delim = ""
722 self.__write(odelim + line)
724 def skip_lines(self):
725 """Internal: skip lines until outer boundary if defined."""
726 if not self.outerboundary or self.done:
727 return
728 next = "--" + self.outerboundary
729 last = next + "--"
730 while 1:
731 line = self.fp.readline()
732 if not line:
733 self.done = -1
734 break
735 if line[:2] == "--":
736 strippedline = line.strip()
737 if strippedline == next:
738 break
739 if strippedline == last:
740 self.done = 1
741 break
743 def make_file(self, binary=None):
744 """Overridable: return a readable & writable file.
746 The file will be used as follows:
747 - data is written to it
748 - seek(0)
749 - data is read from it
751 The 'binary' argument is unused -- the file is always opened
752 in binary mode.
754 This version opens a temporary file for reading and writing,
755 and immediately deletes (unlinks) it. The trick (on Unix!) is
756 that the file can still be used, but it can't be opened by
757 another process, and it will automatically be deleted when it
758 is closed or when the current process terminates.
760 If you want a more permanent file, you derive a class which
761 overrides this method. If you want a visible temporary file
762 that is nevertheless automatically deleted when the script
763 terminates, try defining a __del__ method in a derived class
764 which unlinks the temporary files you have created.
767 import tempfile
768 return tempfile.TemporaryFile("w+b")
772 # Backwards Compatibility Classes
773 # ===============================
775 class FormContentDict(UserDict.UserDict):
776 """Form content as dictionary with a list of values per field.
778 form = FormContentDict()
780 form[key] -> [value, value, ...]
781 key in form -> Boolean
782 form.keys() -> [key, key, ...]
783 form.values() -> [[val, val, ...], [val, val, ...], ...]
784 form.items() -> [(key, [val, val, ...]), (key, [val, val, ...]), ...]
785 form.dict == {key: [val, val, ...], ...}
788 def __init__(self, environ=os.environ):
789 self.dict = self.data = parse(environ=environ)
790 self.query_string = environ['QUERY_STRING']
793 class SvFormContentDict(FormContentDict):
794 """Form content as dictionary expecting a single value per field.
796 If you only expect a single value for each field, then form[key]
797 will return that single value. It will raise an IndexError if
798 that expectation is not true. If you expect a field to have
799 possible multiple values, than you can use form.getlist(key) to
800 get all of the values. values() and items() are a compromise:
801 they return single strings where there is a single value, and
802 lists of strings otherwise.
805 def __getitem__(self, key):
806 if len(self.dict[key]) > 1:
807 raise IndexError, 'expecting a single value'
808 return self.dict[key][0]
809 def getlist(self, key):
810 return self.dict[key]
811 def values(self):
812 result = []
813 for value in self.dict.values():
814 if len(value) == 1:
815 result.append(value[0])
816 else: result.append(value)
817 return result
818 def items(self):
819 result = []
820 for key, value in self.dict.items():
821 if len(value) == 1:
822 result.append((key, value[0]))
823 else: result.append((key, value))
824 return result
827 class InterpFormContentDict(SvFormContentDict):
828 """This class is present for backwards compatibility only."""
829 def __getitem__(self, key):
830 v = SvFormContentDict.__getitem__(self, key)
831 if v[0] in '0123456789+-.':
832 try: return int(v)
833 except ValueError:
834 try: return float(v)
835 except ValueError: pass
836 return v.strip()
837 def values(self):
838 result = []
839 for key in self.keys():
840 try:
841 result.append(self[key])
842 except IndexError:
843 result.append(self.dict[key])
844 return result
845 def items(self):
846 result = []
847 for key in self.keys():
848 try:
849 result.append((key, self[key]))
850 except IndexError:
851 result.append((key, self.dict[key]))
852 return result
855 class FormContent(FormContentDict):
856 """This class is present for backwards compatibility only."""
857 def values(self, key):
858 if key in self.dict :return self.dict[key]
859 else: return None
860 def indexed_value(self, key, location):
861 if key in self.dict:
862 if len(self.dict[key]) > location:
863 return self.dict[key][location]
864 else: return None
865 else: return None
866 def value(self, key):
867 if key in self.dict: return self.dict[key][0]
868 else: return None
869 def length(self, key):
870 return len(self.dict[key])
871 def stripped(self, key):
872 if key in self.dict: return self.dict[key][0].strip()
873 else: return None
874 def pars(self):
875 return self.dict
878 # Test/debug code
879 # ===============
881 def test(environ=os.environ):
882 """Robust test CGI script, usable as main program.
884 Write minimal HTTP headers and dump all information provided to
885 the script in HTML form.
888 print "Content-type: text/html"
889 print
890 sys.stderr = sys.stdout
891 try:
892 form = FieldStorage() # Replace with other classes to test those
893 print_directory()
894 print_arguments()
895 print_form(form)
896 print_environ(environ)
897 print_environ_usage()
898 def f():
899 exec "testing print_exception() -- <I>italics?</I>"
900 def g(f=f):
902 print "<H3>What follows is a test, not an actual exception:</H3>"
904 except:
905 print_exception()
907 print "<H1>Second try with a small maxlen...</H1>"
909 global maxlen
910 maxlen = 50
911 try:
912 form = FieldStorage() # Replace with other classes to test those
913 print_directory()
914 print_arguments()
915 print_form(form)
916 print_environ(environ)
917 except:
918 print_exception()
920 def print_exception(type=None, value=None, tb=None, limit=None):
921 if type is None:
922 type, value, tb = sys.exc_info()
923 import traceback
924 print
925 print "<H3>Traceback (most recent call last):</H3>"
926 list = traceback.format_tb(tb, limit) + \
927 traceback.format_exception_only(type, value)
928 print "<PRE>%s<B>%s</B></PRE>" % (
929 escape("".join(list[:-1])),
930 escape(list[-1]),
932 del tb
934 def print_environ(environ=os.environ):
935 """Dump the shell environment as HTML."""
936 keys = environ.keys()
937 keys.sort()
938 print
939 print "<H3>Shell Environment:</H3>"
940 print "<DL>"
941 for key in keys:
942 print "<DT>", escape(key), "<DD>", escape(environ[key])
943 print "</DL>"
944 print
946 def print_form(form):
947 """Dump the contents of a form as HTML."""
948 keys = form.keys()
949 keys.sort()
950 print
951 print "<H3>Form Contents:</H3>"
952 if not keys:
953 print "<P>No form fields."
954 print "<DL>"
955 for key in keys:
956 print "<DT>" + escape(key) + ":",
957 value = form[key]
958 print "<i>" + escape(`type(value)`) + "</i>"
959 print "<DD>" + escape(`value`)
960 print "</DL>"
961 print
963 def print_directory():
964 """Dump the current directory as HTML."""
965 print
966 print "<H3>Current Working Directory:</H3>"
967 try:
968 pwd = os.getcwd()
969 except os.error, msg:
970 print "os.error:", escape(str(msg))
971 else:
972 print escape(pwd)
973 print
975 def print_arguments():
976 print
977 print "<H3>Command Line Arguments:</H3>"
978 print
979 print sys.argv
980 print
982 def print_environ_usage():
983 """Dump a list of environment variables used by CGI as HTML."""
984 print """
985 <H3>These environment variables could have been set:</H3>
986 <UL>
987 <LI>AUTH_TYPE
988 <LI>CONTENT_LENGTH
989 <LI>CONTENT_TYPE
990 <LI>DATE_GMT
991 <LI>DATE_LOCAL
992 <LI>DOCUMENT_NAME
993 <LI>DOCUMENT_ROOT
994 <LI>DOCUMENT_URI
995 <LI>GATEWAY_INTERFACE
996 <LI>LAST_MODIFIED
997 <LI>PATH
998 <LI>PATH_INFO
999 <LI>PATH_TRANSLATED
1000 <LI>QUERY_STRING
1001 <LI>REMOTE_ADDR
1002 <LI>REMOTE_HOST
1003 <LI>REMOTE_IDENT
1004 <LI>REMOTE_USER
1005 <LI>REQUEST_METHOD
1006 <LI>SCRIPT_NAME
1007 <LI>SERVER_NAME
1008 <LI>SERVER_PORT
1009 <LI>SERVER_PROTOCOL
1010 <LI>SERVER_ROOT
1011 <LI>SERVER_SOFTWARE
1012 </UL>
1013 In addition, HTTP headers sent by the server may be passed in the
1014 environment as well. Here are some common variable names:
1015 <UL>
1016 <LI>HTTP_ACCEPT
1017 <LI>HTTP_CONNECTION
1018 <LI>HTTP_HOST
1019 <LI>HTTP_PRAGMA
1020 <LI>HTTP_REFERER
1021 <LI>HTTP_USER_AGENT
1022 </UL>
1026 # Utilities
1027 # =========
1029 def escape(s, quote=None):
1030 """Replace special characters '&', '<' and '>' by SGML entities."""
1031 s = s.replace("&", "&amp;") # Must be done first!
1032 s = s.replace("<", "&lt;")
1033 s = s.replace(">", "&gt;")
1034 if quote:
1035 s = s.replace('"', "&quot;")
1036 return s
1038 def valid_boundary(s, _vb_pattern="^[ -~]{0,200}[!-~]$"):
1039 import re
1040 return re.match(_vb_pattern, s)
1042 # Invoke mainline
1043 # ===============
1045 # Call test() when this file is run as a script (not imported as a module)
1046 if __name__ == '__main__':
1047 test()