From 8d0d405ac5ef8f23bd6a51a0843dd63a1402cbfe Mon Sep 17 00:00:00 2001 From: Arnav Singh Date: Mon, 29 Oct 2018 15:37:34 -0700 Subject: [PATCH 1/2] Allow the percent character in the userinfo of an authority. The username and password in an authority are percent-encoded. --- src/uri/authority.rs | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/src/uri/authority.rs b/src/uri/authority.rs index 0e94b717..c09797f3 100644 --- a/src/uri/authority.rs +++ b/src/uri/authority.rs @@ -91,6 +91,7 @@ impl Authority { let mut colon_cnt = 0; let mut start_bracket = false; let mut end_bracket = false; + let mut has_percent = false; let mut end = s.len(); let mut at_sign_pos = None; @@ -118,7 +119,15 @@ impl Authority { // Those weren't a port colon, but part of the // userinfo, so it needs to be forgotten. colon_cnt = 0; - + has_percent = false; + } + 0 if b == b'%' => { + // Userinfo can have 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. + // If the flag hasn't been cleared at the end, that means this + // was part of the hostname, and fail with an error. + has_percent = true; } 0 => { return Err(ErrorKind::InvalidUriChar.into()); @@ -141,6 +150,11 @@ impl Authority { return Err(ErrorKind::InvalidAuthority.into()); } + if has_percent { + // Something after the userinfo has a `%`, so reject it. + return Err(ErrorKind::InvalidAuthority.into()); + } + Ok(end) } @@ -564,4 +578,20 @@ mod tests { assert!(authority > "abc.com".to_string()); assert!("abc.com".to_string() < authority); } + + #[test] + fn allows_percent_in_userinfo() { + let authority_str = "a%2f:b%2f@example.com"; + let authority: Authority = authority_str.parse().unwrap(); + assert_eq!(authority, authority_str); + } + + #[test] + fn rejects_percent_in_hostname() { + let err = Authority::parse_non_empty(b"example%2f.com").unwrap_err(); + assert_eq!(err.0, ErrorKind::InvalidAuthority); + + let err = Authority::parse_non_empty(b"a%2f:b%2f@example%2f.com").unwrap_err(); + assert_eq!(err.0, ErrorKind::InvalidAuthority); + } } From 6ac4229de31f3cd89299612ae4ec9f5183482270 Mon Sep 17 00:00:00 2001 From: Arnav Singh Date: Tue, 30 Oct 2018 11:26:32 -0700 Subject: [PATCH 2/2] Add spec references. --- src/uri/authority.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/uri/authority.rs b/src/uri/authority.rs index c09797f3..4782285e 100644 --- a/src/uri/authority.rs +++ b/src/uri/authority.rs @@ -122,11 +122,13 @@ impl Authority { has_percent = false; } 0 if b == b'%' => { - // Userinfo can have percent-encoded username and password, + // Per https://tools.ietf.org/html/rfc3986#section-3.2.1 and + // https://url.spec.whatwg.org/#authority-state + // 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. // If the flag hasn't been cleared at the end, that means this - // was part of the hostname, and fail with an error. + // was part of the hostname, and will fail with an error. has_percent = true; } 0 => {