cgi.py (21861B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\carbon\common\stdlib\cgi.py 2 __version__ = '2.6' 3 from operator import attrgetter 4 import sys 5 import os 6 import urllib 7 import UserDict 8 import urlparse 9 from warnings import filterwarnings, catch_warnings, warn 10 with catch_warnings(): 11 if sys.py3kwarning: 12 filterwarnings('ignore', '.*mimetools has been removed', DeprecationWarning) 13 filterwarnings('ignore', '.*rfc822 has been removed', DeprecationWarning) 14 import mimetools 15 import rfc822 16 try: 17 from cStringIO import StringIO 18 except ImportError: 19 from StringIO import StringIO 20 21 __all__ = ['MiniFieldStorage', 22 'FieldStorage', 23 'FormContentDict', 24 'SvFormContentDict', 25 'InterpFormContentDict', 26 'FormContent', 27 'parse', 28 'parse_qs', 29 'parse_qsl', 30 'parse_multipart', 31 'parse_header', 32 'print_exception', 33 'print_environ', 34 'print_form', 35 'print_directory', 36 'print_arguments', 37 'print_environ_usage', 38 'escape'] 39 logfile = '' 40 logfp = None 41 42 def initlog(*allargs): 43 global logfp 44 global log 45 if logfile and not logfp: 46 try: 47 logfp = open(logfile, 'a') 48 except IOError: 49 pass 50 51 if not logfp: 52 log = nolog 53 else: 54 log = dolog 55 log(*allargs) 56 57 58 def dolog(fmt, *args): 59 logfp.write(fmt % args + '\n') 60 61 62 def nolog(*allargs): 63 pass 64 65 66 log = initlog 67 maxlen = 0 68 69 def parse(fp = None, environ = os.environ, keep_blank_values = 0, strict_parsing = 0): 70 global maxlen 71 if fp is None: 72 fp = sys.stdin 73 if 'REQUEST_METHOD' not in environ: 74 environ['REQUEST_METHOD'] = 'GET' 75 if environ['REQUEST_METHOD'] == 'POST': 76 ctype, pdict = parse_header(environ['CONTENT_TYPE']) 77 if ctype == 'multipart/form-data': 78 return parse_multipart(fp, pdict) 79 if ctype == 'application/x-www-form-urlencoded': 80 clength = int(environ['CONTENT_LENGTH']) 81 if maxlen and clength > maxlen: 82 raise ValueError, 'Maximum content length exceeded' 83 qs = fp.read(clength) 84 else: 85 qs = '' 86 if 'QUERY_STRING' in environ: 87 if qs: 88 qs = qs + '&' 89 qs = qs + environ['QUERY_STRING'] 90 elif sys.argv[1:]: 91 if qs: 92 qs = qs + '&' 93 qs = qs + sys.argv[1] 94 environ['QUERY_STRING'] = qs 95 elif 'QUERY_STRING' in environ: 96 qs = environ['QUERY_STRING'] 97 else: 98 if sys.argv[1:]: 99 qs = sys.argv[1] 100 else: 101 qs = '' 102 environ['QUERY_STRING'] = qs 103 return urlparse.parse_qs(qs, keep_blank_values, strict_parsing) 104 105 106 def parse_qs(qs, keep_blank_values = 0, strict_parsing = 0): 107 warn('cgi.parse_qs is deprecated, use urlparse.parse_qs instead', PendingDeprecationWarning, 2) 108 return urlparse.parse_qs(qs, keep_blank_values, strict_parsing) 109 110 111 def parse_qsl(qs, keep_blank_values = 0, strict_parsing = 0): 112 warn('cgi.parse_qsl is deprecated, use urlparse.parse_qsl instead', PendingDeprecationWarning, 2) 113 return urlparse.parse_qsl(qs, keep_blank_values, strict_parsing) 114 115 116 def parse_multipart(fp, pdict): 117 boundary = '' 118 if 'boundary' in pdict: 119 boundary = pdict['boundary'] 120 if not valid_boundary(boundary): 121 raise ValueError, 'Invalid boundary in multipart form: %r' % (boundary,) 122 nextpart = '--' + boundary 123 lastpart = '--' + boundary + '--' 124 partdict = {} 125 terminator = '' 126 while terminator != lastpart: 127 bytes = -1 128 data = None 129 if terminator: 130 headers = mimetools.Message(fp) 131 clength = headers.getheader('content-length') 132 if clength: 133 try: 134 bytes = int(clength) 135 except ValueError: 136 pass 137 138 if bytes > 0: 139 if maxlen and bytes > maxlen: 140 raise ValueError, 'Maximum content length exceeded' 141 data = fp.read(bytes) 142 else: 143 data = '' 144 lines = [] 145 while 1: 146 line = fp.readline() 147 if not line: 148 terminator = lastpart 149 break 150 if line[:2] == '--': 151 terminator = line.strip() 152 if terminator in (nextpart, lastpart): 153 break 154 lines.append(line) 155 156 if data is None: 157 continue 158 if bytes < 0: 159 if lines: 160 line = lines[-1] 161 if line[-2:] == '\r\n': 162 line = line[:-2] 163 elif line[-1:] == '\n': 164 line = line[:-1] 165 lines[-1] = line 166 data = ''.join(lines) 167 line = headers['content-disposition'] 168 if not line: 169 continue 170 key, params = parse_header(line) 171 if key != 'form-data': 172 continue 173 if 'name' in params: 174 name = params['name'] 175 else: 176 continue 177 if name in partdict: 178 partdict[name].append(data) 179 else: 180 partdict[name] = [data] 181 182 return partdict 183 184 185 def _parseparam(s): 186 while s[:1] == ';': 187 s = s[1:] 188 end = s.find(';') 189 while end > 0 and s.count('"', 0, end) % 2: 190 end = s.find(';', end + 1) 191 192 if end < 0: 193 end = len(s) 194 f = s[:end] 195 yield f.strip() 196 s = s[end:] 197 198 199 def parse_header(line): 200 parts = _parseparam(';' + line) 201 key = parts.next() 202 pdict = {} 203 for p in parts: 204 i = p.find('=') 205 if i >= 0: 206 name = p[:i].strip().lower() 207 value = p[i + 1:].strip() 208 if len(value) >= 2 and value[0] == value[-1] == '"': 209 value = value[1:-1] 210 value = value.replace('\\\\', '\\').replace('\\"', '"') 211 pdict[name] = value 212 213 return (key, pdict) 214 215 216 class MiniFieldStorage(): 217 filename = None 218 list = None 219 type = None 220 file = None 221 type_options = {} 222 disposition = None 223 disposition_options = {} 224 headers = {} 225 226 def __init__(self, name, value): 227 self.name = name 228 self.value = value 229 230 def __repr__(self): 231 return 'MiniFieldStorage(%r, %r)' % (self.name, self.value) 232 233 234 class FieldStorage(): 235 236 def __init__(self, fp = None, headers = None, outerboundary = '', environ = os.environ, keep_blank_values = 0, strict_parsing = 0): 237 method = 'GET' 238 self.keep_blank_values = keep_blank_values 239 self.strict_parsing = strict_parsing 240 if 'REQUEST_METHOD' in environ: 241 method = environ['REQUEST_METHOD'].upper() 242 self.qs_on_post = None 243 if method == 'GET' or method == 'HEAD': 244 if 'QUERY_STRING' in environ: 245 qs = environ['QUERY_STRING'] 246 elif sys.argv[1:]: 247 qs = sys.argv[1] 248 else: 249 qs = '' 250 fp = StringIO(qs) 251 if headers is None: 252 headers = {'content-type': 'application/x-www-form-urlencoded'} 253 if headers is None: 254 headers = {} 255 if method == 'POST': 256 headers['content-type'] = 'application/x-www-form-urlencoded' 257 if 'CONTENT_TYPE' in environ: 258 headers['content-type'] = environ['CONTENT_TYPE'] 259 if 'QUERY_STRING' in environ: 260 self.qs_on_post = environ['QUERY_STRING'] 261 if 'CONTENT_LENGTH' in environ: 262 headers['content-length'] = environ['CONTENT_LENGTH'] 263 self.fp = fp or sys.stdin 264 self.headers = headers 265 self.outerboundary = outerboundary 266 cdisp, pdict = '', {} 267 if 'content-disposition' in self.headers: 268 cdisp, pdict = parse_header(self.headers['content-disposition']) 269 self.disposition = cdisp 270 self.disposition_options = pdict 271 self.name = None 272 if 'name' in pdict: 273 self.name = pdict['name'] 274 self.filename = None 275 if 'filename' in pdict: 276 self.filename = pdict['filename'] 277 if 'content-type' in self.headers: 278 ctype, pdict = parse_header(self.headers['content-type']) 279 elif self.outerboundary or method != 'POST': 280 ctype, pdict = 'text/plain', {} 281 else: 282 ctype, pdict = 'application/x-www-form-urlencoded', {} 283 self.type = ctype 284 self.type_options = pdict 285 self.innerboundary = '' 286 if 'boundary' in pdict: 287 self.innerboundary = pdict['boundary'] 288 clen = -1 289 if 'content-length' in self.headers: 290 try: 291 clen = int(self.headers['content-length']) 292 except ValueError: 293 pass 294 295 if maxlen and clen > maxlen: 296 raise ValueError, 'Maximum content length exceeded' 297 self.length = clen 298 self.list = self.file = None 299 self.done = 0 300 if ctype == 'application/x-www-form-urlencoded': 301 self.read_urlencoded() 302 elif ctype[:10] == 'multipart/': 303 self.read_multi(environ, keep_blank_values, strict_parsing) 304 else: 305 self.read_single() 306 307 def __repr__(self): 308 return 'FieldStorage(%r, %r, %r)' % (self.name, self.filename, self.value) 309 310 def __iter__(self): 311 return iter(self.keys()) 312 313 def __getattr__(self, name): 314 if name != 'value': 315 raise AttributeError, name 316 if self.file: 317 self.file.seek(0) 318 value = self.file.read() 319 self.file.seek(0) 320 elif self.list is not None: 321 value = self.list 322 else: 323 value = None 324 return value 325 326 def __getitem__(self, key): 327 if self.list is None: 328 raise TypeError, 'not indexable' 329 found = [] 330 for item in self.list: 331 if item.name == key: 332 found.append(item) 333 334 if not found: 335 raise KeyError, key 336 if len(found) == 1: 337 return found[0] 338 else: 339 return found 340 341 def getvalue(self, key, default = None): 342 if key in self: 343 value = self[key] 344 if type(value) is type([]): 345 return map(attrgetter('value'), value) 346 else: 347 return value.value 348 else: 349 return default 350 351 def getfirst(self, key, default = None): 352 if key in self: 353 value = self[key] 354 if type(value) is type([]): 355 return value[0].value 356 else: 357 return value.value 358 else: 359 return default 360 361 def getlist(self, key): 362 if key in self: 363 value = self[key] 364 if type(value) is type([]): 365 return map(attrgetter('value'), value) 366 else: 367 return [value.value] 368 else: 369 return [] 370 371 def keys(self): 372 if self.list is None: 373 raise TypeError, 'not indexable' 374 return list(set((item.name for item in self.list))) 375 376 def has_key(self, key): 377 if self.list is None: 378 raise TypeError, 'not indexable' 379 return any((item.name == key for item in self.list)) 380 381 def __contains__(self, key): 382 if self.list is None: 383 raise TypeError, 'not indexable' 384 return any((item.name == key for item in self.list)) 385 386 def __len__(self): 387 return len(self.keys()) 388 389 def __nonzero__(self): 390 return bool(self.list) 391 392 def read_urlencoded(self): 393 qs = self.fp.read(self.length) 394 if self.qs_on_post: 395 qs += '&' + self.qs_on_post 396 self.list = list = [] 397 for key, value in urlparse.parse_qsl(qs, self.keep_blank_values, self.strict_parsing): 398 list.append(MiniFieldStorage(key, value)) 399 400 self.skip_lines() 401 402 FieldStorageClass = None 403 404 def read_multi(self, environ, keep_blank_values, strict_parsing): 405 ib = self.innerboundary 406 if not valid_boundary(ib): 407 raise ValueError, 'Invalid boundary in multipart form: %r' % (ib,) 408 self.list = [] 409 if self.qs_on_post: 410 for key, value in urlparse.parse_qsl(self.qs_on_post, self.keep_blank_values, self.strict_parsing): 411 self.list.append(MiniFieldStorage(key, value)) 412 413 FieldStorageClass = None 414 klass = self.FieldStorageClass or self.__class__ 415 part = klass(self.fp, {}, ib, environ, keep_blank_values, strict_parsing) 416 while not part.done: 417 headers = rfc822.Message(self.fp) 418 part = klass(self.fp, headers, ib, environ, keep_blank_values, strict_parsing) 419 self.list.append(part) 420 421 self.skip_lines() 422 423 def read_single(self): 424 if self.length >= 0: 425 self.read_binary() 426 self.skip_lines() 427 else: 428 self.read_lines() 429 self.file.seek(0) 430 431 bufsize = 8192 432 433 def read_binary(self): 434 self.file = self.make_file('b') 435 todo = self.length 436 if todo >= 0: 437 while todo > 0: 438 data = self.fp.read(min(todo, self.bufsize)) 439 if not data: 440 self.done = -1 441 break 442 self.file.write(data) 443 todo = todo - len(data) 444 445 def read_lines(self): 446 self.file = self.__file = StringIO() 447 if self.outerboundary: 448 self.read_lines_to_outerboundary() 449 else: 450 self.read_lines_to_eof() 451 452 def __write(self, line): 453 if self.__file is not None: 454 if self.__file.tell() + len(line) > 1000: 455 self.file = self.make_file('') 456 self.file.write(self.__file.getvalue()) 457 self.__file = None 458 self.file.write(line) 459 460 def read_lines_to_eof(self): 461 while 1: 462 line = self.fp.readline(65536) 463 if not line: 464 self.done = -1 465 break 466 self.__write(line) 467 468 def read_lines_to_outerboundary(self): 469 next = '--' + self.outerboundary 470 last = next + '--' 471 delim = '' 472 last_line_lfend = True 473 while 1: 474 line = self.fp.readline(65536) 475 if not line: 476 self.done = -1 477 break 478 if line[:2] == '--' and last_line_lfend: 479 strippedline = line.strip() 480 if strippedline == next: 481 break 482 if strippedline == last: 483 self.done = 1 484 break 485 odelim = delim 486 if line[-2:] == '\r\n': 487 delim = '\r\n' 488 line = line[:-2] 489 last_line_lfend = True 490 elif line[-1] == '\n': 491 delim = '\n' 492 line = line[:-1] 493 last_line_lfend = True 494 else: 495 delim = '' 496 last_line_lfend = False 497 self.__write(odelim + line) 498 499 def skip_lines(self): 500 if not self.outerboundary or self.done: 501 return 502 next = '--' + self.outerboundary 503 last = next + '--' 504 last_line_lfend = True 505 while 1: 506 line = self.fp.readline(65536) 507 if not line: 508 self.done = -1 509 break 510 if line[:2] == '--' and last_line_lfend: 511 strippedline = line.strip() 512 if strippedline == next: 513 break 514 if strippedline == last: 515 self.done = 1 516 break 517 last_line_lfend = line.endswith('\n') 518 519 def make_file(self, binary = None): 520 import tempfile 521 return tempfile.TemporaryFile('w+b') 522 523 524 class FormContentDict(UserDict.UserDict): 525 526 def __init__(self, environ = os.environ, keep_blank_values = 0, strict_parsing = 0): 527 self.dict = self.data = parse(environ=environ, keep_blank_values=keep_blank_values, strict_parsing=strict_parsing) 528 self.query_string = environ['QUERY_STRING'] 529 530 531 class SvFormContentDict(FormContentDict): 532 533 def __getitem__(self, key): 534 if len(self.dict[key]) > 1: 535 raise IndexError, 'expecting a single value' 536 return self.dict[key][0] 537 538 def getlist(self, key): 539 return self.dict[key] 540 541 def values(self): 542 result = [] 543 for value in self.dict.values(): 544 if len(value) == 1: 545 result.append(value[0]) 546 else: 547 result.append(value) 548 549 return result 550 551 def items(self): 552 result = [] 553 for key, value in self.dict.items(): 554 if len(value) == 1: 555 result.append((key, value[0])) 556 else: 557 result.append((key, value)) 558 559 return result 560 561 562 class InterpFormContentDict(SvFormContentDict): 563 564 def __getitem__(self, key): 565 v = SvFormContentDict.__getitem__(self, key) 566 if v[0] in '0123456789+-.': 567 try: 568 return int(v) 569 except ValueError: 570 try: 571 return float(v) 572 except ValueError: 573 pass 574 575 return v.strip() 576 577 def values(self): 578 result = [] 579 for key in self.keys(): 580 try: 581 result.append(self[key]) 582 except IndexError: 583 result.append(self.dict[key]) 584 585 return result 586 587 def items(self): 588 result = [] 589 for key in self.keys(): 590 try: 591 result.append((key, self[key])) 592 except IndexError: 593 result.append((key, self.dict[key])) 594 595 return result 596 597 598 class FormContent(FormContentDict): 599 600 def values(self, key): 601 if key in self.dict: 602 return self.dict[key] 603 else: 604 return None 605 606 def indexed_value(self, key, location): 607 if key in self.dict: 608 if len(self.dict[key]) > location: 609 return self.dict[key][location] 610 else: 611 return None 612 else: 613 return None 614 615 def value(self, key): 616 if key in self.dict: 617 return self.dict[key][0] 618 else: 619 return None 620 621 def length(self, key): 622 return len(self.dict[key]) 623 624 def stripped(self, key): 625 if key in self.dict: 626 return self.dict[key][0].strip() 627 else: 628 return None 629 630 def pars(self): 631 return self.dict 632 633 634 def test(environ = os.environ): 635 global maxlen 636 print 'Content-type: text/html' 637 print 638 sys.stderr = sys.stdout 639 try: 640 form = FieldStorage() 641 print_directory() 642 print_arguments() 643 print_form(form) 644 print_environ(environ) 645 print_environ_usage() 646 647 def f(): 648 exec 'testing print_exception() -- <I>italics?</I>' 649 650 def g(f = f): 651 f() 652 653 print '<H3>What follows is a test, not an actual exception:</H3>' 654 g() 655 except: 656 print_exception() 657 658 print '<H1>Second try with a small maxlen...</H1>' 659 maxlen = 50 660 try: 661 form = FieldStorage() 662 print_directory() 663 print_arguments() 664 print_form(form) 665 print_environ(environ) 666 except: 667 print_exception() 668 669 670 def print_exception(type = None, value = None, tb = None, limit = None): 671 if type is None: 672 type, value, tb = sys.exc_info() 673 import traceback 674 print 675 print '<H3>Traceback (most recent call last):</H3>' 676 list = traceback.format_tb(tb, limit) + traceback.format_exception_only(type, value) 677 print '<PRE>%s<B>%s</B></PRE>' % (escape(''.join(list[:-1])), escape(list[-1])) 678 del tb 679 680 681 def print_environ(environ = os.environ): 682 keys = environ.keys() 683 keys.sort() 684 print 685 print '<H3>Shell Environment:</H3>' 686 print '<DL>' 687 for key in keys: 688 print '<DT>', escape(key), '<DD>', escape(environ[key]) 689 690 print '</DL>' 691 print 692 693 694 def print_form(form): 695 keys = form.keys() 696 keys.sort() 697 print 698 print '<H3>Form Contents:</H3>' 699 if not keys: 700 print '<P>No form fields.' 701 print '<DL>' 702 for key in keys: 703 print '<DT>' + escape(key) + ':', 704 value = form[key] 705 print '<i>' + escape(repr(type(value))) + '</i>' 706 print '<DD>' + escape(repr(value)) 707 708 print '</DL>' 709 print 710 711 712 def print_directory(): 713 print 714 print '<H3>Current Working Directory:</H3>' 715 try: 716 pwd = os.getcwd() 717 except os.error as msg: 718 print 'os.error:', escape(str(msg)) 719 else: 720 print escape(pwd) 721 722 print 723 724 725 def print_arguments(): 726 print 727 print '<H3>Command Line Arguments:</H3>' 728 print 729 print sys.argv 730 print 731 732 733 def print_environ_usage(): 734 print '\n<H3>These environment variables could have been set:</H3>\n<UL>\n<LI>AUTH_TYPE\n<LI>CONTENT_LENGTH\n<LI>CONTENT_TYPE\n<LI>DATE_GMT\n<LI>DATE_LOCAL\n<LI>DOCUMENT_NAME\n<LI>DOCUMENT_ROOT\n<LI>DOCUMENT_URI\n<LI>GATEWAY_INTERFACE\n<LI>LAST_MODIFIED\n<LI>PATH\n<LI>PATH_INFO\n<LI>PATH_TRANSLATED\n<LI>QUERY_STRING\n<LI>REMOTE_ADDR\n<LI>REMOTE_HOST\n<LI>REMOTE_IDENT\n<LI>REMOTE_USER\n<LI>REQUEST_METHOD\n<LI>SCRIPT_NAME\n<LI>SERVER_NAME\n<LI>SERVER_PORT\n<LI>SERVER_PROTOCOL\n<LI>SERVER_ROOT\n<LI>SERVER_SOFTWARE\n</UL>\nIn addition, HTTP headers sent by the server may be passed in the\nenvironment as well. Here are some common variable names:\n<UL>\n<LI>HTTP_ACCEPT\n<LI>HTTP_CONNECTION\n<LI>HTTP_HOST\n<LI>HTTP_PRAGMA\n<LI>HTTP_REFERER\n<LI>HTTP_USER_AGENT\n</UL>\n' 735 736 737 def escape(s, quote = None): 738 s = s.replace('&', '&') 739 s = s.replace('<', '<') 740 s = s.replace('>', '>') 741 if quote: 742 s = s.replace('"', '"') 743 return s 744 745 746 def valid_boundary(s, _vb_pattern = '^[ -~]{0,200}[!-~]$'): 747 import re 748 return re.match(_vb_pattern, s) 749 750 751 if __name__ == '__main__': 752 test()