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