0001 #! /usr/local/bin/python 0002 0003 # NOTE: the above "/usr/local/bin/python" is NOT a mistake. It is 0004 # intentionally NOT "/usr/bin/env python". On many systems 0005 # (e.g. Solaris), /usr/local/bin is not in $PATH as passed to CGI 0006 # scripts, and /usr/local/bin is the default directory where Python is 0007 # installed, so /usr/bin/env would be unable to find python. Granted, 0008 # binary installations by Linux vendors often install Python in 0009 # /usr/bin. So let those vendors patch cgi.py to match their choice 0010 # of installation. 0011 0012 """Support module for CGI (Common Gateway Interface) scripts. 0013 0014 This module defines a number of utilities for use by CGI scripts 0015 written in Python. 0016 """ 0017 0018 # XXX Perhaps there should be a slimmed version that doesn't contain 0019 # all those backwards compatible and debugging classes and functions? 0020 0021 # History 0022 # ------- 0023 # 0024 # Michael McLay started this module. Steve Majewski changed the 0025 # interface to SvFormContentDict and FormContentDict. The multipart 0026 # parsing was inspired by code submitted by Andreas Paepcke. Guido van 0027 # Rossum rewrote, reformatted and documented the module and is currently 0028 # responsible for its maintenance. 0029 # 0030 0031 __version__ = "2.6" 0032 0033 0034 # Imports 0035 # ======= 0036 0037 import sys 0038 import os 0039 import urllib 0040 import mimetools 0041 import rfc822 0042 import UserDict 0043 from StringIO import StringIO 0044 0045 __all__ = ["MiniFieldStorage", "FieldStorage", "FormContentDict", 0046 "SvFormContentDict", "InterpFormContentDict", "FormContent", 0047 "parse", "parse_qs", "parse_qsl", "parse_multipart", 0048 "parse_header", "print_exception", "print_environ", 0049 "print_form", "print_directory", "print_arguments", 0050 "print_environ_usage", "escape"] 0051 0052 # Logging support 0053 # =============== 0054 0055 logfile = "" # Filename to log to, if not empty 0056 logfp = None # File object to log to, if not None 0057 0058 def initlog(*allargs): 0059 """Write a log message, if there is a log file. 0060 0061 Even though this function is called initlog(), you should always 0062 use log(); log is a variable that is set either to initlog 0063 (initially), to dolog (once the log file has been opened), or to 0064 nolog (when logging is disabled). 0065 0066 The first argument is a format string; the remaining arguments (if 0067 any) are arguments to the % operator, so e.g. 0068 log("%s: %s", "a", "b") 0069 will write "a: b" to the log file, followed by a newline. 0070 0071 If the global logfp is not None, it should be a file object to 0072 which log data is written. 0073 0074 If the global logfp is None, the global logfile may be a string 0075 giving a filename to open, in append mode. This file should be 0076 world writable!!! If the file can't be opened, logging is 0077 silently disabled (since there is no safe place where we could 0078 send an error message). 0079 0080 """ 0081 global logfp, log 0082 if logfile and not logfp: 0083 try: 0084 logfp = open(logfile, "a") 0085 except IOError: 0086 pass 0087 if not logfp: 0088 log = nolog 0089 else: 0090 log = dolog 0091 log(*allargs) 0092 0093 def dolog(fmt, *args): 0094 """Write a log message to the log file. See initlog() for docs.""" 0095 logfp.write(fmt%args + "\n") 0096 0097 def nolog(*allargs): 0098 """Dummy function, assigned to log when logging is disabled.""" 0099 pass 0100 0101 log = initlog # The current logging function 0102 0103 0104 # Parsing functions 0105 # ================= 0106 0107 # Maximum input we will accept when REQUEST_METHOD is POST 0108 # 0 ==> unlimited input 0109 maxlen = 0 0110 0111 def parse(fp=None, environ=os.environ, keep_blank_values=0, strict_parsing=0): 0112 """Parse a query in the environment or from a file (default stdin) 0113 0114 Arguments, all optional: 0115 0116 fp : file pointer; default: sys.stdin 0117 0118 environ : environment dictionary; default: os.environ 0119 0120 keep_blank_values: flag indicating whether blank values in 0121 URL encoded forms should be treated as blank strings. 0122 A true value indicates that blanks should be retained as 0123 blank strings. The default false value indicates that 0124 blank values are to be ignored and treated as if they were 0125 not included. 0126 0127 strict_parsing: flag indicating what to do with parsing errors. 0128 If false (the default), errors are silently ignored. 0129 If true, errors raise a ValueError exception. 0130 """ 0131 if fp is None: 0132 fp = sys.stdin 0133 if not 'REQUEST_METHOD' in environ: 0134 environ['REQUEST_METHOD'] = 'GET' # For testing stand-alone 0135 if environ['REQUEST_METHOD'] == 'POST': 0136 ctype, pdict = parse_header(environ['CONTENT_TYPE']) 0137 if ctype == 'multipart/form-data': 0138 return parse_multipart(fp, pdict) 0139 elif ctype == 'application/x-www-form-urlencoded': 0140 clength = int(environ['CONTENT_LENGTH']) 0141 if maxlen and clength > maxlen: 0142 raise ValueError, 'Maximum content length exceeded' 0143 qs = fp.read(clength) 0144 else: 0145 qs = '' # Unknown content-type 0146 if 'QUERY_STRING' in environ: 0147 if qs: qs = qs + '&' 0148 qs = qs + environ['QUERY_STRING'] 0149 elif sys.argv[1:]: 0150 if qs: qs = qs + '&' 0151 qs = qs + sys.argv[1] 0152 environ['QUERY_STRING'] = qs # XXX Shouldn't, really 0153 elif 'QUERY_STRING' in environ: 0154 qs = environ['QUERY_STRING'] 0155 else: 0156 if sys.argv[1:]: 0157 qs = sys.argv[1] 0158 else: 0159 qs = "" 0160 environ['QUERY_STRING'] = qs # XXX Shouldn't, really 0161 return parse_qs(qs, keep_blank_values, strict_parsing) 0162 0163 0164 def parse_qs(qs, keep_blank_values=0, strict_parsing=0): 0165 """Parse a query given as a string argument. 0166 0167 Arguments: 0168 0169 qs: URL-encoded query string to be parsed 0170 0171 keep_blank_values: flag indicating whether blank values in 0172 URL encoded queries should be treated as blank strings. 0173 A true value indicates that blanks should be retained as 0174 blank strings. The default false value indicates that 0175 blank values are to be ignored and treated as if they were 0176 not included. 0177 0178 strict_parsing: flag indicating what to do with parsing errors. 0179 If false (the default), errors are silently ignored. 0180 If true, errors raise a ValueError exception. 0181 """ 0182 dict = {} 0183 for name, value in parse_qsl(qs, keep_blank_values, strict_parsing): 0184 if name in dict: 0185 dict[name].append(value) 0186 else: 0187 dict[name] = [value] 0188 return dict 0189 0190 def parse_qsl(qs, keep_blank_values=0, strict_parsing=0): 0191 """Parse a query given as a string argument. 0192 0193 Arguments: 0194 0195 qs: URL-encoded query string to be parsed 0196 0197 keep_blank_values: flag indicating whether blank values in 0198 URL encoded queries should be treated as blank strings. A 0199 true value indicates that blanks should be retained as blank 0200 strings. The default false value indicates that blank values 0201 are to be ignored and treated as if they were not included. 0202 0203 strict_parsing: flag indicating what to do with parsing errors. If 0204 false (the default), errors are silently ignored. If true, 0205 errors raise a ValueError exception. 0206 0207 Returns a list, as G-d intended. 0208 """ 0209 pairs = [s2 for s1 in qs.split('&') for s2 in s1.split(';')] 0210 r = [] 0211 for name_value in pairs: 0212 if not name_value and not strict_parsing: 0213 continue 0214 nv = name_value.split('=', 1) 0215 if len(nv) != 2: 0216 if strict_parsing: 0217 raise ValueError, "bad query field: %r" % (name_value,) 0218 # Handle case of a control-name with no equal sign 0219 if keep_blank_values: 0220 nv.append('') 0221 else: 0222 continue 0223 if len(nv[1]) or keep_blank_values: 0224 name = urllib.unquote(nv[0].replace('+', ' ')) 0225 value = urllib.unquote(nv[1].replace('+', ' ')) 0226 r.append((name, value)) 0227 0228 return r 0229 0230 0231 def parse_multipart(fp, pdict): 0232 """Parse multipart input. 0233 0234 Arguments: 0235 fp : input file 0236 pdict: dictionary containing other parameters of conten-type header 0237 0238 Returns a dictionary just like parse_qs(): keys are the field names, each 0239 value is a list of values for that field. This is easy to use but not 0240 much good if you are expecting megabytes to be uploaded -- in that case, 0241 use the FieldStorage class instead which is much more flexible. Note 0242 that content-type is the raw, unparsed contents of the content-type 0243 header. 0244 0245 XXX This does not parse nested multipart parts -- use FieldStorage for 0246 that. 0247 0248 XXX This should really be subsumed by FieldStorage altogether -- no 0249 point in having two implementations of the same parsing algorithm. 0250 0251 """ 0252 boundary = "" 0253 if 'boundary' in pdict: 0254 boundary = pdict['boundary'] 0255 if not valid_boundary(boundary): 0256 raise ValueError, ('Invalid boundary in multipart form: %r' 0257 % (boundary,)) 0258 0259 nextpart = "--" + boundary 0260 lastpart = "--" + boundary + "--" 0261 partdict = {} 0262 terminator = "" 0263 0264 while terminator != lastpart: 0265 bytes = -1 0266 data = None 0267 if terminator: 0268 # At start of next part. Read headers first. 0269 headers = mimetools.Message(fp) 0270 clength = headers.getheader('content-length') 0271 if clength: 0272 try: 0273 bytes = int(clength) 0274 except ValueError: 0275 pass 0276 if bytes > 0: 0277 if maxlen and bytes > maxlen: 0278 raise ValueError, 'Maximum content length exceeded' 0279 data = fp.read(bytes) 0280 else: 0281 data = "" 0282 # Read lines until end of part. 0283 lines = [] 0284 while 1: 0285 line = fp.readline() 0286 if not line: 0287 terminator = lastpart # End outer loop 0288 break 0289 if line[:2] == "--": 0290 terminator = line.strip() 0291 if terminator in (nextpart, lastpart): 0292 break 0293 lines.append(line) 0294 # Done with part. 0295 if data is None: 0296 continue 0297 if bytes < 0: 0298 if lines: 0299 # Strip final line terminator 0300 line = lines[-1] 0301 if line[-2:] == "\r\n": 0302 line = line[:-2] 0303 elif line[-1:] == "\n": 0304 line = line[:-1] 0305 lines[-1] = line 0306 data = "".join(lines) 0307 line = headers['content-disposition'] 0308 if not line: 0309 continue 0310 key, params = parse_header(line) 0311 if key != 'form-data': 0312 continue 0313 if 'name' in params: 0314 name = params['name'] 0315 else: 0316 continue 0317 if name in partdict: 0318 partdict[name].append(data) 0319 else: 0320 partdict[name] = [data] 0321 0322 return partdict 0323 0324 0325 def parse_header(line): 0326 """Parse a Content-type like header. 0327 0328 Return the main content-type and a dictionary of options. 0329 0330 """ 0331 plist = map(lambda x: x.strip(), line.split(';')) 0332 key = plist.pop(0).lower() 0333 pdict = {} 0334 for p in plist: 0335 i = p.find('=') 0336 if i >= 0: 0337 name = p[:i].strip().lower() 0338 value = p[i+1:].strip() 0339 if len(value) >= 2 and value[0] == value[-1] == '"': 0340 value = value[1:-1] 0341 value = value.replace('\\\\', '\\').replace('\\"', '"') 0342 pdict[name] = value 0343 return key, pdict 0344 0345 0346 # Classes for field storage 0347 # ========================= 0348 0349 class MiniFieldStorage: 0350 0351 """Like FieldStorage, for use when no file uploads are possible.""" 0352 0353 # Dummy attributes 0354 filename = None 0355 list = None 0356 type = None 0357 file = None 0358 type_options = {} 0359 disposition = None 0360 disposition_options = {} 0361 headers = {} 0362 0363 def __init__(self, name, value): 0364 """Constructor from field name and value.""" 0365 self.name = name 0366 self.value = value 0367 # self.file = StringIO(value) 0368 0369 def __repr__(self): 0370 """Return printable representation.""" 0371 return "MiniFieldStorage(%r, %r)" % (self.name, self.value) 0372 0373 0374 class FieldStorage: 0375 0376 """Store a sequence of fields, reading multipart/form-data. 0377 0378 This class provides naming, typing, files stored on disk, and 0379 more. At the top level, it is accessible like a dictionary, whose 0380 keys are the field names. (Note: None can occur as a field name.) 0381 The items are either a Python list (if there's multiple values) or 0382 another FieldStorage or MiniFieldStorage object. If it's a single 0383 object, it has the following attributes: 0384 0385 name: the field name, if specified; otherwise None 0386 0387 filename: the filename, if specified; otherwise None; this is the 0388 client side filename, *not* the file name on which it is 0389 stored (that's a temporary file you don't deal with) 0390 0391 value: the value as a *string*; for file uploads, this 0392 transparently reads the file every time you request the value 0393 0394 file: the file(-like) object from which you can read the data; 0395 None if the data is stored a simple string 0396 0397 type: the content-type, or None if not specified 0398 0399 type_options: dictionary of options specified on the content-type 0400 line 0401 0402 disposition: content-disposition, or None if not specified 0403 0404 disposition_options: dictionary of corresponding options 0405 0406 headers: a dictionary(-like) object (sometimes rfc822.Message or a 0407 subclass thereof) containing *all* headers 0408 0409 The class is subclassable, mostly for the purpose of overriding 0410 the make_file() method, which is called internally to come up with 0411 a file open for reading and writing. This makes it possible to 0412 override the default choice of storing all files in a temporary 0413 directory and unlinking them as soon as they have been opened. 0414 0415 """ 0416 0417 def __init__(self, fp=None, headers=None, outerboundary="", 0418 environ=os.environ, keep_blank_values=0, strict_parsing=0): 0419 """Constructor. Read multipart/* until last part. 0420 0421 Arguments, all optional: 0422 0423 fp : file pointer; default: sys.stdin 0424 (not used when the request method is GET) 0425 0426 headers : header dictionary-like object; default: 0427 taken from environ as per CGI spec 0428 0429 outerboundary : terminating multipart boundary 0430 (for internal use only) 0431 0432 environ : environment dictionary; default: os.environ 0433 0434 keep_blank_values: flag indicating whether blank values in 0435 URL encoded forms should be treated as blank strings. 0436 A true value indicates that blanks should be retained as 0437 blank strings. The default false value indicates that 0438 blank values are to be ignored and treated as if they were 0439 not included. 0440 0441 strict_parsing: flag indicating what to do with parsing errors. 0442 If false (the default), errors are silently ignored. 0443 If true, errors raise a ValueError exception. 0444 0445 """ 0446 method = 'GET' 0447 self.keep_blank_values = keep_blank_values 0448 self.strict_parsing = strict_parsing 0449 if 'REQUEST_METHOD' in environ: 0450 method = environ['REQUEST_METHOD'].upper() 0451 if method == 'GET' or method == 'HEAD': 0452 if 'QUERY_STRING' in environ: 0453 qs = environ['QUERY_STRING'] 0454 elif sys.argv[1:]: 0455 qs = sys.argv[1] 0456 else: 0457 qs = "" 0458 fp = StringIO(qs) 0459 if headers is None: 0460 headers = {'content-type': 0461 "application/x-www-form-urlencoded"} 0462 if headers is None: 0463 headers = {} 0464 if method == 'POST': 0465 # Set default content-type for POST to what's traditional 0466 headers['content-type'] = "application/x-www-form-urlencoded" 0467 if 'CONTENT_TYPE' in environ: 0468 headers['content-type'] = environ['CONTENT_TYPE'] 0469 if 'CONTENT_LENGTH' in environ: 0470 headers['content-length'] = environ['CONTENT_LENGTH'] 0471 self.fp = fp or sys.stdin 0472 self.headers = headers 0473 self.outerboundary = outerboundary 0474 0475 # Process content-disposition header 0476 cdisp, pdict = "", {} 0477 if 'content-disposition' in self.headers: 0478 cdisp, pdict = parse_header(self.headers['content-disposition']) 0479 self.disposition = cdisp 0480 self.disposition_options = pdict 0481 self.name = None 0482 if 'name' in pdict: 0483 self.name = pdict['name'] 0484 self.filename = None 0485 if 'filename' in pdict: 0486 self.filename = pdict['filename'] 0487 0488 # Process content-type header 0489 # 0490 # Honor any existing content-type header. But if there is no 0491 # content-type header, use some sensible defaults. Assume 0492 # outerboundary is "" at the outer level, but something non-false 0493 # inside a multi-part. The default for an inner part is text/plain, 0494 # but for an outer part it should be urlencoded. This should catch 0495 # bogus clients which erroneously forget to include a content-type 0496 # header. 0497 # 0498 # See below for what we do if there does exist a content-type header, 0499 # but it happens to be something we don't understand. 0500 if 'content-type' in self.headers: 0501 ctype, pdict = parse_header(self.headers['content-type']) 0502 elif self.outerboundary or method != 'POST': 0503 ctype, pdict = "text/plain", {} 0504 else: 0505 ctype, pdict = 'application/x-www-form-urlencoded', {} 0506 self.type = ctype 0507 self.type_options = pdict 0508 self.innerboundary = "" 0509 if 'boundary' in pdict: 0510 self.innerboundary = pdict['boundary'] 0511 clen = -1 0512 if 'content-length' in self.headers: 0513 try: 0514 clen = int(self.headers['content-length']) 0515 except ValueError: 0516 pass 0517 if maxlen and clen > maxlen: 0518 raise ValueError, 'Maximum content length exceeded' 0519 self.length = clen 0520 0521 self.list = self.file = None 0522 self.done = 0 0523 if ctype == 'application/x-www-form-urlencoded': 0524 self.read_urlencoded() 0525 elif ctype[:10] == 'multipart/': 0526 self.read_multi(environ, keep_blank_values, strict_parsing) 0527 else: 0528 self.read_single() 0529 0530 def __repr__(self): 0531 """Return a printable representation.""" 0532 return "FieldStorage(%r, %r, %r)" % ( 0533 self.name, self.filename, self.value) 0534 0535 def __iter__(self): 0536 return iter(self.keys()) 0537 0538 def __getattr__(self, name): 0539 if name != 'value': 0540 raise AttributeError, name 0541 if self.file: 0542 self.file.seek(0) 0543 value = self.file.read() 0544 self.file.seek(0) 0545 elif self.list is not None: 0546 value = self.list 0547 else: 0548 value = None 0549 return value 0550 0551 def __getitem__(self, key): 0552 """Dictionary style indexing.""" 0553 if self.list is None: 0554 raise TypeError, "not indexable" 0555 found = [] 0556 for item in self.list: 0557 if item.name == key: found.append(item) 0558 if not found: 0559 raise KeyError, key 0560 if len(found) == 1: 0561 return found[0] 0562 else: 0563 return found 0564 0565 def getvalue(self, key, default=None): 0566 """Dictionary style get() method, including 'value' lookup.""" 0567 if key in self: 0568 value = self[key] 0569 if type(value) is type([]): 0570 return map(lambda v: v.value, value) 0571 else: 0572 return value.value 0573 else: 0574 return default 0575 0576 def getfirst(self, key, default=None): 0577 """ Return the first value received.""" 0578 if key in self: 0579 value = self[key] 0580 if type(value) is type([]): 0581 return value[0].value 0582 else: 0583 return value.value 0584 else: 0585 return default 0586 0587 def getlist(self, key): 0588 """ Return list of received values.""" 0589 if key in self: 0590 value = self[key] 0591 if type(value) is type([]): 0592 return map(lambda v: v.value, value) 0593 else: 0594 return [value.value] 0595 else: 0596 return [] 0597 0598 def keys(self): 0599 """Dictionary style keys() method.""" 0600 if self.list is None: 0601 raise TypeError, "not indexable" 0602 keys = [] 0603 for item in self.list: 0604 if item.name not in keys: keys.append(item.name) 0605 return keys 0606 0607 def has_key(self, key): 0608 """Dictionary style has_key() method.""" 0609 if self.list is None: 0610 raise TypeError, "not indexable" 0611 for item in self.list: 0612 if item.name == key: return True 0613 return False 0614 0615 def __contains__(self, key): 0616 """Dictionary style __contains__ method.""" 0617 if self.list is None: 0618 raise TypeError, "not indexable" 0619 for item in self.list: 0620 if item.name == key: return True 0621 return False 0622 0623 def __len__(self): 0624 """Dictionary style len(x) support.""" 0625 return len(self.keys()) 0626 0627 def read_urlencoded(self): 0628 """Internal: read data in query string format.""" 0629 qs = self.fp.read(self.length) 0630 self.list = list = [] 0631 for key, value in parse_qsl(qs, self.keep_blank_values, 0632 self.strict_parsing): 0633 list.append(MiniFieldStorage(key, value)) 0634 self.skip_lines() 0635 0636 FieldStorageClass = None 0637 0638 def read_multi(self, environ, keep_blank_values, strict_parsing): 0639 """Internal: read a part that is itself multipart.""" 0640 ib = self.innerboundary 0641 if not valid_boundary(ib): 0642 raise ValueError, 'Invalid boundary in multipart form: %r' % (ib,) 0643 self.list = [] 0644 klass = self.FieldStorageClass or self.__class__ 0645 part = klass(self.fp, {}, ib, 0646 environ, keep_blank_values, strict_parsing) 0647 # Throw first part away 0648 while not part.done: 0649 headers = rfc822.Message(self.fp) 0650 part = klass(self.fp, headers, ib, 0651 environ, keep_blank_values, strict_parsing) 0652 self.list.append(part) 0653 self.skip_lines() 0654 0655 def read_single(self): 0656 """Internal: read an atomic part.""" 0657 if self.length >= 0: 0658 self.read_binary() 0659 self.skip_lines() 0660 else: 0661 self.read_lines() 0662 self.file.seek(0) 0663 0664 bufsize = 8*1024 # I/O buffering size for copy to file 0665 0666 def read_binary(self): 0667 """Internal: read binary data.""" 0668 self.file = self.make_file('b') 0669 todo = self.length 0670 if todo >= 0: 0671 while todo > 0: 0672 data = self.fp.read(min(todo, self.bufsize)) 0673 if not data: 0674 self.done = -1 0675 break 0676 self.file.write(data) 0677 todo = todo - len(data) 0678 0679 def read_lines(self): 0680 """Internal: read lines until EOF or outerboundary.""" 0681 self.file = self.__file = StringIO() 0682 if self.outerboundary: 0683 self.read_lines_to_outerboundary() 0684 else: 0685 self.read_lines_to_eof() 0686 0687 def __write(self, line): 0688 if self.__file is not None: 0689 if self.__file.tell() + len(line) > 1000: 0690 self.file = self.make_file('') 0691 self.file.write(self.__file.getvalue()) 0692 self.__file = None 0693 self.file.write(line) 0694 0695 def read_lines_to_eof(self): 0696 """Internal: read lines until EOF.""" 0697 while 1: 0698 line = self.fp.readline() 0699 if not line: 0700 self.done = -1 0701 break 0702 self.__write(line) 0703 0704 def read_lines_to_outerboundary(self): 0705 """Internal: read lines until outerboundary.""" 0706 next = "--" + self.outerboundary 0707 last = next + "--" 0708 delim = "" 0709 while 1: 0710 line = self.fp.readline() 0711 if not line: 0712 self.done = -1 0713 break 0714 if line[:2] == "--": 0715 strippedline = line.strip() 0716 if strippedline == next: 0717 break 0718 if strippedline == last: 0719 self.done = 1 0720 break 0721 odelim = delim 0722 if line[-2:] == "\r\n": 0723 delim = "\r\n" 0724 line = line[:-2] 0725 elif line[-1] == "\n": 0726 delim = "\n" 0727 line = line[:-1] 0728 else: 0729 delim = "" 0730 self.__write(odelim + line) 0731 0732 def skip_lines(self): 0733 """Internal: skip lines until outer boundary if defined.""" 0734 if not self.outerboundary or self.done: 0735 return 0736 next = "--" + self.outerboundary 0737 last = next + "--" 0738 while 1: 0739 line = self.fp.readline() 0740 if not line: 0741 self.done = -1 0742 break 0743 if line[:2] == "--": 0744 strippedline = line.strip() 0745 if strippedline == next: 0746 break 0747 if strippedline == last: 0748 self.done = 1 0749 break 0750 0751 def make_file(self, binary=None): 0752 """Overridable: return a readable & writable file. 0753 0754 The file will be used as follows: 0755 - data is written to it 0756 - seek(0) 0757 - data is read from it 0758 0759 The 'binary' argument is unused -- the file is always opened 0760 in binary mode. 0761 0762 This version opens a temporary file for reading and writing, 0763 and immediately deletes (unlinks) it. The trick (on Unix!) is 0764 that the file can still be used, but it can't be opened by 0765 another process, and it will automatically be deleted when it 0766 is closed or when the current process terminates. 0767 0768 If you want a more permanent file, you derive a class which 0769 overrides this method. If you want a visible temporary file 0770 that is nevertheless automatically deleted when the script 0771 terminates, try defining a __del__ method in a derived class 0772 which unlinks the temporary files you have created. 0773 0774 """ 0775 import tempfile 0776 return tempfile.TemporaryFile("w+b") 0777 0778 0779 0780 # Backwards Compatibility Classes 0781 # =============================== 0782 0783 class FormContentDict(UserDict.UserDict): 0784 """Form content as dictionary with a list of values per field. 0785 0786 form = FormContentDict() 0787 0788 form[key] -> [value, value, ...] 0789 key in form -> Boolean 0790 form.keys() -> [key, key, ...] 0791 form.values() -> [[val, val, ...], [val, val, ...], ...] 0792 form.items() -> [(key, [val, val, ...]), (key, [val, val, ...]), ...] 0793 form.dict == {key: [val, val, ...], ...} 0794 0795 """ 0796 def __init__(self, environ=os.environ): 0797 self.dict = self.data = parse(environ=environ) 0798 self.query_string = environ['QUERY_STRING'] 0799 0800 0801 class SvFormContentDict(FormContentDict): 0802 """Form content as dictionary expecting a single value per field. 0803 0804 If you only expect a single value for each field, then form[key] 0805 will return that single value. It will raise an IndexError if 0806 that expectation is not true. If you expect a field to have 0807 possible multiple values, than you can use form.getlist(key) to 0808 get all of the values. values() and items() are a compromise: 0809 they return single strings where there is a single value, and 0810 lists of strings otherwise. 0811 0812 """ 0813 def __getitem__(self, key): 0814 if len(self.dict[key]) > 1: 0815 raise IndexError, 'expecting a single value' 0816 return self.dict[key][0] 0817 def getlist(self, key): 0818 return self.dict[key] 0819 def values(self): 0820 result = [] 0821 for value in self.dict.values(): 0822 if len(value) == 1: 0823 result.append(value[0]) 0824 else: result.append(value) 0825 return result 0826 def items(self): 0827 result = [] 0828 for key, value in self.dict.items(): 0829 if len(value) == 1: 0830 result.append((key, value[0])) 0831 else: result.append((key, value)) 0832 return result 0833 0834 0835 class InterpFormContentDict(SvFormContentDict): 0836 """This class is present for backwards compatibility only.""" 0837 def __getitem__(self, key): 0838 v = SvFormContentDict.__getitem__(self, key) 0839 if v[0] in '0123456789+-.': 0840 try: return int(v) 0841 except ValueError: 0842 try: return float(v) 0843 except ValueError: pass 0844 return v.strip() 0845 def values(self): 0846 result = [] 0847 for key in self.keys(): 0848 try: 0849 result.append(self[key]) 0850 except IndexError: 0851 result.append(self.dict[key]) 0852 return result 0853 def items(self): 0854 result = [] 0855 for key in self.keys(): 0856 try: 0857 result.append((key, self[key])) 0858 except IndexError: 0859 result.append((key, self.dict[key])) 0860 return result 0861 0862 0863 class FormContent(FormContentDict): 0864 """This class is present for backwards compatibility only.""" 0865 def values(self, key): 0866 if key in self.dict :return self.dict[key] 0867 else: return None 0868 def indexed_value(self, key, location): 0869 if key in self.dict: 0870 if len(self.dict[key]) > location: 0871 return self.dict[key][location] 0872 else: return None 0873 else: return None 0874 def value(self, key): 0875 if key in self.dict: return self.dict[key][0] 0876 else: return None 0877 def length(self, key): 0878 return len(self.dict[key]) 0879 def stripped(self, key): 0880 if key in self.dict: return self.dict[key][0].strip() 0881 else: return None 0882 def pars(self): 0883 return self.dict 0884 0885 0886 # Test/debug code 0887 # =============== 0888 0889 def test(environ=os.environ): 0890 """Robust test CGI script, usable as main program. 0891 0892 Write minimal HTTP headers and dump all information provided to 0893 the script in HTML form. 0894 0895 """ 0896 print "Content-type: text/html" 0897 print 0898 sys.stderr = sys.stdout 0899 try: 0900 form = FieldStorage() # Replace with other classes to test those 0901 print_directory() 0902 print_arguments() 0903 print_form(form) 0904 print_environ(environ) 0905 print_environ_usage() 0906 def f(): 0907 exec "testing print_exception() -- <I>italics?</I>" 0908 def g(f=f): 0909 f() 0910 print "<H3>What follows is a test, not an actual exception:</H3>" 0911 g() 0912 except: 0913 print_exception() 0914 0915 print "<H1>Second try with a small maxlen...</H1>" 0916 0917 global maxlen 0918 maxlen = 50 0919 try: 0920 form = FieldStorage() # Replace with other classes to test those 0921 print_directory() 0922 print_arguments() 0923 print_form(form) 0924 print_environ(environ) 0925 except: 0926 print_exception() 0927 0928 def print_exception(type=None, value=None, tb=None, limit=None): 0929 if type is None: 0930 type, value, tb = sys.exc_info() 0931 import traceback 0932 print 0933 print "<H3>Traceback (most recent call last):</H3>" 0934 list = traceback.format_tb(tb, limit) + \ 0935 traceback.format_exception_only(type, value) 0936 print "<PRE>%s<B>%s</B></PRE>" % ( 0937 escape("".join(list[:-1])), 0938 escape(list[-1]), 0939 ) 0940 del tb 0941 0942 def print_environ(environ=os.environ): 0943 """Dump the shell environment as HTML.""" 0944 keys = environ.keys() 0945 keys.sort() 0946 print 0947 print "<H3>Shell Environment:</H3>" 0948 print "<DL>" 0949 for key in keys: 0950 print "<DT>", escape(key), "<DD>", escape(environ[key]) 0951 print "</DL>" 0952 print 0953 0954 def print_form(form): 0955 """Dump the contents of a form as HTML.""" 0956 keys = form.keys() 0957 keys.sort() 0958 print 0959 print "<H3>Form Contents:</H3>" 0960 if not keys: 0961 print "<P>No form fields." 0962 print "<DL>" 0963 for key in keys: 0964 print "<DT>" + escape(key) + ":", 0965 value = form[key] 0966 print "<i>" + escape(repr(type(value))) + "</i>" 0967 print "<DD>" + escape(repr(value)) 0968 print "</DL>" 0969 print 0970 0971 def print_directory(): 0972 """Dump the current directory as HTML.""" 0973 print 0974 print "<H3>Current Working Directory:</H3>" 0975 try: 0976 pwd = os.getcwd() 0977 except os.error, msg: 0978 print "os.error:", escape(str(msg)) 0979 else: 0980 print escape(pwd) 0981 print 0982 0983 def print_arguments(): 0984 print 0985 print "<H3>Command Line Arguments:</H3>" 0986 print 0987 print sys.argv 0988 print 0989 0990 def print_environ_usage(): 0991 """Dump a list of environment variables used by CGI as HTML.""" 0992 print """ 0993 <H3>These environment variables could have been set:</H3> 0994 <UL> 0995 <LI>AUTH_TYPE 0996 <LI>CONTENT_LENGTH 0997 <LI>CONTENT_TYPE 0998 <LI>DATE_GMT 0999 <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> 1021 In addition, HTTP headers sent by the server may be passed in the 1022 environment 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 1037 def escape(s, quote=None): 1038 """Replace special characters '&', '<' and '>' by SGML entities.""" 1039 s = s.replace("&", "&") # Must be done first! 1040 s = s.replace("<", "<") 1041 s = s.replace(">", ">") 1042 if quote: 1043 s = s.replace('"', """) 1044 return s 1045 1046 def 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) 1054 if __name__ == '__main__': 1055 test() 1056
Generated by PyXR 0.9.4