URL: changes on host(name) setter, introduce clean_hostname_input

This commit is contained in:
Halil Durak
2026-06-22 13:09:23 +03:00
committed by nikneym
parent 0c4f6f0d87
commit 7d5553238e

View File

@@ -335,17 +335,40 @@ pub unsafe extern "C" fn url_get_port(url: *const Url) -> i32 {
}
}
fn clean_hostname_input(url: &Url, raw: &str) -> String {
let special = matches!(
url.scheme(),
"http" | "https" | "ws" | "wss" | "ftp" | "file"
);
let mut out = String::with_capacity(raw.len());
let mut in_brackets = false;
for c in raw.chars() {
match c {
'\t' | '\n' | '\r' => continue,
'[' => in_brackets = true,
']' => in_brackets = false,
'/' | '?' | '#' => break,
'\\' if special => break,
':' if !in_brackets => break,
_ => {}
}
out.push(c);
}
out
}
/// WHATWG `hostname` setter: sets the host without touching the port.
#[no_mangle]
pub unsafe extern "C" fn url_set_hostname(url: *mut Url, ptr: *const c_uchar, len: usize) -> i32 {
let url = unsafe { &mut *url };
let slice = match str_from(ptr, len) {
let raw = match str_from(ptr, len) {
Some(s) => s,
None => return -1,
};
let host = clean_hostname_input(url, raw);
match url.set_host(Some(slice)) {
match url.set_host(Some(host.as_str())) {
Ok(()) => 0,
Err(_) => -1,
}
@@ -406,6 +429,18 @@ pub unsafe extern "C" fn url_set_host(url: *mut Url, ptr: *const c_uchar, len: u
None => return -1,
};
// The WHATWG host setter parses in "host state", which stops at the first
// '/', '?', '#' (and '\' for special schemes); the remainder is ignored
// rather than making the whole value invalid.
let special = matches!(
url.scheme(),
"http" | "https" | "ws" | "wss" | "ftp" | "file"
);
let end = input
.find(|c| c == '/' || c == '?' || c == '#' || (special && c == '\\'))
.unwrap_or(input.len());
let input = &input[..end];
// Find the port separator ':', but only outside an IPv6 [...] literal.
let colon = if input.starts_with('[') {
input
@@ -430,7 +465,11 @@ pub unsafe extern "C" fn url_set_host(url: *mut Url, ptr: *const c_uchar, len: u
// the WHATWG host setter ignores: set the host only, leaving any existing
// port untouched (matches Chrome and Firefox).
if port_str.is_empty() {
return if url.set_host(Some(host)).is_ok() { 0 } else { -1 };
return if url.set_host(Some(host)).is_ok() {
0
} else {
-1
};
}
// Validate the port up-front so we never apply the host and then fail.