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