@@ -109,7 +109,8 @@ impl Host<String> {
109109
110110 if domain. find ( is_invalid_domain_char) . is_some ( ) {
111111 Err ( ParseError :: InvalidDomainCharacter )
112- } else if let Some ( address) = parse_ipv4addr ( & domain) ? {
112+ } else if ends_in_a_number ( & domain) {
113+ let address = parse_ipv4addr ( & domain) ?;
113114 Ok ( Host :: Ipv4 ( address) )
114115 } else {
115116 Ok ( Host :: Domain ( domain) )
@@ -264,8 +265,33 @@ fn longest_zero_sequence(pieces: &[u16; 8]) -> (isize, isize) {
264265 }
265266}
266267
268+ /// <https://url.spec.whatwg.org/#ends-in-a-number-checker>
269+ fn ends_in_a_number ( input : & str ) -> bool {
270+ let mut parts = input. rsplit ( '.' ) ;
271+ let last = parts. next ( ) . unwrap ( ) ;
272+ let last = if last. is_empty ( ) {
273+ if let Some ( last) = parts. next ( ) {
274+ last
275+ } else {
276+ return false ;
277+ }
278+ } else {
279+ last
280+ } ;
281+ if !last. is_empty ( ) && last. chars ( ) . all ( |c| ( '0' ..='9' ) . contains ( & c) ) {
282+ return true ;
283+ }
284+
285+ parse_ipv4number ( last) . is_ok ( )
286+ }
287+
267288/// <https://url.spec.whatwg.org/#ipv4-number-parser>
289+ /// Ok(None) means the input is a valid number, but it overflows a `u32`.
268290fn parse_ipv4number ( mut input : & str ) -> Result < Option < u32 > , ( ) > {
291+ if input. is_empty ( ) {
292+ return Err ( ( ) ) ;
293+ }
294+
269295 let mut r = 10 ;
270296 if input. starts_with ( "0x" ) || input. starts_with ( "0X" ) {
271297 input = & input[ 2 ..] ;
@@ -275,10 +301,10 @@ fn parse_ipv4number(mut input: &str) -> Result<Option<u32>, ()> {
275301 r = 8 ;
276302 }
277303
278- // At the moment we can't know the reason why from_str_radix fails
279- // https://github.com/rust-lang/rust/issues/22639
280- // So instead we check if the input looks like a real number and only return
281- // an error when it's an overflow.
304+ if input . is_empty ( ) {
305+ return Ok ( Some ( 0 ) ) ;
306+ }
307+
282308 let valid_number = match r {
283309 8 => input. chars ( ) . all ( |c| ( '0' ..='7' ) . contains ( & c) ) ,
284310 10 => input. chars ( ) . all ( |c| ( '0' ..='9' ) . contains ( & c) ) ,
@@ -287,50 +313,34 @@ fn parse_ipv4number(mut input: &str) -> Result<Option<u32>, ()> {
287313 } ) ,
288314 _ => false ,
289315 } ;
290-
291316 if !valid_number {
292- return Ok ( None ) ;
317+ return Err ( ( ) ) ;
293318 }
294319
295- if input. is_empty ( ) {
296- return Ok ( Some ( 0 ) ) ;
297- }
298- if input. starts_with ( '+' ) {
299- return Ok ( None ) ;
300- }
301320 match u32:: from_str_radix ( input, r) {
302- Ok ( number) => Ok ( Some ( number) ) ,
303- Err ( _) => Err ( ( ) ) ,
321+ Ok ( num) => Ok ( Some ( num) ) ,
322+ Err ( _) => Ok ( None ) , // The only possible error kind here is an integer overflow.
323+ // The validity of the chars in the input is checked above.
304324 }
305325}
306326
307327/// <https://url.spec.whatwg.org/#concept-ipv4-parser>
308- fn parse_ipv4addr ( input : & str ) -> ParseResult < Option < Ipv4Addr > > {
309- if input. is_empty ( ) {
310- return Ok ( None ) ;
311- }
328+ fn parse_ipv4addr ( input : & str ) -> ParseResult < Ipv4Addr > {
312329 let mut parts: Vec < & str > = input. split ( '.' ) . collect ( ) ;
313330 if parts. last ( ) == Some ( & "" ) {
314331 parts. pop ( ) ;
315332 }
316333 if parts. len ( ) > 4 {
317- return Ok ( None ) ;
334+ return Err ( ParseError :: InvalidIpv4Address ) ;
318335 }
319336 let mut numbers: Vec < u32 > = Vec :: new ( ) ;
320- let mut overflow = false ;
321337 for part in parts {
322- if part. is_empty ( ) {
323- return Ok ( None ) ;
324- }
325338 match parse_ipv4number ( part) {
326339 Ok ( Some ( n) ) => numbers. push ( n) ,
327- Ok ( None ) => return Ok ( None ) ,
328- Err ( ( ) ) => overflow = true ,
340+ Ok ( None ) => return Err ( ParseError :: InvalidIpv4Address ) , // u32 overflow
341+ Err ( ( ) ) => return Err ( ParseError :: InvalidIpv4Address ) ,
329342 } ;
330343 }
331- if overflow {
332- return Err ( ParseError :: InvalidIpv4Address ) ;
333- }
334344 let mut ipv4 = numbers. pop ( ) . expect ( "a non-empty list of numbers" ) ;
335345 // Equivalent to: ipv4 >= 256 ** (4 − numbers.len())
336346 if ipv4 > u32:: max_value ( ) >> ( 8 * numbers. len ( ) as u32 ) {
@@ -342,7 +352,7 @@ fn parse_ipv4addr(input: &str) -> ParseResult<Option<Ipv4Addr>> {
342352 for ( counter, n) in numbers. iter ( ) . enumerate ( ) {
343353 ipv4 += n << ( 8 * ( 3 - counter as u32 ) )
344354 }
345- Ok ( Some ( Ipv4Addr :: from ( ipv4) ) )
355+ Ok ( Ipv4Addr :: from ( ipv4) )
346356}
347357
348358/// <https://url.spec.whatwg.org/#concept-ipv6-parser>
0 commit comments