diff --git a/src/lib.rs b/src/lib.rs index cd6bdf326..5d752e558 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1569,10 +1569,25 @@ impl Url { if host == "" && SchemeType::from(self.scheme()).is_special() { return Err(ParseError::EmptyHost); } + let mut host_substr = host; + // Otherwise, if c is U+003A (:) and the [] flag is unset, then + if !host.starts_with('[') || !host.ends_with(']') { + match host.find(':') { + Some(0) => { + // If buffer is the empty string, validation error, return failure. + return Err(ParseError::InvalidDomainCharacter); + } + // Let host be the result of host parsing buffer + Some(colon_index) => { + host_substr = &host[..colon_index]; + } + None => {} + } + } if SchemeType::from(self.scheme()).is_special() { - self.set_host_internal(Host::parse(host)?, None) + self.set_host_internal(Host::parse(host_substr)?, None); } else { - self.set_host_internal(Host::parse_opaque(host)?, None) + self.set_host_internal(Host::parse_opaque(host_substr)?, None); } } else if self.has_host() { if SchemeType::from(self.scheme()).is_special() { @@ -1954,6 +1969,13 @@ impl Url { parser.serialization.push_str(self.slice(old_scheme_end..)); self.serialization = parser.serialization; + + // Update the port so it can be removed + // If it is the scheme's default + // We don't mind it silently failing + // If there was no port in the first place + let _ = self.set_port(self.port()); + Ok(()) } diff --git a/src/quirks.rs b/src/quirks.rs index 285ee21b6..8684bed6f 100644 --- a/src/quirks.rs +++ b/src/quirks.rs @@ -111,9 +111,13 @@ pub fn set_host(url: &mut Url, new_host: &str) -> Result<(), ()> { Ok((h, remaining)) => { host = h; opt_port = if let Some(remaining) = remaining.split_prefix(':') { - Parser::parse_port(remaining, || default_port(scheme), Context::Setter) - .ok() - .map(|(port, _remaining)| port) + if remaining.is_empty() { + None + } else { + Parser::parse_port(remaining, || default_port(scheme), Context::Setter) + .ok() + .map(|(port, _remaining)| port) + } } else { None }; @@ -208,13 +212,14 @@ pub fn hash(url: &Url) -> &str { /// Setter for https://url.spec.whatwg.org/#dom-url-hash pub fn set_hash(url: &mut Url, new_hash: &str) { - if url.scheme() != "javascript" { - url.set_fragment(match new_hash { - "" => None, - _ if new_hash.starts_with('#') => Some(&new_hash[1..]), - _ => Some(new_hash), - }) - } + url.set_fragment(match new_hash { + // If the given value is the empty string, + // then set context object’s url’s fragment to null and return. + "" => None, + // Let input be the given value with a single leading U+0023 (#) removed, if any. + _ if new_hash.starts_with('#') => Some(&new_hash[1..]), + _ => Some(new_hash), + }) } fn trim(s: &str) -> &str {