@@ -109,7 +109,8 @@ impl Host<String> {
109
109
110
110
if domain. find ( is_invalid_domain_char) . is_some ( ) {
111
111
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) ?;
113
114
Ok ( Host :: Ipv4 ( address) )
114
115
} else {
115
116
Ok ( Host :: Domain ( domain) )
@@ -264,8 +265,33 @@ fn longest_zero_sequence(pieces: &[u16; 8]) -> (isize, isize) {
264
265
}
265
266
}
266
267
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
+
267
288
/// <https://url.spec.whatwg.org/#ipv4-number-parser>
289
+ /// Ok(None) means the input is a valid number, but it overflows a `u32`.
268
290
fn parse_ipv4number ( mut input : & str ) -> Result < Option < u32 > , ( ) > {
291
+ if input. is_empty ( ) {
292
+ return Err ( ( ) ) ;
293
+ }
294
+
269
295
let mut r = 10 ;
270
296
if input. starts_with ( "0x" ) || input. starts_with ( "0X" ) {
271
297
input = & input[ 2 ..] ;
@@ -275,10 +301,10 @@ fn parse_ipv4number(mut input: &str) -> Result<Option<u32>, ()> {
275
301
r = 8 ;
276
302
}
277
303
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
+
282
308
let valid_number = match r {
283
309
8 => input. chars ( ) . all ( |c| ( '0' ..='7' ) . contains ( & c) ) ,
284
310
10 => input. chars ( ) . all ( |c| ( '0' ..='9' ) . contains ( & c) ) ,
@@ -287,50 +313,34 @@ fn parse_ipv4number(mut input: &str) -> Result<Option<u32>, ()> {
287
313
} ) ,
288
314
_ => false ,
289
315
} ;
290
-
291
316
if !valid_number {
292
- return Ok ( None ) ;
317
+ return Err ( ( ) ) ;
293
318
}
294
319
295
- if input. is_empty ( ) {
296
- return Ok ( Some ( 0 ) ) ;
297
- }
298
- if input. starts_with ( '+' ) {
299
- return Ok ( None ) ;
300
- }
301
320
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.
304
324
}
305
325
}
306
326
307
327
/// <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 > {
312
329
let mut parts: Vec < & str > = input. split ( '.' ) . collect ( ) ;
313
330
if parts. last ( ) == Some ( & "" ) {
314
331
parts. pop ( ) ;
315
332
}
316
333
if parts. len ( ) > 4 {
317
- return Ok ( None ) ;
334
+ return Err ( ParseError :: InvalidIpv4Address ) ;
318
335
}
319
336
let mut numbers: Vec < u32 > = Vec :: new ( ) ;
320
- let mut overflow = false ;
321
337
for part in parts {
322
- if part. is_empty ( ) {
323
- return Ok ( None ) ;
324
- }
325
338
match parse_ipv4number ( part) {
326
339
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 ) ,
329
342
} ;
330
343
}
331
- if overflow {
332
- return Err ( ParseError :: InvalidIpv4Address ) ;
333
- }
334
344
let mut ipv4 = numbers. pop ( ) . expect ( "a non-empty list of numbers" ) ;
335
345
// Equivalent to: ipv4 >= 256 ** (4 − numbers.len())
336
346
if ipv4 > u32:: max_value ( ) >> ( 8 * numbers. len ( ) as u32 ) {
@@ -342,7 +352,7 @@ fn parse_ipv4addr(input: &str) -> ParseResult<Option<Ipv4Addr>> {
342
352
for ( counter, n) in numbers. iter ( ) . enumerate ( ) {
343
353
ipv4 += n << ( 8 * ( 3 - counter as u32 ) )
344
354
}
345
- Ok ( Some ( Ipv4Addr :: from ( ipv4) ) )
355
+ Ok ( Ipv4Addr :: from ( ipv4) )
346
356
}
347
357
348
358
/// <https://url.spec.whatwg.org/#concept-ipv6-parser>
0 commit comments