@@ -55,6 +55,7 @@ def _quote_byte(error: UnicodeError) -> Tuple[str, int]:
5555
5656_safe_chars = RFC3986_RESERVED + RFC3986_UNRESERVED + EXTRA_SAFE_CHARS + b"%"
5757_path_safe_chars = _safe_chars .replace (b"#" , b"" )
58+ RFC3986_USERINFO_SAFE_CHARS = RFC3986_UNRESERVED + RFC3986_SUB_DELIMS + b":"
5859
5960_ascii_tab_newline_re = re .compile (
6061 r"[\t\n\r]"
@@ -95,14 +96,34 @@ def safe_url_string(
9596 decoded = to_unicode (url , encoding = encoding , errors = "percentencode" )
9697 parts = urlsplit (_ascii_tab_newline_re .sub ("" , decoded ))
9798
98- # IDNA encoding can fail for too long labels (>63 characters)
99- # or missing labels (e.g. http://.example.com)
100- try :
101- netloc_bytes = parts .netloc .encode ("idna" )
102- except UnicodeError :
103- netloc = parts .netloc
104- else :
105- netloc = netloc_bytes .decode ()
99+ username , password , hostname , port = (
100+ parts .username ,
101+ parts .password ,
102+ parts .hostname ,
103+ parts .port ,
104+ )
105+ netloc_bytes = b""
106+ if username is not None or password is not None :
107+ if username is not None :
108+ safe_username = quote (username , RFC3986_USERINFO_SAFE_CHARS )
109+ netloc_bytes += safe_username .encode (encoding )
110+ if password is not None :
111+ netloc_bytes += b":"
112+ safe_password = quote (password , RFC3986_USERINFO_SAFE_CHARS )
113+ netloc_bytes += safe_password .encode (encoding )
114+ netloc_bytes += b"@"
115+ if hostname is not None :
116+ try :
117+ netloc_bytes += hostname .encode ("idna" )
118+ except UnicodeError :
119+ # IDNA encoding can fail for too long labels (>63 characters) or
120+ # missing labels (e.g. http://.example.com)
121+ netloc_bytes += hostname .encode (encoding )
122+ if port is not None :
123+ netloc_bytes += b":"
124+ netloc_bytes += str (port ).encode (encoding )
125+
126+ netloc = netloc_bytes .decode ()
106127
107128 # default encoding for path component SHOULD be UTF-8
108129 if quote_path :
@@ -113,7 +134,7 @@ def safe_url_string(
113134 return urlunsplit (
114135 (
115136 parts .scheme ,
116- netloc . rstrip ( ":" ) ,
137+ netloc ,
117138 path ,
118139 quote (parts .query .encode (encoding ), _safe_chars ),
119140 quote (parts .fragment .encode (encoding ), _safe_chars ),
0 commit comments