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