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