Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow the percent character in the userinfo of an authority. #269

Merged
merged 2 commits into from Oct 30, 2018
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
34 changes: 33 additions & 1 deletion src/uri/authority.rs
Expand Up @@ -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;

Expand Down Expand Up @@ -118,7 +119,17 @@ 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'%' => {
// 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 will fail with an error.
has_percent = true;
}
0 => {
return Err(ErrorKind::InvalidUriChar.into());
Expand All @@ -141,6 +152,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)
}

Expand Down Expand Up @@ -564,4 +580,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);
}
}