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