From f248c0ce20e2cc3ea4d4a229b764ddd6a8c6afef Mon Sep 17 00:00:00 2001 From: Kousik Mitra Date: Fri, 25 Nov 2022 20:47:08 +0530 Subject: [PATCH] Fix url parsing of ipv6 urls #1931 --- starlette/datastructures.py | 9 ++++++++- tests/test_datastructures.py | 12 ++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/starlette/datastructures.py b/starlette/datastructures.py index ebef2ebdfa..fe9ff6e45e 100644 --- a/starlette/datastructures.py +++ b/starlette/datastructures.py @@ -114,11 +114,18 @@ def replace(self, **kwargs: typing.Any) -> "URL": or "hostname" in kwargs or "port" in kwargs ): - hostname = kwargs.pop("hostname", self.hostname) + hostname = kwargs.pop("hostname", None) port = kwargs.pop("port", self.port) username = kwargs.pop("username", self.username) password = kwargs.pop("password", self.password) + if not hostname: + netloc = self.netloc + _, _, hostname = netloc.rpartition("@") + + if hostname[-1] != "]": + hostname = hostname.rsplit(":", 1)[0] + netloc = hostname if port is not None: netloc += f":{port}" diff --git a/tests/test_datastructures.py b/tests/test_datastructures.py index b87b26e22f..cd5f05095c 100644 --- a/tests/test_datastructures.py +++ b/tests/test_datastructures.py @@ -38,6 +38,18 @@ def test_url(): assert new == "https://example.com:123/path/to/somewhere?abc=123#anchor" assert new.hostname == "example.com" + ipv6_url = URL("https://[fe::2]:12345") + new = ipv6_url.replace(port=8080) + assert new == "https://[fe::2]:8080" + + new = ipv6_url.replace(username="username", password="password") + assert new == "https://username:password@[fe::2]:12345" + assert new.netloc == "username:password@[fe::2]:12345" + + ipv6_url = URL("https://[fe::2]") + new = ipv6_url.replace(port=123) + assert new == "https://[fe::2]:123" + def test_url_query_params(): u = URL("https://example.org/path/?page=3")