1b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik# code stolen from "six" 2b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik 3b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikimport sys 4b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikimport types 5b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik 6b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik# True if we are running on Python 3. 7b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris CraikPY3 = sys.version_info[0] == 3 8b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik 9b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikif PY3: # pragma: no cover 10b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik string_types = str, 11b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik integer_types = int, 12b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik class_types = type, 13b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik text_type = str 14b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik long = int 15b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikelse: 16b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik string_types = basestring, 17b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik integer_types = (int, long) 18b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik class_types = (type, types.ClassType) 19b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik text_type = unicode 20b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik long = long 21b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik 22b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik# TODO check if errors is ever used 23b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik 24b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikdef text_(s, encoding='latin-1', errors='strict'): 25b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik if isinstance(s, bytes): 26b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik return s.decode(encoding, errors) 27b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik return s 28b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik 29b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikdef bytes_(s, encoding='latin-1', errors='strict'): 30b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik if isinstance(s, text_type): 31b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik return s.encode(encoding, errors) 32b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik return s 33b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik 34b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikif PY3: # pragma: no cover 35b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik def native_(s, encoding='latin-1', errors='strict'): 36b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik if isinstance(s, text_type): 37b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik return s 38b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik return str(s, encoding, errors) 39b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikelse: 40b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik def native_(s, encoding='latin-1', errors='strict'): 41b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik if isinstance(s, text_type): 42b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik return s.encode(encoding, errors) 43b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik return str(s) 44b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik 45b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craiktry: 46b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik from queue import Queue, Empty 47b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikexcept ImportError: 48b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik from Queue import Queue, Empty 49b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik 50b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikif PY3: # pragma: no cover 51b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik from urllib import parse 52b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik urlparse = parse 53b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik from urllib.parse import quote as url_quote 54b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik from urllib.parse import urlencode as url_encode, quote_plus 55b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik from urllib.request import urlopen as url_open 56b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikelse: 57b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik import urlparse 58b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik from urllib import quote_plus 59b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik from urllib import quote as url_quote 60b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik from urllib import unquote as url_unquote 61b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik from urllib import urlencode as url_encode 62b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik from urllib2 import urlopen as url_open 63b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik 64b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikif PY3: # pragma: no cover 65b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik def reraise(exc_info): 66b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik etype, exc, tb = exc_info 67b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik if exc.__traceback__ is not tb: 68b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik raise exc.with_traceback(tb) 69b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik raise exc 70b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikelse: # pragma: no cover 71b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik exec("def reraise(exc): raise exc[0], exc[1], exc[2]") 72b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik 73b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik 74b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikif PY3: # pragma: no cover 75b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik def iteritems_(d): 76b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik return d.items() 77b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik def itervalues_(d): 78b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik return d.values() 79b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikelse: 80b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik def iteritems_(d): 81b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik return d.iteritems() 82b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik def itervalues_(d): 83b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik return d.itervalues() 84b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik 85b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik 86b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikif PY3: # pragma: no cover 87b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik def unquote(string): 88b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik if not string: 89b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik return b'' 90b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik res = string.split(b'%') 91b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik if len(res) != 1: 92b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik string = res[0] 93b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik for item in res[1:]: 94b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik try: 95b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik string += bytes([int(item[:2], 16)]) + item[2:] 96b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik except ValueError: 97b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik string += b'%' + item 98b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik return string 99b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik 100b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik def url_unquote(s): 101b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik return unquote(s.encode('ascii')).decode('latin-1') 102b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik 103b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik def parse_qsl_text(qs, encoding='utf-8'): 104b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik qs = qs.encode('latin-1') 105b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik qs = qs.replace(b'+', b' ') 106b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik pairs = [s2 for s1 in qs.split(b'&') for s2 in s1.split(b';') if s2] 107b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik for name_value in pairs: 108b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik nv = name_value.split(b'=', 1) 109b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik if len(nv) != 2: 110b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik nv.append('') 111b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik name = unquote(nv[0]) 112b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik value = unquote(nv[1]) 113b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik yield (name.decode(encoding), value.decode(encoding)) 114b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik 115b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikelse: 116b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik from urlparse import parse_qsl 117b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik 118b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik def parse_qsl_text(qs, encoding='utf-8'): 119b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik qsl = parse_qsl( 120b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik qs, 121b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik keep_blank_values=True, 122b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik strict_parsing=False 123b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik ) 124b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik for (x, y) in qsl: 125b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik yield (x.decode(encoding), y.decode(encoding)) 126b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik 127b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik 128b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikif PY3: # pragma no cover 129b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik from html import escape 130b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikelse: 131b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik from cgi import escape 132b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik 133b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik 134b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik# We only need this on Python3 but the issue was fixed in Pytohn 3.4.4 and 3.5. 135b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikif PY3 and sys.version_info[:3] < (3, 4, 4): # pragma no cover 136b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik # Work around http://bugs.python.org/issue23801 137b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik import cgi 138b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik from cgi import FieldStorage as _cgi_FieldStorage 139b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik 140b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik class cgi_FieldStorage(_cgi_FieldStorage): 141b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik # This is taken exactly from Python 3.5's cgi.py module, and patched 142b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik # with the patch from http://bugs.python.org/issue23801. 143b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik def read_multi(self, environ, keep_blank_values, strict_parsing): 144b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik """Internal: read a part that is itself multipart.""" 145b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik ib = self.innerboundary 146b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik if not cgi.valid_boundary(ib): 147b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik raise ValueError( 148b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik 'Invalid boundary in multipart form: %r' % (ib,)) 149b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik self.list = [] 150b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik if self.qs_on_post: 151b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik query = cgi.urllib.parse.parse_qsl( 152b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik self.qs_on_post, self.keep_blank_values, 153b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik self.strict_parsing, 154b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik encoding=self.encoding, errors=self.errors) 155b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik for key, value in query: 156b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik self.list.append(cgi.MiniFieldStorage(key, value)) 157b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik 158b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik klass = self.FieldStorageClass or self.__class__ 159b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik first_line = self.fp.readline() # bytes 160b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik if not isinstance(first_line, bytes): 161b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik raise ValueError("%s should return bytes, got %s" 162b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik % (self.fp, type(first_line).__name__)) 163b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik self.bytes_read += len(first_line) 164b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik 165b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik # Ensure that we consume the file until we've hit our innerboundary 166b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik while (first_line.strip() != (b"--" + self.innerboundary) and 167b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik first_line): 168b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik first_line = self.fp.readline() 169b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik self.bytes_read += len(first_line) 170b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik 171b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik while True: 172b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik parser = cgi.FeedParser() 173b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik hdr_text = b"" 174b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik while True: 175b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik data = self.fp.readline() 176b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik hdr_text += data 177b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik if not data.strip(): 178b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik break 179b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik if not hdr_text: 180b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik break 181b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik # parser takes strings, not bytes 182b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik self.bytes_read += len(hdr_text) 183b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik parser.feed(hdr_text.decode(self.encoding, self.errors)) 184b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik headers = parser.close() 185b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik part = klass(self.fp, headers, ib, environ, keep_blank_values, 186b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik strict_parsing, self.limit-self.bytes_read, 187b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik self.encoding, self.errors) 188b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik self.bytes_read += part.bytes_read 189b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik self.list.append(part) 190b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik if part.done or self.bytes_read >= self.length > 0: 191b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik break 192b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik self.skip_lines() 193b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikelse: 194b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik from cgi import FieldStorage as cgi_FieldStorage 195