diff --git a/Cargo.lock b/Cargo.lock index 4d5e297..7792d0b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -623,6 +623,7 @@ dependencies = [ "rand 0.8.4", "redis", "tokio", + "url", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index bae0e41..395b817 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,6 +19,7 @@ rand = { version = "0.8", default-features = false, features = ["std", "std_rng" redis = { version = "0.21", features = ["tokio-comp"] } tokio = { version = "1", features = ["time"] } log = "0.4" +url = "2.2.2" [dev-dependencies] anyhow = "1" diff --git a/src/lib.rs b/src/lib.rs index 3d7d9a2..1c77fff 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -475,26 +475,41 @@ where let connections = stream::iter(initial_nodes.iter().cloned()) .map(|info| async move { let addr = match info.addr { - ConnectionAddr::Tcp(ref host, port) => match &info.redis.password { - Some(pw) => format!("redis://:{}@{}:{}", pw, host, port), - None => format!("redis://{}:{}", host, port), - }, - ConnectionAddr::TcpTls { ref host, port, insecure } => match &info.redis.password { - Some(pw) if insecure => format!("rediss://:{}@{}:{}/#insecure", pw, host, port), - Some(pw) => format!("rediss://:{}@{}:{}", pw, host, port), - None if insecure => format!("rediss://{}:{}/#insecure", host, port), - None => format!("rediss://{}:{}", host, port), - }, + ConnectionAddr::Tcp(ref host, port) => { + let addr = format!("redis://{}:{}", host, port); + match &info.redis.password { + Some(password) => set_password(addr, password), + None => Some(addr), + } + } + ConnectionAddr::TcpTls { + ref host, + port, + insecure, + } => { + let addr = if insecure { + format!("rediss://{}:{}", host, port) + } else { + format!("rediss://{}:{}/#insecure", host, port) + }; + match &info.redis.password { + Some(password) => set_password(addr, password), + None => Some(addr), + } + } _ => panic!("No reach."), }; - let result = connect_and_check(info).await; - match result { - Ok(conn) => Some((addr, async { conn }.boxed().shared())), - Err(e) => { + match (connect_and_check(info).await, addr) { + (Ok(conn), Some(addr)) => Some((addr, async { conn }.boxed().shared())), + (Err(e), _) => { trace!("Failed to connect to initial node: {:?}", e); None - }, + } + (Ok(_), None) => { + trace!("Failed to parse addr, info addr"); + None + } } }) .buffer_unordered(initial_nodes.len()) @@ -1138,9 +1153,10 @@ where return None; }; let scheme = if use_tls { "rediss" } else { "redis" }; + let addr = format!("{}://{}:{}", scheme, ip, port); match &password { - Some(pw) => Some(format!("{}://:{}@{}:{}", scheme, pw, ip, port)), - None => Some(format!("{}://{}:{}", scheme, ip, port)), + Some(pw) => set_password(addr, pw), + None => Some(addr), } } else { None @@ -1169,6 +1185,15 @@ fn get_password(addr: &str) -> Option { redis::parse_redis_url(addr).and_then(|url| url.password().map(|s| s.into())) } +fn set_password(addr: String, password: &str) -> Option { + if let Ok(mut url) = url::Url::parse(&addr) { + if url.set_password(Some(password)).is_ok() { + return Some(url.to_string()); + } + } + None +} + #[cfg(test)] mod tests { use super::*;