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