From a8e51cc6bb5e0a0a85f1b61188ec79c2a8c5666e Mon Sep 17 00:00:00 2001
From: Tunglies <77394545+Tunglies@users.noreply.github.com>
Date: Tue, 3 Feb 2026 10:26:50 +0800
Subject: [PATCH] fix: improve subscription URL handling by fixing query
parameter parsing
---
Changelog.md | 1 +
src-tauri/src/config/prfitem.rs | 48 ++++++++++++++++++++++++++++++---
2 files changed, 46 insertions(+), 3 deletions(-)
diff --git a/Changelog.md b/Changelog.md
index be9924a9f..286606bab 100644
--- a/Changelog.md
+++ b/Changelog.md
@@ -21,5 +21,6 @@
🚀 优化改进
- 安装服务失败时报告更详细的错误
+- 避免脏订阅地址无法 Scheme 导入订阅
diff --git a/src-tauri/src/config/prfitem.rs b/src-tauri/src/config/prfitem.rs
index 24dc7eb77..4190e5930 100644
--- a/src-tauri/src/config/prfitem.rs
+++ b/src-tauri/src/config/prfitem.rs
@@ -12,6 +12,9 @@ use serde_yaml_ng::Mapping;
use smartstring::alias::String;
use std::time::Duration;
use tokio::fs;
+// TODO, use other re-export
+use reqwest_dav::re_exports::url::form_urlencoded;
+use tauri::Url;
#[derive(Debug, Clone, Deserialize, Serialize, Default)]
pub struct PrfItem {
@@ -278,9 +281,17 @@ impl PrfItem {
ProxyType::None
};
+ let url = fix_dirty_url(url)?;
+
// 使用网络管理器发送请求
let resp = match NetworkManager::new()
- .get_with_interrupt(url, proxy_type, Some(timeout), user_agent.clone(), accept_invalid_certs)
+ .get_with_interrupt(
+ url.as_str(),
+ proxy_type,
+ Some(timeout),
+ user_agent.clone(),
+ accept_invalid_certs,
+ )
.await
{
Ok(r) => r,
@@ -340,7 +351,9 @@ impl PrfItem {
},
}
}
- None => Some(crate::utils::help::get_last_part_and_decode(url).unwrap_or_else(|| "Remote File".into())),
+ None => {
+ Some(crate::utils::help::get_last_part_and_decode(url.as_str()).unwrap_or_else(|| "Remote File".into()))
+ }
};
let update_interval = match update_interval {
Some(val) => Some(val),
@@ -410,7 +423,7 @@ impl PrfItem {
name: Some(name),
desc: desc.cloned(),
file: Some(file),
- url: Some(url.into()),
+ url: Some(url.as_str().into()),
selected: None,
extra,
option: Some(PrfOption {
@@ -569,3 +582,32 @@ impl PrfItem {
const fn default_allow_auto_update() -> Option {
Some(true)
}
+
+/// Fix URLs where query parameters are incorrectly appended to the path segment
+///
+/// Incorrect Example: https://example.com/path¶m1=value1
+fn fix_dirty_url(input: &str) -> Result {
+ let mut url = match Url::parse(input) {
+ Ok(u) => u,
+ Err(e) => {
+ return Err(anyhow::anyhow!(
+ "failed to parse deep link url: {:?}, input: {:?}",
+ e,
+ input
+ ));
+ }
+ };
+
+ if url.query().is_none() && url.path().contains('&') {
+ let path = url.path().to_string();
+
+ if let Some((clean_path, dirty_params)) = path.split_once('&') {
+ url.set_path(clean_path);
+
+ url.query_pairs_mut()
+ .extend_pairs(form_urlencoded::parse(dirty_params.as_bytes()));
+ }
+ }
+
+ Ok(url)
+}