diff --git a/docs/project/changelog.rst b/docs/project/changelog.rst index 3e147f850..7f0fd7fd6 100644 --- a/docs/project/changelog.rst +++ b/docs/project/changelog.rst @@ -47,6 +47,9 @@ Improvements Bug fixes ......... +* Preserved percent-encoded sequences in paths and queries when connecting to + internationalized URIs. + * Fixed a regression from 16.1 where the legacy implementation rejected non-ASCII headers. diff --git a/src/websockets/uri.py b/src/websockets/uri.py index f85e16810..abcd20ebe 100644 --- a/src/websockets/uri.py +++ b/src/websockets/uri.py @@ -97,8 +97,8 @@ def parse_uri(uri: str) -> WebSocketURI: # Input contains non-ASCII characters. # It must be an IRI. Convert it to a URI. host = host.encode("idna").decode() - path = urllib.parse.quote(path, safe=DELIMS) - query = urllib.parse.quote(query, safe=DELIMS) + path = urllib.parse.quote(path, safe=DELIMS + "%") + query = urllib.parse.quote(query, safe=DELIMS + "%") if username is not None: assert password is not None username = urllib.parse.quote(username, safe=DELIMS) diff --git a/tests/test_uri.py b/tests/test_uri.py index 057a17291..ed6dc2717 100644 --- a/tests/test_uri.py +++ b/tests/test_uri.py @@ -64,6 +64,9 @@ ("ws://localhost", "/"), ("ws://localhost/path?query", "/path?query"), ("ws://høst/πass?qùéry", "/%CF%80ass?q%C3%B9%C3%A9ry"), + ("ws://høst/a%20b?x=%26%3D%2B", "/a%20b?x=%26%3D%2B"), + ("ws://localhost/café%2Fmenu?x=%25", "/caf%C3%A9%2Fmenu?x=%25"), + ("ws://localhost/a%2fb?q=café%26tea", "/a%2fb?q=caf%C3%A9%26tea"), ] URIS_WITH_USER_INFO = [