From c7064b29d23e83f40b5001c7acb2a977f2c64fcf Mon Sep 17 00:00:00 2001 From: Muneeb Sheikh Date: Sun, 11 Oct 2026 13:53:43 -0400 Subject: [PATCH] Replace the authority when resolving network-path references --- src/hyperlink/_url.py | 6 ++++++ src/hyperlink/test/test_url.py | 23 +++++++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/src/hyperlink/_url.py b/src/hyperlink/_url.py index 8797b5cc..d6e507ea 100644 --- a/src/hyperlink/_url.py +++ b/src/hyperlink/_url.py @@ -1619,6 +1619,12 @@ def click(self, href=u""): else: clicked = self + if clicked.uses_netloc: + return clicked.replace( + scheme=clicked.scheme or self.scheme, + path=_resolve_dot_segments(clicked.path), + ) + query = clicked.query if clicked.scheme and not clicked.rooted: # Schemes with relative paths are not well-defined. RFC 3986 calls diff --git a/src/hyperlink/test/test_url.py b/src/hyperlink/test/test_url.py index 37c91726..de0c23ec 100644 --- a/src/hyperlink/test/test_url.py +++ b/src/hyperlink/test/test_url.py @@ -412,6 +412,29 @@ def test_sibling(self): urlpath.sibling("sister").to_text(), ) + def test_click_network_path_replaces_authority(self): + # type: () -> None + base = URL.from_text("http://user:password@example.com:8080/old?q=base") + for href, expected in [ + ("//other.example/new", "http://other.example/new"), + ("//other.example", "http://other.example"), + ("//other.example?x=1", "http://other.example/?x=1"), + ("//other.example:0/new", "http://other.example:0/new"), + ("//newuser@other.example/new", "http://newuser@other.example/new"), + ("//other.example/a/../new", "http://other.example/new"), + ]: + self.assertEqual( + base.click(href).to_text(with_password=True), expected + ) + self.assertEqual( + base.click("/new").to_text(with_password=True), + "http://user:password@example.com:8080/new", + ) + self.assertEqual( + base.to_text(with_password=True), + "http://user:password@example.com:8080/old?q=base", + ) + def test_click(self): # type: () -> None """