Home | History | Annotate | Download | only in Lib
      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 
     14 This module defines a number of utilities for use by CGI scripts
     15 written 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 
     37 from operator import attrgetter
     38 import sys
     39 import os
     40 import urllib
     41 import UserDict
     42 import urlparse
     43 
     44 from warnings import filterwarnings, catch_warnings, warn
     45 with 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 
     54 try:
     55     from cStringIO import StringIO
     56 except 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 
     69 logfile = ""            # Filename to log to, if not empty

     70 logfp = None            # File object to log to, if not None

     71 
     72 def 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 
    107 def dolog(fmt, *args):
    108     """Write a log message to the log file.  See initlog() for docs."""
    109     logfp.write(fmt%args + "\n")
    110 
    111 def nolog(*allargs):
    112     """Dummy function, assigned to log when logging is disabled."""
    113     pass
    114 
    115 log = 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

    123 maxlen = 0
    124 
    125 def 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 
    181 def 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 
    188 def 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 
    194 def 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 
    292 def _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 
    304 def 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 
    328 class 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 
    353 class 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 
    775 class 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 
    795 class 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 
    829 class 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 
    857 class 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 
    883 def 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 
    922 def 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 
    936 def 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 
    948 def 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 
    965 def 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 
    977 def print_arguments():
    978     print
    979     print "<H3>Command Line Arguments:</H3>"
    980     print
    981     print sys.argv
    982     print
    983 
    984 def 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>
   1015 In addition, HTTP headers sent by the server may be passed in the
   1016 environment 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 
   1031 def 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("&", "&amp;") # Must be done first!

   1036     s = s.replace("<", "&lt;")
   1037     s = s.replace(">", "&gt;")
   1038     if quote:
   1039         s = s.replace('"', "&quot;")
   1040     return s
   1041 
   1042 def 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)

   1050 if __name__ == '__main__':
   1051     test()
   1052