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