fix: do not URL-encode proxy hostnames

This commit is contained in:
link2xt
2026-03-31 16:11:52 +02:00
parent 24b21c0588
commit 4a5370ea56
2 changed files with 72 additions and 7 deletions

View File

@@ -19,7 +19,6 @@ use tokio_io_timeout::TimeoutStream;
use url::Url;
use crate::config::Config;
use crate::constants::NON_ALPHANUMERIC_WITHOUT_DOT;
use crate::context::Context;
use crate::net::connect_tcp;
use crate::net::session::SessionStream;
@@ -93,13 +92,12 @@ impl HttpConfig {
}
fn to_url(&self, scheme: &str) -> String {
let host = utf8_percent_encode(&self.host, NON_ALPHANUMERIC_WITHOUT_DOT);
if let Some((user, password)) = &self.user_password {
let user = utf8_percent_encode(user, NON_ALPHANUMERIC);
let password = utf8_percent_encode(password, NON_ALPHANUMERIC);
format!("{scheme}://{user}:{password}@{host}:{}", self.port)
format!("{scheme}://{user}:{password}@{}:{}", self.host, self.port)
} else {
format!("{scheme}://{host}:{}", self.port)
format!("{scheme}://{}:{}", self.host, self.port)
}
}
}
@@ -143,13 +141,12 @@ impl Socks5Config {
}
fn to_url(&self) -> String {
let host = utf8_percent_encode(&self.host, NON_ALPHANUMERIC_WITHOUT_DOT);
if let Some((user, password)) = &self.user_password {
let user = utf8_percent_encode(user, NON_ALPHANUMERIC);
let password = utf8_percent_encode(password, NON_ALPHANUMERIC);
format!("socks5://{user}:{password}@{host}:{}", self.port)
format!("socks5://{user}:{password}@{}:{}", self.host, self.port)
} else {
format!("socks5://{host}:{}", self.port)
format!("socks5://{}:{}", self.host, self.port)
}
}
}
@@ -565,6 +562,20 @@ mod tests {
user_password: None
})
);
let proxy_config = ProxyConfig::from_url("socks5://my-proxy.example.org").unwrap();
assert_eq!(
proxy_config,
ProxyConfig::Socks5(Socks5Config {
host: "my-proxy.example.org".to_string(),
port: 1080,
user_password: None
})
);
assert_eq!(
proxy_config.to_url(),
"socks5://my-proxy.example.org:1080".to_string()
);
}
#[test]
@@ -598,6 +609,20 @@ mod tests {
user_password: None
})
);
let proxy_config = ProxyConfig::from_url("http://my-proxy.example.org").unwrap();
assert_eq!(
proxy_config,
ProxyConfig::Http(HttpConfig {
host: "my-proxy.example.org".to_string(),
port: 80,
user_password: None
})
);
assert_eq!(
proxy_config.to_url(),
"http://my-proxy.example.org:80".to_string()
);
}
#[test]
@@ -631,6 +656,20 @@ mod tests {
user_password: None
})
);
let proxy_config = ProxyConfig::from_url("https://my-proxy.example.org").unwrap();
assert_eq!(
proxy_config,
ProxyConfig::Https(HttpConfig {
host: "my-proxy.example.org".to_string(),
port: 443,
user_password: None
})
);
assert_eq!(
proxy_config.to_url(),
"https://my-proxy.example.org:443".to_string()
);
}
#[test]

View File

@@ -892,6 +892,32 @@ async fn test_set_proxy_config_from_qr() -> Result<()> {
Ok(())
}
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_dont_encode_hyphen_in_proxy_hostnames() -> Result<()> {
let mut tcm = TestContextManager::new();
let t = &tcm.alice().await;
let qr_text = "socks5://my-proxy.example.org";
let qr = check_qr(t, qr_text).await?;
assert_eq!(
qr,
Qr::Proxy {
url: "socks5://my-proxy.example.org".to_string(),
host: "my-proxy.example.org".to_string(),
port: 1080,
}
);
set_config_from_qr(t, "socks5://my-proxy.example.org").await?;
assert_eq!(
t.get_config(Config::ProxyUrl).await?,
Some("socks5://my-proxy.example.org:1080".to_string())
);
Ok(())
}
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_decode_shadowsocks() -> Result<()> {
let ctx = TestContext::new().await;