From e614de83fc616d7a093c9e24acb016963cef1e1c Mon Sep 17 00:00:00 2001 From: Leo Camus Date: Thu, 15 Oct 2026 04:30:06 +0200 Subject: [PATCH] fix: read host= from an exe path with non-ASCII characters (#16556) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit get_custom_server_from_string located "host=" in s.to_lowercase() and sliced s with that byte index. Lowercasing can change a character's byte length ("İ" is 2 bytes, "i̇" is 3), and on Windows the string is the full exe path, so a profile such as C:\Users\İsmail shifted the slice past the "h" and host came back empty. The client then fell back to the default rendezvous server. "host=" is ASCII, so search s.to_ascii_lowercase(), which keeps byte offsets. --- src/custom_server.rs | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/custom_server.rs b/src/custom_server.rs index 3a7d60fe9..44e80658c 100644 --- a/src/custom_server.rs +++ b/src/custom_server.rs @@ -62,7 +62,7 @@ pub fn get_custom_server_from_string(s: &str) -> ResultType { * This allows using a ',' (comma) symbol as a final delimiter. */ if s.to_lowercase().contains("host=") { - let stripped = &s[s.to_lowercase().find("host=").unwrap_or(0)..s.len()]; + let stripped = &s[s.to_ascii_lowercase().find("host=").unwrap_or(0)..s.len()]; let strs: Vec<&str> = stripped.split(",").collect(); let mut host = String::default(); let mut key = String::default(); @@ -232,4 +232,21 @@ mod test { get_custom_server_from_string("=0nI900VsFHZVBVdIlncwpHS4V0bOZ0dtVldrpVO4JHdCp0YV5WdzUGZzdnYRVjI6ISeltmIsISMuEjLx4SMiojI0N3boJye.exe") .unwrap(), lic); } + + #[test] + fn test_filename_license_string_in_non_ascii_path() { + // Windows passes the full exe path, and `İ` grows from 2 to 3 bytes when lowercased. + assert_eq!( + get_custom_server_from_string( + r"C:\Users\İsmail\Downloads\rustdesk-host=server.example.net,key=Zm9vYmFyLiwyCg==.exe" + ) + .unwrap(), + CustomServer { + host: "server.example.net".to_owned(), + key: "Zm9vYmFyLiwyCg==".to_owned(), + api: "".to_owned(), + relay: "".to_owned(), + } + ); + } }