Index: Lib/urllib/parse.py =================================================================== --- Lib/urllib/parse.py (revision 79950) +++ Lib/urllib/parse.py (working copy) @@ -1,7 +1,17 @@ """Parse (absolute and relative) URLs. -See RFC 1808: "Relative Uniform Resource Locators", by R. Fielding, -UC Irvine, June 1995. +See: + + RFC 1738: "Uniform Resource Locators (URL)" + T. Berners-Lee, L. Masinter, M. McCahill, December 1994 + RFC 1808: "Relative Uniform Resource Locators" + R. Fielding, UC Irvine, June 1995. + RFC 2373: "IP Version 6 Addressing Architecture" + R. Hinden, S. Deering, July 1998 + RFC 3986, "Uniform Resource Identifiers" + by T. Berners-Lee, R. Fielding and L. Masinter, January 2005 + RFC 2732: "Format for Literal IPv6 Addresses in URL's" + R. Hinden, B. Carpenter, L. Masinter, December 1999 """ import sys @@ -70,22 +80,23 @@ @property def hostname(self): - netloc = self.netloc - if "@" in netloc: - netloc = netloc.rsplit("@", 1)[1] - if ":" in netloc: - netloc = netloc.split(":", 1)[0] - return netloc.lower() or None + netloc = self.netloc.split("@")[-1] + if "]" in netloc: + return netloc.split("]")[0][1:].lower() + elif ":" in netloc: + return netloc.split(":")[0].lower() + elif netloc == '': + return None + else: + return netloc.lower() @property def port(self): - netloc = self.netloc - if "@" in netloc: - netloc = netloc.rsplit("@", 1)[1] + netloc = self.netloc.split("@")[-1].split("]")[-1] if ":" in netloc: - port = netloc.split(":", 1)[1] - return int(port, 10) - return None + return int(netloc.split(":")[1], 10) + else: + return None from collections import namedtuple Index: Lib/test/test_urlparse.py =================================================================== --- Lib/test/test_urlparse.py (revision 79961) +++ Lib/test/test_urlparse.py (working copy) @@ -354,6 +354,34 @@ self.assertEqual(urllib.parse.urlparse("x-newscheme://foo.com/stuff"), ('x-newscheme', 'foo.com', '/stuff', '', '', '')) + + def test_rfc2732(self): + for url, hostname, port in [ + ('http://Test.python.org:5432/foo/', 'test.python.org', 5432), + ('http://12.34.56.78:5432/foo/', '12.34.56.78', 5432), + ('http://[::1]:5432/foo/', '::1', 5432), + ('http://[dead:beef::1]:5432/foo/', 'dead:beef::1', 5432), + ('http://[dead:beef::]:5432/foo/', 'dead:beef::', 5432), + ('http://[dead:beef:cafe:5417:affe:8FA3:deaf:feed]:5432/foo/', + 'dead:beef:cafe:5417:affe:8fa3:deaf:feed', 5432), + ('http://[::12.34.56.78]:5432/foo/', '::12.34.56.78', 5432), + ('http://[::ffff:12.34.56.78]:5432/foo/', + '::ffff:12.34.56.78', 5432), + ('http://Test.python.org/foo/', 'test.python.org', None), + ('http://12.34.56.78/foo/', '12.34.56.78', None), + ('http://[::1]/foo/', '::1', None), + ('http://[dead:beef::1]/foo/', 'dead:beef::1', None), + ('http://[dead:beef::]/foo/', 'dead:beef::', None), + ('http://[dead:beef:cafe:5417:affe:8FA3:deaf:feed]/foo/', + 'dead:beef:cafe:5417:affe:8fa3:deaf:feed', None), + ('http://[::12.34.56.78]/foo/', '::12.34.56.78', None), + ('http://[::ffff:12.34.56.78]/foo/', + '::ffff:12.34.56.78', None), + ]: + urlparsed = urllib.parse.urlparse(url) + self.assertEqual((urlparsed.hostname, urlparsed.port) , (hostname, port)) + + def test_main(): support.run_unittest(UrlParseTestCase)