symbian-qemu-0.9.1-12/python-win32-2.6.1/lib/cgi.py
changeset 1 2fb8b9db1c86
equal deleted inserted replaced
0:ffa851df0825 1:2fb8b9db1c86
       
     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     import mimetools
       
    50     if sys.py3kwarning:
       
    51         filterwarnings("ignore", ".*rfc822 has been removed", DeprecationWarning)
       
    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             URL 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 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 \
       
   184             instead",PendingDeprecationWarning)
       
   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)
       
   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 parse_header(line):
       
   293     """Parse a Content-type like header.
       
   294 
       
   295     Return the main content-type and a dictionary of options.
       
   296 
       
   297     """
       
   298     plist = [x.strip() for x in line.split(';')]
       
   299     key = plist.pop(0).lower()
       
   300     pdict = {}
       
   301     for p in plist:
       
   302         i = p.find('=')
       
   303         if i >= 0:
       
   304             name = p[:i].strip().lower()
       
   305             value = p[i+1:].strip()
       
   306             if len(value) >= 2 and value[0] == value[-1] == '"':
       
   307                 value = value[1:-1]
       
   308                 value = value.replace('\\\\', '\\').replace('\\"', '"')
       
   309             pdict[name] = value
       
   310     return key, pdict
       
   311 
       
   312 
       
   313 # Classes for field storage
       
   314 # =========================
       
   315 
       
   316 class MiniFieldStorage:
       
   317 
       
   318     """Like FieldStorage, for use when no file uploads are possible."""
       
   319 
       
   320     # Dummy attributes
       
   321     filename = None
       
   322     list = None
       
   323     type = None
       
   324     file = None
       
   325     type_options = {}
       
   326     disposition = None
       
   327     disposition_options = {}
       
   328     headers = {}
       
   329 
       
   330     def __init__(self, name, value):
       
   331         """Constructor from field name and value."""
       
   332         self.name = name
       
   333         self.value = value
       
   334         # self.file = StringIO(value)
       
   335 
       
   336     def __repr__(self):
       
   337         """Return printable representation."""
       
   338         return "MiniFieldStorage(%r, %r)" % (self.name, self.value)
       
   339 
       
   340 
       
   341 class FieldStorage:
       
   342 
       
   343     """Store a sequence of fields, reading multipart/form-data.
       
   344 
       
   345     This class provides naming, typing, files stored on disk, and
       
   346     more.  At the top level, it is accessible like a dictionary, whose
       
   347     keys are the field names.  (Note: None can occur as a field name.)
       
   348     The items are either a Python list (if there's multiple values) or
       
   349     another FieldStorage or MiniFieldStorage object.  If it's a single
       
   350     object, it has the following attributes:
       
   351 
       
   352     name: the field name, if specified; otherwise None
       
   353 
       
   354     filename: the filename, if specified; otherwise None; this is the
       
   355         client side filename, *not* the file name on which it is
       
   356         stored (that's a temporary file you don't deal with)
       
   357 
       
   358     value: the value as a *string*; for file uploads, this
       
   359         transparently reads the file every time you request the value
       
   360 
       
   361     file: the file(-like) object from which you can read the data;
       
   362         None if the data is stored a simple string
       
   363 
       
   364     type: the content-type, or None if not specified
       
   365 
       
   366     type_options: dictionary of options specified on the content-type
       
   367         line
       
   368 
       
   369     disposition: content-disposition, or None if not specified
       
   370 
       
   371     disposition_options: dictionary of corresponding options
       
   372 
       
   373     headers: a dictionary(-like) object (sometimes rfc822.Message or a
       
   374         subclass thereof) containing *all* headers
       
   375 
       
   376     The class is subclassable, mostly for the purpose of overriding
       
   377     the make_file() method, which is called internally to come up with
       
   378     a file open for reading and writing.  This makes it possible to
       
   379     override the default choice of storing all files in a temporary
       
   380     directory and unlinking them as soon as they have been opened.
       
   381 
       
   382     """
       
   383 
       
   384     def __init__(self, fp=None, headers=None, outerboundary="",
       
   385                  environ=os.environ, keep_blank_values=0, strict_parsing=0):
       
   386         """Constructor.  Read multipart/* until last part.
       
   387 
       
   388         Arguments, all optional:
       
   389 
       
   390         fp              : file pointer; default: sys.stdin
       
   391             (not used when the request method is GET)
       
   392 
       
   393         headers         : header dictionary-like object; default:
       
   394             taken from environ as per CGI spec
       
   395 
       
   396         outerboundary   : terminating multipart boundary
       
   397             (for internal use only)
       
   398 
       
   399         environ         : environment dictionary; default: os.environ
       
   400 
       
   401         keep_blank_values: flag indicating whether blank values in
       
   402             URL encoded forms should be treated as blank strings.
       
   403             A true value indicates that blanks should be retained as
       
   404             blank strings.  The default false value indicates that
       
   405             blank values are to be ignored and treated as if they were
       
   406             not included.
       
   407 
       
   408         strict_parsing: flag indicating what to do with parsing errors.
       
   409             If false (the default), errors are silently ignored.
       
   410             If true, errors raise a ValueError exception.
       
   411 
       
   412         """
       
   413         method = 'GET'
       
   414         self.keep_blank_values = keep_blank_values
       
   415         self.strict_parsing = strict_parsing
       
   416         if 'REQUEST_METHOD' in environ:
       
   417             method = environ['REQUEST_METHOD'].upper()
       
   418         self.qs_on_post = None
       
   419         if method == 'GET' or method == 'HEAD':
       
   420             if 'QUERY_STRING' in environ:
       
   421                 qs = environ['QUERY_STRING']
       
   422             elif sys.argv[1:]:
       
   423                 qs = sys.argv[1]
       
   424             else:
       
   425                 qs = ""
       
   426             fp = StringIO(qs)
       
   427             if headers is None:
       
   428                 headers = {'content-type':
       
   429                            "application/x-www-form-urlencoded"}
       
   430         if headers is None:
       
   431             headers = {}
       
   432             if method == 'POST':
       
   433                 # Set default content-type for POST to what's traditional
       
   434                 headers['content-type'] = "application/x-www-form-urlencoded"
       
   435             if 'CONTENT_TYPE' in environ:
       
   436                 headers['content-type'] = environ['CONTENT_TYPE']
       
   437             if 'QUERY_STRING' in environ:
       
   438                 self.qs_on_post = environ['QUERY_STRING']
       
   439             if 'CONTENT_LENGTH' in environ:
       
   440                 headers['content-length'] = environ['CONTENT_LENGTH']
       
   441         self.fp = fp or sys.stdin
       
   442         self.headers = headers
       
   443         self.outerboundary = outerboundary
       
   444 
       
   445         # Process content-disposition header
       
   446         cdisp, pdict = "", {}
       
   447         if 'content-disposition' in self.headers:
       
   448             cdisp, pdict = parse_header(self.headers['content-disposition'])
       
   449         self.disposition = cdisp
       
   450         self.disposition_options = pdict
       
   451         self.name = None
       
   452         if 'name' in pdict:
       
   453             self.name = pdict['name']
       
   454         self.filename = None
       
   455         if 'filename' in pdict:
       
   456             self.filename = pdict['filename']
       
   457 
       
   458         # Process content-type header
       
   459         #
       
   460         # Honor any existing content-type header.  But if there is no
       
   461         # content-type header, use some sensible defaults.  Assume
       
   462         # outerboundary is "" at the outer level, but something non-false
       
   463         # inside a multi-part.  The default for an inner part is text/plain,
       
   464         # but for an outer part it should be urlencoded.  This should catch
       
   465         # bogus clients which erroneously forget to include a content-type
       
   466         # header.
       
   467         #
       
   468         # See below for what we do if there does exist a content-type header,
       
   469         # but it happens to be something we don't understand.
       
   470         if 'content-type' in self.headers:
       
   471             ctype, pdict = parse_header(self.headers['content-type'])
       
   472         elif self.outerboundary or method != 'POST':
       
   473             ctype, pdict = "text/plain", {}
       
   474         else:
       
   475             ctype, pdict = 'application/x-www-form-urlencoded', {}
       
   476         self.type = ctype
       
   477         self.type_options = pdict
       
   478         self.innerboundary = ""
       
   479         if 'boundary' in pdict:
       
   480             self.innerboundary = pdict['boundary']
       
   481         clen = -1
       
   482         if 'content-length' in self.headers:
       
   483             try:
       
   484                 clen = int(self.headers['content-length'])
       
   485             except ValueError:
       
   486                 pass
       
   487             if maxlen and clen > maxlen:
       
   488                 raise ValueError, 'Maximum content length exceeded'
       
   489         self.length = clen
       
   490 
       
   491         self.list = self.file = None
       
   492         self.done = 0
       
   493         if ctype == 'application/x-www-form-urlencoded':
       
   494             self.read_urlencoded()
       
   495         elif ctype[:10] == 'multipart/':
       
   496             self.read_multi(environ, keep_blank_values, strict_parsing)
       
   497         else:
       
   498             self.read_single()
       
   499 
       
   500     def __repr__(self):
       
   501         """Return a printable representation."""
       
   502         return "FieldStorage(%r, %r, %r)" % (
       
   503                 self.name, self.filename, self.value)
       
   504 
       
   505     def __iter__(self):
       
   506         return iter(self.keys())
       
   507 
       
   508     def __getattr__(self, name):
       
   509         if name != 'value':
       
   510             raise AttributeError, name
       
   511         if self.file:
       
   512             self.file.seek(0)
       
   513             value = self.file.read()
       
   514             self.file.seek(0)
       
   515         elif self.list is not None:
       
   516             value = self.list
       
   517         else:
       
   518             value = None
       
   519         return value
       
   520 
       
   521     def __getitem__(self, key):
       
   522         """Dictionary style indexing."""
       
   523         if self.list is None:
       
   524             raise TypeError, "not indexable"
       
   525         found = []
       
   526         for item in self.list:
       
   527             if item.name == key: found.append(item)
       
   528         if not found:
       
   529             raise KeyError, key
       
   530         if len(found) == 1:
       
   531             return found[0]
       
   532         else:
       
   533             return found
       
   534 
       
   535     def getvalue(self, key, default=None):
       
   536         """Dictionary style get() method, including 'value' lookup."""
       
   537         if key in self:
       
   538             value = self[key]
       
   539             if type(value) is type([]):
       
   540                 return map(attrgetter('value'), value)
       
   541             else:
       
   542                 return value.value
       
   543         else:
       
   544             return default
       
   545 
       
   546     def getfirst(self, key, default=None):
       
   547         """ Return the first value received."""
       
   548         if key in self:
       
   549             value = self[key]
       
   550             if type(value) is type([]):
       
   551                 return value[0].value
       
   552             else:
       
   553                 return value.value
       
   554         else:
       
   555             return default
       
   556 
       
   557     def getlist(self, key):
       
   558         """ Return list of received values."""
       
   559         if key in self:
       
   560             value = self[key]
       
   561             if type(value) is type([]):
       
   562                 return map(attrgetter('value'), value)
       
   563             else:
       
   564                 return [value.value]
       
   565         else:
       
   566             return []
       
   567 
       
   568     def keys(self):
       
   569         """Dictionary style keys() method."""
       
   570         if self.list is None:
       
   571             raise TypeError, "not indexable"
       
   572         return list(set(item.name for item in self.list))
       
   573 
       
   574     def has_key(self, key):
       
   575         """Dictionary style has_key() method."""
       
   576         if self.list is None:
       
   577             raise TypeError, "not indexable"
       
   578         return any(item.name == key for item in self.list)
       
   579 
       
   580     def __contains__(self, key):
       
   581         """Dictionary style __contains__ method."""
       
   582         if self.list is None:
       
   583             raise TypeError, "not indexable"
       
   584         return any(item.name == key for item in self.list)
       
   585 
       
   586     def __len__(self):
       
   587         """Dictionary style len(x) support."""
       
   588         return len(self.keys())
       
   589 
       
   590     def __nonzero__(self):
       
   591         return bool(self.list)
       
   592 
       
   593     def read_urlencoded(self):
       
   594         """Internal: read data in query string format."""
       
   595         qs = self.fp.read(self.length)
       
   596         if self.qs_on_post:
       
   597             qs += '&' + self.qs_on_post
       
   598         self.list = list = []
       
   599         for key, value in urlparse.parse_qsl(qs, self.keep_blank_values,
       
   600                                             self.strict_parsing):
       
   601             list.append(MiniFieldStorage(key, value))
       
   602         self.skip_lines()
       
   603 
       
   604     FieldStorageClass = None
       
   605 
       
   606     def read_multi(self, environ, keep_blank_values, strict_parsing):
       
   607         """Internal: read a part that is itself multipart."""
       
   608         ib = self.innerboundary
       
   609         if not valid_boundary(ib):
       
   610             raise ValueError, 'Invalid boundary in multipart form: %r' % (ib,)
       
   611         self.list = []
       
   612         if self.qs_on_post:
       
   613             for key, value in urlparse.parse_qsl(self.qs_on_post,
       
   614                                 self.keep_blank_values, self.strict_parsing):
       
   615                 self.list.append(MiniFieldStorage(key, value))
       
   616             FieldStorageClass = None
       
   617 
       
   618         klass = self.FieldStorageClass or self.__class__
       
   619         part = klass(self.fp, {}, ib,
       
   620                      environ, keep_blank_values, strict_parsing)
       
   621         # Throw first part away
       
   622         while not part.done:
       
   623             headers = rfc822.Message(self.fp)
       
   624             part = klass(self.fp, headers, ib,
       
   625                          environ, keep_blank_values, strict_parsing)
       
   626             self.list.append(part)
       
   627         self.skip_lines()
       
   628 
       
   629     def read_single(self):
       
   630         """Internal: read an atomic part."""
       
   631         if self.length >= 0:
       
   632             self.read_binary()
       
   633             self.skip_lines()
       
   634         else:
       
   635             self.read_lines()
       
   636         self.file.seek(0)
       
   637 
       
   638     bufsize = 8*1024            # I/O buffering size for copy to file
       
   639 
       
   640     def read_binary(self):
       
   641         """Internal: read binary data."""
       
   642         self.file = self.make_file('b')
       
   643         todo = self.length
       
   644         if todo >= 0:
       
   645             while todo > 0:
       
   646                 data = self.fp.read(min(todo, self.bufsize))
       
   647                 if not data:
       
   648                     self.done = -1
       
   649                     break
       
   650                 self.file.write(data)
       
   651                 todo = todo - len(data)
       
   652 
       
   653     def read_lines(self):
       
   654         """Internal: read lines until EOF or outerboundary."""
       
   655         self.file = self.__file = StringIO()
       
   656         if self.outerboundary:
       
   657             self.read_lines_to_outerboundary()
       
   658         else:
       
   659             self.read_lines_to_eof()
       
   660 
       
   661     def __write(self, line):
       
   662         if self.__file is not None:
       
   663             if self.__file.tell() + len(line) > 1000:
       
   664                 self.file = self.make_file('')
       
   665                 self.file.write(self.__file.getvalue())
       
   666                 self.__file = None
       
   667         self.file.write(line)
       
   668 
       
   669     def read_lines_to_eof(self):
       
   670         """Internal: read lines until EOF."""
       
   671         while 1:
       
   672             line = self.fp.readline(1<<16)
       
   673             if not line:
       
   674                 self.done = -1
       
   675                 break
       
   676             self.__write(line)
       
   677 
       
   678     def read_lines_to_outerboundary(self):
       
   679         """Internal: read lines until outerboundary."""
       
   680         next = "--" + self.outerboundary
       
   681         last = next + "--"
       
   682         delim = ""
       
   683         last_line_lfend = True
       
   684         while 1:
       
   685             line = self.fp.readline(1<<16)
       
   686             if not line:
       
   687                 self.done = -1
       
   688                 break
       
   689             if line[:2] == "--" and last_line_lfend:
       
   690                 strippedline = line.strip()
       
   691                 if strippedline == next:
       
   692                     break
       
   693                 if strippedline == last:
       
   694                     self.done = 1
       
   695                     break
       
   696             odelim = delim
       
   697             if line[-2:] == "\r\n":
       
   698                 delim = "\r\n"
       
   699                 line = line[:-2]
       
   700                 last_line_lfend = True
       
   701             elif line[-1] == "\n":
       
   702                 delim = "\n"
       
   703                 line = line[:-1]
       
   704                 last_line_lfend = True
       
   705             else:
       
   706                 delim = ""
       
   707                 last_line_lfend = False
       
   708             self.__write(odelim + line)
       
   709 
       
   710     def skip_lines(self):
       
   711         """Internal: skip lines until outer boundary if defined."""
       
   712         if not self.outerboundary or self.done:
       
   713             return
       
   714         next = "--" + self.outerboundary
       
   715         last = next + "--"
       
   716         last_line_lfend = True
       
   717         while 1:
       
   718             line = self.fp.readline(1<<16)
       
   719             if not line:
       
   720                 self.done = -1
       
   721                 break
       
   722             if line[:2] == "--" and last_line_lfend:
       
   723                 strippedline = line.strip()
       
   724                 if strippedline == next:
       
   725                     break
       
   726                 if strippedline == last:
       
   727                     self.done = 1
       
   728                     break
       
   729             last_line_lfend = line.endswith('\n')
       
   730 
       
   731     def make_file(self, binary=None):
       
   732         """Overridable: return a readable & writable file.
       
   733 
       
   734         The file will be used as follows:
       
   735         - data is written to it
       
   736         - seek(0)
       
   737         - data is read from it
       
   738 
       
   739         The 'binary' argument is unused -- the file is always opened
       
   740         in binary mode.
       
   741 
       
   742         This version opens a temporary file for reading and writing,
       
   743         and immediately deletes (unlinks) it.  The trick (on Unix!) is
       
   744         that the file can still be used, but it can't be opened by
       
   745         another process, and it will automatically be deleted when it
       
   746         is closed or when the current process terminates.
       
   747 
       
   748         If you want a more permanent file, you derive a class which
       
   749         overrides this method.  If you want a visible temporary file
       
   750         that is nevertheless automatically deleted when the script
       
   751         terminates, try defining a __del__ method in a derived class
       
   752         which unlinks the temporary files you have created.
       
   753 
       
   754         """
       
   755         import tempfile
       
   756         return tempfile.TemporaryFile("w+b")
       
   757 
       
   758 
       
   759 
       
   760 # Backwards Compatibility Classes
       
   761 # ===============================
       
   762 
       
   763 class FormContentDict(UserDict.UserDict):
       
   764     """Form content as dictionary with a list of values per field.
       
   765 
       
   766     form = FormContentDict()
       
   767 
       
   768     form[key] -> [value, value, ...]
       
   769     key in form -> Boolean
       
   770     form.keys() -> [key, key, ...]
       
   771     form.values() -> [[val, val, ...], [val, val, ...], ...]
       
   772     form.items() ->  [(key, [val, val, ...]), (key, [val, val, ...]), ...]
       
   773     form.dict == {key: [val, val, ...], ...}
       
   774 
       
   775     """
       
   776     def __init__(self, environ=os.environ, keep_blank_values=0, strict_parsing=0):
       
   777         self.dict = self.data = parse(environ=environ,
       
   778                                       keep_blank_values=keep_blank_values,
       
   779                                       strict_parsing=strict_parsing)
       
   780         self.query_string = environ['QUERY_STRING']
       
   781 
       
   782 
       
   783 class SvFormContentDict(FormContentDict):
       
   784     """Form content as dictionary expecting a single value per field.
       
   785 
       
   786     If you only expect a single value for each field, then form[key]
       
   787     will return that single value.  It will raise an IndexError if
       
   788     that expectation is not true.  If you expect a field to have
       
   789     possible multiple values, than you can use form.getlist(key) to
       
   790     get all of the values.  values() and items() are a compromise:
       
   791     they return single strings where there is a single value, and
       
   792     lists of strings otherwise.
       
   793 
       
   794     """
       
   795     def __getitem__(self, key):
       
   796         if len(self.dict[key]) > 1:
       
   797             raise IndexError, 'expecting a single value'
       
   798         return self.dict[key][0]
       
   799     def getlist(self, key):
       
   800         return self.dict[key]
       
   801     def values(self):
       
   802         result = []
       
   803         for value in self.dict.values():
       
   804             if len(value) == 1:
       
   805                 result.append(value[0])
       
   806             else: result.append(value)
       
   807         return result
       
   808     def items(self):
       
   809         result = []
       
   810         for key, value in self.dict.items():
       
   811             if len(value) == 1:
       
   812                 result.append((key, value[0]))
       
   813             else: result.append((key, value))
       
   814         return result
       
   815 
       
   816 
       
   817 class InterpFormContentDict(SvFormContentDict):
       
   818     """This class is present for backwards compatibility only."""
       
   819     def __getitem__(self, key):
       
   820         v = SvFormContentDict.__getitem__(self, key)
       
   821         if v[0] in '0123456789+-.':
       
   822             try: return int(v)
       
   823             except ValueError:
       
   824                 try: return float(v)
       
   825                 except ValueError: pass
       
   826         return v.strip()
       
   827     def values(self):
       
   828         result = []
       
   829         for key in self.keys():
       
   830             try:
       
   831                 result.append(self[key])
       
   832             except IndexError:
       
   833                 result.append(self.dict[key])
       
   834         return result
       
   835     def items(self):
       
   836         result = []
       
   837         for key in self.keys():
       
   838             try:
       
   839                 result.append((key, self[key]))
       
   840             except IndexError:
       
   841                 result.append((key, self.dict[key]))
       
   842         return result
       
   843 
       
   844 
       
   845 class FormContent(FormContentDict):
       
   846     """This class is present for backwards compatibility only."""
       
   847     def values(self, key):
       
   848         if key in self.dict :return self.dict[key]
       
   849         else: return None
       
   850     def indexed_value(self, key, location):
       
   851         if key in self.dict:
       
   852             if len(self.dict[key]) > location:
       
   853                 return self.dict[key][location]
       
   854             else: return None
       
   855         else: return None
       
   856     def value(self, key):
       
   857         if key in self.dict: return self.dict[key][0]
       
   858         else: return None
       
   859     def length(self, key):
       
   860         return len(self.dict[key])
       
   861     def stripped(self, key):
       
   862         if key in self.dict: return self.dict[key][0].strip()
       
   863         else: return None
       
   864     def pars(self):
       
   865         return self.dict
       
   866 
       
   867 
       
   868 # Test/debug code
       
   869 # ===============
       
   870 
       
   871 def test(environ=os.environ):
       
   872     """Robust test CGI script, usable as main program.
       
   873 
       
   874     Write minimal HTTP headers and dump all information provided to
       
   875     the script in HTML form.
       
   876 
       
   877     """
       
   878     print "Content-type: text/html"
       
   879     print
       
   880     sys.stderr = sys.stdout
       
   881     try:
       
   882         form = FieldStorage()   # Replace with other classes to test those
       
   883         print_directory()
       
   884         print_arguments()
       
   885         print_form(form)
       
   886         print_environ(environ)
       
   887         print_environ_usage()
       
   888         def f():
       
   889             exec "testing print_exception() -- <I>italics?</I>"
       
   890         def g(f=f):
       
   891             f()
       
   892         print "<H3>What follows is a test, not an actual exception:</H3>"
       
   893         g()
       
   894     except:
       
   895         print_exception()
       
   896 
       
   897     print "<H1>Second try with a small maxlen...</H1>"
       
   898 
       
   899     global maxlen
       
   900     maxlen = 50
       
   901     try:
       
   902         form = FieldStorage()   # Replace with other classes to test those
       
   903         print_directory()
       
   904         print_arguments()
       
   905         print_form(form)
       
   906         print_environ(environ)
       
   907     except:
       
   908         print_exception()
       
   909 
       
   910 def print_exception(type=None, value=None, tb=None, limit=None):
       
   911     if type is None:
       
   912         type, value, tb = sys.exc_info()
       
   913     import traceback
       
   914     print
       
   915     print "<H3>Traceback (most recent call last):</H3>"
       
   916     list = traceback.format_tb(tb, limit) + \
       
   917            traceback.format_exception_only(type, value)
       
   918     print "<PRE>%s<B>%s</B></PRE>" % (
       
   919         escape("".join(list[:-1])),
       
   920         escape(list[-1]),
       
   921         )
       
   922     del tb
       
   923 
       
   924 def print_environ(environ=os.environ):
       
   925     """Dump the shell environment as HTML."""
       
   926     keys = environ.keys()
       
   927     keys.sort()
       
   928     print
       
   929     print "<H3>Shell Environment:</H3>"
       
   930     print "<DL>"
       
   931     for key in keys:
       
   932         print "<DT>", escape(key), "<DD>", escape(environ[key])
       
   933     print "</DL>"
       
   934     print
       
   935 
       
   936 def print_form(form):
       
   937     """Dump the contents of a form as HTML."""
       
   938     keys = form.keys()
       
   939     keys.sort()
       
   940     print
       
   941     print "<H3>Form Contents:</H3>"
       
   942     if not keys:
       
   943         print "<P>No form fields."
       
   944     print "<DL>"
       
   945     for key in keys:
       
   946         print "<DT>" + escape(key) + ":",
       
   947         value = form[key]
       
   948         print "<i>" + escape(repr(type(value))) + "</i>"
       
   949         print "<DD>" + escape(repr(value))
       
   950     print "</DL>"
       
   951     print
       
   952 
       
   953 def print_directory():
       
   954     """Dump the current directory as HTML."""
       
   955     print
       
   956     print "<H3>Current Working Directory:</H3>"
       
   957     try:
       
   958         pwd = os.getcwd()
       
   959     except os.error, msg:
       
   960         print "os.error:", escape(str(msg))
       
   961     else:
       
   962         print escape(pwd)
       
   963     print
       
   964 
       
   965 def print_arguments():
       
   966     print
       
   967     print "<H3>Command Line Arguments:</H3>"
       
   968     print
       
   969     print sys.argv
       
   970     print
       
   971 
       
   972 def print_environ_usage():
       
   973     """Dump a list of environment variables used by CGI as HTML."""
       
   974     print """
       
   975 <H3>These environment variables could have been set:</H3>
       
   976 <UL>
       
   977 <LI>AUTH_TYPE
       
   978 <LI>CONTENT_LENGTH
       
   979 <LI>CONTENT_TYPE
       
   980 <LI>DATE_GMT
       
   981 <LI>DATE_LOCAL
       
   982 <LI>DOCUMENT_NAME
       
   983 <LI>DOCUMENT_ROOT
       
   984 <LI>DOCUMENT_URI
       
   985 <LI>GATEWAY_INTERFACE
       
   986 <LI>LAST_MODIFIED
       
   987 <LI>PATH
       
   988 <LI>PATH_INFO
       
   989 <LI>PATH_TRANSLATED
       
   990 <LI>QUERY_STRING
       
   991 <LI>REMOTE_ADDR
       
   992 <LI>REMOTE_HOST
       
   993 <LI>REMOTE_IDENT
       
   994 <LI>REMOTE_USER
       
   995 <LI>REQUEST_METHOD
       
   996 <LI>SCRIPT_NAME
       
   997 <LI>SERVER_NAME
       
   998 <LI>SERVER_PORT
       
   999 <LI>SERVER_PROTOCOL
       
  1000 <LI>SERVER_ROOT
       
  1001 <LI>SERVER_SOFTWARE
       
  1002 </UL>
       
  1003 In addition, HTTP headers sent by the server may be passed in the
       
  1004 environment as well.  Here are some common variable names:
       
  1005 <UL>
       
  1006 <LI>HTTP_ACCEPT
       
  1007 <LI>HTTP_CONNECTION
       
  1008 <LI>HTTP_HOST
       
  1009 <LI>HTTP_PRAGMA
       
  1010 <LI>HTTP_REFERER
       
  1011 <LI>HTTP_USER_AGENT
       
  1012 </UL>
       
  1013 """
       
  1014 
       
  1015 
       
  1016 # Utilities
       
  1017 # =========
       
  1018 
       
  1019 def escape(s, quote=None):
       
  1020     '''Replace special characters "&", "<" and ">" to HTML-safe sequences.
       
  1021     If the optional flag quote is true, the quotation mark character (")
       
  1022     is also translated.'''
       
  1023     s = s.replace("&", "&amp;") # Must be done first!
       
  1024     s = s.replace("<", "&lt;")
       
  1025     s = s.replace(">", "&gt;")
       
  1026     if quote:
       
  1027         s = s.replace('"', "&quot;")
       
  1028     return s
       
  1029 
       
  1030 def valid_boundary(s, _vb_pattern="^[ -~]{0,200}[!-~]$"):
       
  1031     import re
       
  1032     return re.match(_vb_pattern, s)
       
  1033 
       
  1034 # Invoke mainline
       
  1035 # ===============
       
  1036 
       
  1037 # Call test() when this file is run as a script (not imported as a module)
       
  1038 if __name__ == '__main__':
       
  1039     test()