From 12296aeb4d91ab477fa3817e246fdf237211c1cb Mon Sep 17 00:00:00 2001 From: xu-kai-quan <50357378+xu-kai-quan@users.noreply.github.com> Date: Mon, 7 Sep 2026 15:54:27 +0800 Subject: [PATCH] fix(proxy): stop mask_url panicking on multi-byte UTF-8 near the truncation boundary mask_url's fallback branch (used when the proxy URL fails Url::parse) sliced the raw string at byte 20 and panicked when a multi-byte UTF-8 character straddled that offset, e.g. a CJK string pasted into the global proxy address. Snap the cut to the nearest char boundary at or before 20 and add a regression test. --- src-tauri/src/proxy/http_client.rs | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src-tauri/src/proxy/http_client.rs b/src-tauri/src/proxy/http_client.rs index 97e927e46..de697d4e7 100644 --- a/src-tauri/src/proxy/http_client.rs +++ b/src-tauri/src/proxy/http_client.rs @@ -325,9 +325,14 @@ pub fn mask_url(url: &str) -> String { None => format!("{}://{}", parsed.scheme(), host), } } else { - // URL 解析失败,返回部分内容 + // URL 解析失败,返回部分内容。截断点回退到最近的字符边界, + // 避免在多字节 UTF-8 字符中间切割导致 panic。 if url.len() > 20 { - format!("{}...", &url[..20]) + let cut = (0..=20) + .rev() + .find(|&i| url.is_char_boundary(i)) + .unwrap_or(0); + format!("{}...", &url[..cut]) } else { url.to_string() } @@ -366,6 +371,16 @@ mod tests { ); } + #[test] + fn test_mask_url_does_not_panic_on_multibyte_boundary() { + // 一个无法被 Url::parse 解析、且在字节 20 处正好切在多字节字符中间的字符串。 + // 回归 https://github.com/farion1231/cc-switch 的 mask_url 越界 panic。 + let bad = "这是一个无效的代理地址不能解析"; + assert!(bad.len() > 20 && !bad.is_char_boundary(20)); + let masked = mask_url(bad); + assert!(masked.ends_with("...")); + } + #[test] fn test_build_client_direct() { let result = build_client(None);