@@ -185,10 +185,11 @@ impl<'a> ParsedUrl<'a> {
185185
186186 /// Validate and possibly normalize a hostname
187187 /// Valid DNS hostnames are normalized to lowercase
188- /// Invalid strings (like injection attempts) are preserved as-is but ? is rejected
188+ /// Hostnames containing ? or whitespace characters are rejected with an error
189189 fn normalize_hostname ( host : & str ) -> Result < String , UrlParseError > {
190- // Reject ? character which git's url parser rejects
191- if host. contains ( '?' ) {
190+ // Reject invalid characters: ?, space, tab, newline, etc.
191+ // These characters are forbidden in URLs per RFC 3986
192+ if host. chars ( ) . any ( |c| c == '?' || c. is_whitespace ( ) ) {
192193 return Err ( UrlParseError :: InvalidDomainCharacter ) ;
193194 }
194195
@@ -261,4 +262,21 @@ mod tests {
261262 assert_eq ! ( url. port, Some ( 8080 ) ) ;
262263 assert_eq ! ( url. path, "/path" ) ;
263264 }
265+
266+ #[ test]
267+ fn test_url_with_space_in_host_is_rejected ( ) {
268+ assert ! ( ParsedUrl :: parse( "http://has a space" ) . is_err( ) ) ;
269+ assert ! ( ParsedUrl :: parse( "http://has a space/path" ) . is_err( ) ) ;
270+ assert ! ( ParsedUrl :: parse( "https://example.com with space/path" ) . is_err( ) ) ;
271+ }
272+
273+ #[ test]
274+ fn test_url_with_tab_in_host_is_rejected ( ) {
275+ assert ! ( ParsedUrl :: parse( "http://has\t a\t tab" ) . is_err( ) ) ;
276+ }
277+
278+ #[ test]
279+ fn test_url_with_newline_in_host_is_rejected ( ) {
280+ assert ! ( ParsedUrl :: parse( "http://has\n a\n newline" ) . is_err( ) ) ;
281+ }
264282}
0 commit comments