@@ -32,30 +32,28 @@ impl<'a> ParsedUrl<'a> {
3232 /// Expected format: scheme://[user[:password]@]host[:port]/path
3333 pub ( crate ) fn parse ( input : & ' a str ) -> Result < Self , ParseError > {
3434 // Find scheme by looking for first ':'
35- let first_colon = input
36- . find ( ':' )
37- . ok_or ( ParseError :: RelativeUrlWithoutBase ) ?;
38-
35+ let first_colon = input. find ( ':' ) . ok_or ( ParseError :: RelativeUrlWithoutBase ) ?;
36+
3937 let scheme = & input[ ..first_colon] ;
40-
38+
4139 // Verify it's followed by "//"
4240 if !input[ first_colon..] . starts_with ( "://" ) {
4341 return Err ( ParseError :: RelativeUrlWithoutBase ) ;
4442 }
45-
43+
4644 // Start after "://"
4745 let after_scheme = & input[ first_colon + 3 ..] ;
48-
46+
4947 // Check for relative URL (scheme without proper authority)
5048 if scheme. is_empty ( ) {
5149 return Err ( ParseError :: RelativeUrlWithoutBase ) ;
5250 }
53-
51+
5452 // Validate scheme characters
5553 if !scheme. chars ( ) . all ( is_valid_scheme_char) {
5654 return Err ( ParseError :: RelativeUrlWithoutBase ) ;
5755 }
58-
56+
5957 // Find path start (first '/' after scheme)
6058 let path_start = after_scheme. find ( '/' ) . unwrap_or ( after_scheme. len ( ) ) ;
6159 let authority = & after_scheme[ ..path_start] ;
@@ -65,34 +63,30 @@ impl<'a> ParsedUrl<'a> {
6563 // No path specified - leave empty (caller can default to / if needed)
6664 ""
6765 } ;
68-
66+
6967 // Parse authority: [user[:password]@]host[:port]
7068 let ( username, password, host, port) = if let Some ( at_pos) = authority. rfind ( '@' ) {
7169 // Has user info
7270 let user_info = & authority[ ..at_pos] ;
7371 let host_port = & authority[ at_pos + 1 ..] ;
74-
72+
7573 let ( user, pass) = if let Some ( colon_pos) = user_info. find ( ':' ) {
7674 let pass_str = & user_info[ colon_pos + 1 ..] ;
7775 // Treat empty password as None
78- let pass = if pass_str. is_empty ( ) {
79- None
80- } else {
81- Some ( pass_str)
82- } ;
76+ let pass = if pass_str. is_empty ( ) { None } else { Some ( pass_str) } ;
8377 ( & user_info[ ..colon_pos] , pass)
8478 } else {
8579 ( user_info, None )
8680 } ;
87-
81+
8882 let ( h, p) = Self :: parse_host_port ( host_port) ?;
8983 ( user, pass, h, p)
9084 } else {
9185 // No user info
9286 let ( h, p) = Self :: parse_host_port ( authority) ?;
9387 ( "" , None , h, p)
9488 } ;
95-
89+
9690 Ok ( ParsedUrl {
9791 scheme,
9892 username,
@@ -102,25 +96,22 @@ impl<'a> ParsedUrl<'a> {
10296 path,
10397 } )
10498 }
105-
99+
106100 fn parse_host_port ( host_port : & str ) -> Result < ( Option < & str > , Option < u16 > ) , ParseError > {
107101 if host_port. is_empty ( ) {
108102 return Ok ( ( None , None ) ) ;
109103 }
110-
104+
111105 // Handle IPv6 addresses: [::1] or [::1]:port
112106 if host_port. starts_with ( '[' ) {
113107 if let Some ( bracket_end) = host_port. find ( ']' ) {
114108 let host = Some ( & host_port[ ..bracket_end + 1 ] ) ;
115109 let remaining = & host_port[ bracket_end + 1 ..] ;
116-
110+
117111 if remaining. is_empty ( ) {
118112 return Ok ( ( host, None ) ) ;
119- } else if remaining. starts_with ( ':' ) {
120- let port_str = & remaining[ 1 ..] ;
121- let port = port_str
122- . parse :: < u16 > ( )
123- . map_err ( |_| ParseError :: InvalidPort ) ?;
113+ } else if let Some ( port_str) = remaining. strip_prefix ( ':' ) {
114+ let port = port_str. parse :: < u16 > ( ) . map_err ( |_| ParseError :: InvalidPort ) ?;
124115 // Validate port is in valid range (1-65535, port 0 is invalid)
125116 if port == 0 {
126117 return Err ( ParseError :: InvalidPort ) ;
@@ -133,7 +124,7 @@ impl<'a> ParsedUrl<'a> {
133124 return Err ( ParseError :: InvalidDomainCharacter ) ;
134125 }
135126 }
136-
127+
137128 // Handle regular host:port
138129 // Use rfind to handle IPv6 addresses without brackets (edge case)
139130 if let Some ( colon_pos) = host_port. rfind ( ':' ) {
@@ -145,45 +136,43 @@ impl<'a> ParsedUrl<'a> {
145136 return Ok ( ( Some ( host) , None ) ) ;
146137 } else if potential_port. chars ( ) . all ( |c| c. is_ascii_digit ( ) ) {
147138 let host = & host_port[ ..colon_pos] ;
148- let port = potential_port
149- . parse :: < u16 > ( )
150- . map_err ( |_| ParseError :: InvalidPort ) ?;
139+ let port = potential_port. parse :: < u16 > ( ) . map_err ( |_| ParseError :: InvalidPort ) ?;
151140 // Validate port is in valid range (1-65535, port 0 is invalid)
152141 if port == 0 {
153142 return Err ( ParseError :: InvalidPort ) ;
154143 }
155144 return Ok ( ( Some ( host) , Some ( port) ) ) ;
156145 }
157146 }
158-
147+
159148 // No port, just host
160149 Ok ( ( Some ( host_port) , None ) )
161150 }
162-
151+
163152 pub ( crate ) fn scheme ( & self ) -> & str {
164153 self . scheme
165154 }
166-
155+
167156 pub ( crate ) fn username ( & self ) -> & str {
168157 self . username
169158 }
170-
159+
171160 pub ( crate ) fn password ( & self ) -> Option < & str > {
172161 self . password
173162 }
174-
163+
175164 pub ( crate ) fn host_str ( & self ) -> Option < & str > {
176165 self . host
177166 }
178-
167+
179168 pub ( crate ) fn port ( & self ) -> Option < u16 > {
180169 self . port
181170 }
182-
171+
183172 pub ( crate ) fn path ( & self ) -> & str {
184173 self . path
185174 }
186-
175+
187176 /// Check if this URL cannot be a base (is relative).
188177 /// For our purposes, since we only parse URLs with "://", they can all be a base.
189178 pub ( crate ) fn cannot_be_a_base ( & self ) -> bool {
0 commit comments