Skip to content

Commit 4899458

Browse files
committed
Fail IPv4 parsing when the number is overflowing
1 parent edee129 commit 4899458

File tree

2 files changed

+44
-9
lines changed

2 files changed

+44
-9
lines changed

src/host.rs

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -329,7 +329,7 @@ fn longest_zero_sequence(pieces: &[u16; 8]) -> (isize, isize) {
329329
}
330330

331331
/// <https://url.spec.whatwg.org/#ipv4-number-parser>
332-
fn parse_ipv4number(mut input: &str) -> Result<u32, ()> {
332+
fn parse_ipv4number(mut input: &str) -> Result<Option<u32>, ()> {
333333
let mut r = 10;
334334
if input.starts_with("0x") || input.starts_with("0X") {
335335
input = &input[2..];
@@ -338,14 +338,30 @@ fn parse_ipv4number(mut input: &str) -> Result<u32, ()> {
338338
input = &input[1..];
339339
r = 8;
340340
}
341+
342+
// At the moment we can't know the reason why from_str_radix fails
343+
// https://github.com/rust-lang/rust/issues/22639
344+
// So instead we check if the input looks like a real number and only return
345+
// an error when it's an overflow.
346+
let valid_number = match r {
347+
8 => input.chars().all(|c| c >= '0' && c <='7'),
348+
10 => input.chars().all(|c| c >= '0' && c <='9'),
349+
16 => input.chars().all(|c| (c >= '0' && c <='9') || (c >='a' && c <= 'f') || (c >= 'A' && c <= 'F')),
350+
_ => false
351+
};
352+
353+
if !valid_number {
354+
return Ok(None);
355+
}
356+
341357
if input.is_empty() {
342-
return Ok(0);
358+
return Ok(Some(0));
343359
}
344360
if input.starts_with('+') {
345-
return Err(())
361+
return Ok(None);
346362
}
347363
match u32::from_str_radix(input, r) {
348-
Ok(number) => Ok(number),
364+
Ok(number) => Ok(Some(number)),
349365
Err(_) => Err(()),
350366
}
351367
}
@@ -363,15 +379,19 @@ fn parse_ipv4addr(input: &str) -> ParseResult<Option<Ipv4Addr>> {
363379
return Ok(None);
364380
}
365381
let mut numbers: Vec<u32> = Vec::new();
382+
let mut overflow = false;
366383
for part in parts {
367384
if part == "" {
368385
return Ok(None);
369386
}
370-
if let Ok(n) = parse_ipv4number(part) {
371-
numbers.push(n);
372-
} else {
373-
return Ok(None);
374-
}
387+
match parse_ipv4number(part) {
388+
Ok(Some(n)) => numbers.push(n),
389+
Ok(None) => return Ok(None),
390+
Err(()) => overflow = true
391+
};
392+
}
393+
if overflow {
394+
return Err(ParseError::InvalidIpv4Address);
375395
}
376396
let mut ipv4 = numbers.pop().expect("a non-empty list of numbers");
377397
// Equivalent to: ipv4 >= 256 ** (4 − numbers.len())

tests/urltestdata.json

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4843,6 +4843,11 @@
48434843
"search": "",
48444844
"hash": ""
48454845
},
4846+
{
4847+
"input": "http://10000000000",
4848+
"base": "http://other.com/",
4849+
"failure": true
4850+
},
48464851
{
48474852
"input": "http://10000000000.com",
48484853
"base": "http://other.com/",
@@ -4873,6 +4878,11 @@
48734878
"search": "",
48744879
"hash": ""
48754880
},
4881+
{
4882+
"input": "http://4294967296",
4883+
"base": "http://other.com/",
4884+
"failure": true
4885+
},
48764886
{
48774887
"input": "http://0xffffffff",
48784888
"base": "http://other.com/",
@@ -4888,6 +4898,11 @@
48884898
"search": "",
48894899
"hash": ""
48904900
},
4901+
{
4902+
"input": "http://0xffffffff1",
4903+
"base": "http://other.com/",
4904+
"failure": true
4905+
},
48914906
{
48924907
"input": "http://256.256.256.256",
48934908
"base": "http://other.com/",

0 commit comments

Comments
 (0)