PyXR

c:\python24\lib \ cgi.py



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("&", "&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 
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
SourceForge.net Logo