diff options
author | Bert JW Regeer <bertjw@regeer.org> | 2019-08-27 14:36:05 -0600 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-08-27 14:36:05 -0600 |
commit | e247c93ce932c0184c5242d451e5776b17a20d21 (patch) | |
tree | 1800a88a481b54395d44b89151f48cd4fa9ec04d | |
parent | 94e23114bf4e8db9507f3550294037a4804eb053 (diff) | |
parent | 2bd372a52c2e2f18258e593885c16db68172ff1b (diff) | |
download | waitress-e247c93ce932c0184c5242d451e5776b17a20d21.tar.gz |
Merge pull request #261 from Pylons/bugfix/uri_parsing
Bugfix: uri parsing
-rw-r--r-- | CHANGES.txt | 14 | ||||
-rw-r--r-- | waitress/parser.py | 28 | ||||
-rw-r--r-- | waitress/tests/test_parser.py | 24 |
3 files changed, 62 insertions, 4 deletions
diff --git a/CHANGES.txt b/CHANGES.txt index 01fe6f3..f511dbb 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,3 +1,17 @@ +1.3.1 (2019-08-27) +------------------ + +Bugfixes +~~~~~~~~ + +- Waitress won't accidentally throw away part of the path if it starts with a + double slash (``GET //testing/whatever HTTP/1.0``). WSGI applications will + now receive a ``PATH_INFO`` in the environment that contains + ``//testing/whatever`` as required. See + https://github.com/Pylons/waitress/issues/260 and + https://github.com/Pylons/waitress/pull/261 + + 1.3.0 (2019-04-22) ------------------ diff --git a/waitress/parser.py b/waitress/parser.py index e85ede2..6ee700e 100644 --- a/waitress/parser.py +++ b/waitress/parser.py @@ -253,10 +253,30 @@ class HTTPRequestParser(object): def split_uri(uri): # urlsplit handles byte input by returning bytes on py3, so # scheme, netloc, path, query, and fragment are bytes - try: - scheme, netloc, path, query, fragment = urlparse.urlsplit(uri) - except UnicodeError: - raise ParsingError('Bad URI') + + scheme = netloc = path = query = fragment = b'' + + # urlsplit below will treat this as a scheme-less netloc, thereby losing + # the original intent of the request. Here we shamelessly stole 4 lines of + # code from the CPython stdlib to parse out the fragment and query but + # leave the path alone. See + # https://github.com/python/cpython/blob/8c9e9b0cd5b24dfbf1424d1f253d02de80e8f5ef/Lib/urllib/parse.py#L465-L468 + # and https://github.com/Pylons/waitress/issues/260 + + if uri[:2] == b'//': + path = uri + + if b'#' in path: + path, fragment = path.split(b'#', 1) + + if b'?' in path: + path, query = path.split(b'?', 1) + else: + try: + scheme, netloc, path, query, fragment = urlparse.urlsplit(uri) + except UnicodeError: + raise ParsingError('Bad URI') + return ( tostr(scheme), tostr(netloc), diff --git a/waitress/tests/test_parser.py b/waitress/tests/test_parser.py index cf4a976..920de96 100644 --- a/waitress/tests/test_parser.py +++ b/waitress/tests/test_parser.py @@ -259,6 +259,30 @@ class Test_split_uri(unittest.TestCase): except ParsingError: pass + def test_split_uri_path(self): + self._callFUT(b'//testing/whatever') + self.assertEqual(self.path, '//testing/whatever') + self.assertEqual(self.proxy_scheme, '') + self.assertEqual(self.proxy_netloc, '') + self.assertEqual(self.query, '') + self.assertEqual(self.fragment, '') + + def test_split_uri_path_query(self): + self._callFUT(b'//testing/whatever?a=1&b=2') + self.assertEqual(self.path, '//testing/whatever') + self.assertEqual(self.proxy_scheme, '') + self.assertEqual(self.proxy_netloc, '') + self.assertEqual(self.query, 'a=1&b=2') + self.assertEqual(self.fragment, '') + + def test_split_uri_path_query_fragment(self): + self._callFUT(b'//testing/whatever?a=1&b=2#fragment') + self.assertEqual(self.path, '//testing/whatever') + self.assertEqual(self.proxy_scheme, '') + self.assertEqual(self.proxy_netloc, '') + self.assertEqual(self.query, 'a=1&b=2') + self.assertEqual(self.fragment, 'fragment') + class Test_get_header_lines(unittest.TestCase): def _callFUT(self, data): |