PageRenderTime 86ms CodeModel.GetById 16ms app.highlight 61ms RepoModel.GetById 1ms app.codeStats 1ms

/Lib/cgi.py

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