Skip to content

Commit 17f3d20

Browse files
committed
Host checks.
1 parent ec23e7c commit 17f3d20

File tree

2 files changed

+35
-10
lines changed

2 files changed

+35
-10
lines changed

src/parser.rs

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ macro_rules! simple_enum_error {
7979

8080
simple_enum_error! {
8181
EmptyHost => "empty host",
82+
InvalidAuthority => "invalid authority",
8283
IdnaError => "invalid international domain name",
8384
InvalidPort => "invalid port number",
8485
InvalidIpv4Address => "invalid IPv4 address",
@@ -840,11 +841,13 @@ impl<'a> Parser<'a> {
840841
self.serialization.push('/');
841842
self.serialization.push('/');
842843
// authority state
844+
let before_authority = self.serialization.len();
843845
let (username_end, remaining) = self.parse_userinfo(input, scheme_type)?;
846+
let has_authority = before_authority != self.serialization.len();
844847
// host state
845848
let host_start = to_u32(self.serialization.len())?;
846849
let (host_end, host, port, remaining) =
847-
self.parse_host_and_port(remaining, scheme_end, scheme_type)?;
850+
self.parse_host_and_port(remaining, scheme_end, scheme_type, has_authority)?;
848851
// path state
849852
let path_start = to_u32(self.serialization.len())?;
850853
let remaining = self.parse_path_start(scheme_type, &mut true, remaining);
@@ -888,7 +891,18 @@ impl<'a> Parser<'a> {
888891
}
889892
let (mut userinfo_char_count, remaining) = match last_at {
890893
None => return Ok((to_u32(self.serialization.len())?, input)),
891-
Some((0, remaining)) => return Ok((to_u32(self.serialization.len())?, remaining)),
894+
Some((0, remaining)) => {
895+
// Otherwise, if one of the following is true
896+
// c is the EOF code point, U+002F (/), U+003F (?), or U+0023 (#)
897+
// url is special and c is U+005C (\)
898+
// If @ flag is set and buffer is the empty string, validation error, return failure.
899+
if let (Some(c), _) = remaining.split_first() {
900+
if c == '/' || c == '?' || c == '#' || scheme_type.is_special() && c == '\\' {
901+
return Err(ParseError::InvalidAuthority);
902+
}
903+
}
904+
return Ok((to_u32(self.serialization.len())?, remaining));
905+
}
892906
Some(x) => x,
893907
};
894908

@@ -930,18 +944,26 @@ impl<'a> Parser<'a> {
930944
input: Input<'i>,
931945
scheme_end: u32,
932946
scheme_type: SchemeType,
947+
has_authority: bool,
933948
) -> ParseResult<(u32, HostInternal, Option<u16>, Input<'i>)> {
934949
let (host, remaining) = Parser::parse_host(input, scheme_type)?;
935950
write!(&mut self.serialization, "{}", host).unwrap();
936951
let host_end = to_u32(self.serialization.len())?;
937-
if remaining.starts_with(":") {
938-
// Port with an empty host
939-
if let Host::Domain(h) = &host {
940-
if h.is_empty() {
952+
if let Host::Domain(h) = &host {
953+
if h.is_empty() {
954+
// Port with an empty host
955+
if remaining.starts_with(":") {
956+
return Err(ParseError::EmptyHost);
957+
}
958+
if scheme_type.is_special() {
959+
return Err(ParseError::EmptyHost);
960+
}
961+
if !scheme_type.is_special() && has_authority {
941962
return Err(ParseError::EmptyHost);
942963
}
943964
}
944-
}
965+
};
966+
945967
let (port, remaining) = if let Some(remaining) = remaining.split_prefix(':') {
946968
let scheme = || default_port(&self.serialization[..scheme_end as usize]);
947969
Parser::parse_port(remaining, scheme, self.context)?
@@ -1010,7 +1032,10 @@ impl<'a> Parser<'a> {
10101032

10111033
pub fn get_file_host<'i>(input: Input<'i>) -> ParseResult<(Host<String>, Input)> {
10121034
let (_, host_str, remaining) = Parser::file_host(input)?;
1013-
let host = Host::parse(&host_str)?;
1035+
let host = match Host::parse(&host_str)? {
1036+
Host::Domain(ref d) if d == "localhost" => Host::Domain("".to_string()),
1037+
host => host,
1038+
};
10141039
Ok((host, remaining))
10151040
}
10161041

src/quirks.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -177,8 +177,8 @@ pub fn set_hostname(url: &mut Url, new_hostname: &str) -> Result<(), ()> {
177177
if let Ok((host, _remaining)) = result {
178178
if let Host::Domain(h) = &host {
179179
if h.is_empty() {
180-
// Empty host on special url
181-
if SchemeType::from(url.scheme()).is_special()
180+
// Empty host on special not file url
181+
if SchemeType::from(url.scheme()) == SchemeType::SpecialNotFile
182182
// Port with an empty host
183183
||!port(&url).is_empty()
184184
// Empty host with includes credentials

0 commit comments

Comments
 (0)