diff --git a/falcon/request.py b/falcon/request.py index 54ce059..102bcb8 100644 --- a/falcon/request.py +++ b/falcon/request.py @@ -220,6 +220,11 @@ class Request(object): # Normalize path path = env['PATH_INFO'] if path: + if six.PY3: # pragma: no cover + # PEP 3333 specifies that PATH_INFO variable are always + # "bytes tunneled as latin-1" and must be encoded back + path = path.encode('latin1').decode('utf-8', 'replace') + if len(path) != 1 and path.endswith('/'): self.path = path[:-1] else: diff --git a/tests/test_req_vars.py b/tests/test_req_vars.py index 48dfe06..7e7f414 100644 --- a/tests/test_req_vars.py +++ b/tests/test_req_vars.py @@ -1,4 +1,6 @@ import datetime +import six +import testtools import ddt @@ -107,6 +109,16 @@ class TestReqVars(testing.TestBase): self.assertEqual(expected_uri, req.uri) + @testtools.skipUnless(six.PY3, 'Test only applies to Python 3') + def test_nonlatin_path(self): + cyrillic_path = u'/hello_\u043f\u0440\u0438\u0432\u0435\u0442' + cyrillic_path_decoded = cyrillic_path.encode('utf-8').decode('latin1') + req = Request(testing.create_environ( + host='com', + path=cyrillic_path_decoded, + headers=self.headers)) + self.assertEqual(req.path, cyrillic_path) + def test_uri(self): uri = ('http://' + testing.DEFAULT_HOST + ':8080' + self.app + self.relative_uri)