ยปCore Development>Code coverage>Lib/cgi.py

Python code coverage for Lib/cgi.py

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