diff -r 668aba845fb2 Lib/test/test_urlparse.py --- a/Lib/test/test_urlparse.py Mon Jun 10 09:24:01 2013 -0700 +++ b/Lib/test/test_urlparse.py Wed Jun 19 23:17:41 2013 +0200 @@ -484,6 +484,21 @@ self.assertEqual(p.port, 80) self.assertEqual(p.geturl(), url) + # Addressing issue1698, which suggests Password can contain + # "#" and "?" characters. This format is also not RFC compliant. + url = "http://User:Pa#?ss@www.python.org:080/doc/?query=yes#frag" + p = urllib.parse.urlsplit(url) + self.assertEqual(p.scheme, "http") + self.assertEqual(p.netloc, "User:Pa#?ss@www.python.org:080") + self.assertEqual(p.path, "/doc/") + self.assertEqual(p.query, "query=yes") + self.assertEqual(p.fragment, "frag") + self.assertEqual(p.username, "User") + self.assertEqual(p.password, "Pa#?ss") + self.assertEqual(p.hostname, "www.python.org") + self.assertEqual(p.port, 80) + self.assertEqual(p.geturl(), url) + # And check them all again, only with bytes this time url = b"HTTP://WWW.PYTHON.ORG/doc/#frag" p = urllib.parse.urlsplit(url) diff -r 668aba845fb2 Lib/urllib/parse.py --- a/Lib/urllib/parse.py Mon Jun 10 09:24:01 2013 -0700 +++ b/Lib/urllib/parse.py Wed Jun 19 23:17:41 2013 +0200 @@ -310,8 +310,13 @@ def _splitnetloc(url, start=0): delim = len(url) # position of end of domain part of url, default is end + at_symbol_index = url.find('@') # ensure passwords containing delims + if at_symbol_index > start: # are not treated as fragments by + cutoff = at_symbol_index # beginning to search for delimiters + else: # after the first '@' symbol + cutoff = start for c in '/?#': # look for delimiters; the order is NOT important - wdelim = url.find(c, start) # find first of this delim + wdelim = url.find(c, cutoff) # find first of this delim if wdelim >= 0: # if found delim = min(delim, wdelim) # use earliest delim position return url[start:delim], url[delim:] # return (domain, rest)