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