From ae97094f215b757a9e80d6b4463cd670bfcb5860 Mon Sep 17 00:00:00 2001 From: Dan Johnson Date: Thu, 5 Sep 2019 13:21:45 -0700 Subject: [PATCH 1/2] Allow % in IPv6 addresses to support zone identifiers. https://tools.ietf.org/html/rfc6874 explains that %25 can be used to indicate a "zone identifier", useful for IPv6 link-local addresses. --- src/uri/authority.rs | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/uri/authority.rs b/src/uri/authority.rs index 724712cc..7088b8c6 100644 --- a/src/uri/authority.rs +++ b/src/uri/authority.rs @@ -103,15 +103,20 @@ impl Authority { } b':' => { colon_cnt += 1; - }, + } b'[' => { start_bracket = true; + if has_percent { + // Something other than the userinfo has a `%`, so reject it. + return Err(ErrorKind::InvalidAuthority.into()); + } } b']' => { end_bracket = true; // Those were part of an IPv6 hostname, so forget them... colon_cnt = 0; + has_percent = false; } b'@' => { at_sign_pos = Some(i); @@ -127,8 +132,11 @@ impl Authority { // the userinfo can have a percent-encoded username and password, // so record that a `%` was found. If this turns out to be // part of the userinfo, this flag will be cleared. + // Also per https://tools.ietf.org/html/rfc6874, percent-encoding can + // be used to indicate a zone identifier. // If the flag hasn't been cleared at the end, that means this - // was part of the hostname, and will fail with an error. + // was part of the hostname (and not part of an IPv6 address), and + // will fail with an error. has_percent = true; } 0 => { @@ -612,4 +620,11 @@ mod tests { let err = Authority::parse_non_empty(b"a%2f:b%2f@example%2f.com").unwrap_err(); assert_eq!(err.0, ErrorKind::InvalidAuthority); } + + #[test] + fn allows_percent_in_ipv6_address() { + let authority_str = "[fe80::1:2:3:4%25eth0]"; + let result: Authority = authority_str.parse().unwrap(); + assert_eq!(result, authority_str); + } } From d674788393af80d26c954aaeb600c2e3f37c753f Mon Sep 17 00:00:00 2001 From: Dan Johnson Date: Fri, 13 Sep 2019 10:28:39 -0700 Subject: [PATCH 2/2] Add test case for % outside of IPv6 address --- src/uri/authority.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/uri/authority.rs b/src/uri/authority.rs index 7088b8c6..0564f2b5 100644 --- a/src/uri/authority.rs +++ b/src/uri/authority.rs @@ -627,4 +627,13 @@ mod tests { let result: Authority = authority_str.parse().unwrap(); assert_eq!(result, authority_str); } + + #[test] + fn rejects_percent_outside_ipv6_address() { + let err = Authority::parse_non_empty(b"1234%20[fe80::1:2:3:4]").unwrap_err(); + assert_eq!(err.0, ErrorKind::InvalidAuthority); + + let err = Authority::parse_non_empty(b"[fe80::1:2:3:4]%20").unwrap_err(); + assert_eq!(err.0, ErrorKind::InvalidAuthority); + } }