mirror of
https://github.com/rustfs/rustfs.git
synced 2026-08-31 17:28:12 +00:00
fix: decode percent-encoded paths in get_file_path() (#1072)
Co-authored-by: houseme <housemecn@gmail.com> Co-authored-by: loverustfs <hello@rustfs.com>
This commit is contained in:
@@ -198,15 +198,22 @@ impl Endpoint {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_file_path(&self) -> &str {
|
pub fn get_file_path(&self) -> String {
|
||||||
let path = self.url.path();
|
let path: &str = self.url.path();
|
||||||
|
let decoded: std::borrow::Cow<'_, str> = match urlencoding::decode(path) {
|
||||||
|
Ok(decoded) => decoded,
|
||||||
|
Err(e) => {
|
||||||
|
debug!("Failed to decode path '{}': {}, using original path", path, e);
|
||||||
|
std::borrow::Cow::Borrowed(path)
|
||||||
|
}
|
||||||
|
};
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
if self.url.scheme() == "file" {
|
if self.url.scheme() == "file" {
|
||||||
let stripped = path.strip_prefix('/').unwrap_or(path);
|
let stripped: &str = decoded.strip_prefix('/').unwrap_or(&decoded);
|
||||||
debug!("get_file_path windows: path={}", stripped);
|
debug!("get_file_path windows: path={}", stripped);
|
||||||
return stripped;
|
return stripped.to_string();
|
||||||
}
|
}
|
||||||
path
|
decoded.into_owned()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -501,6 +508,45 @@ mod test {
|
|||||||
assert_eq!(endpoint.get_type(), EndpointType::Path);
|
assert_eq!(endpoint.get_type(), EndpointType::Path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_endpoint_with_spaces_in_path() {
|
||||||
|
let path_with_spaces = "/Users/test/Library/Application Support/rustfs/data";
|
||||||
|
let endpoint = Endpoint::try_from(path_with_spaces).unwrap();
|
||||||
|
assert_eq!(endpoint.get_file_path(), path_with_spaces);
|
||||||
|
assert!(endpoint.is_local);
|
||||||
|
assert_eq!(endpoint.get_type(), EndpointType::Path);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_endpoint_percent_encoding_roundtrip() {
|
||||||
|
let path_with_spaces = "/Users/test/Library/Application Support/rustfs/data";
|
||||||
|
let endpoint = Endpoint::try_from(path_with_spaces).unwrap();
|
||||||
|
|
||||||
|
// Verify that the URL internally stores percent-encoded path
|
||||||
|
assert!(
|
||||||
|
endpoint.url.path().contains("%20"),
|
||||||
|
"URL path should contain percent-encoded spaces: {}",
|
||||||
|
endpoint.url.path()
|
||||||
|
);
|
||||||
|
|
||||||
|
// Verify that get_file_path() decodes the percent-encoded path correctly
|
||||||
|
assert_eq!(
|
||||||
|
endpoint.get_file_path(),
|
||||||
|
"/Users/test/Library/Application Support/rustfs/data",
|
||||||
|
"get_file_path() should decode percent-encoded spaces"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_endpoint_with_various_special_characters() {
|
||||||
|
// Test path with multiple special characters that get percent-encoded
|
||||||
|
let path_with_special = "/tmp/test path/data[1]/file+name&more";
|
||||||
|
let endpoint = Endpoint::try_from(path_with_special).unwrap();
|
||||||
|
|
||||||
|
// get_file_path() should return the original path with decoded characters
|
||||||
|
assert_eq!(endpoint.get_file_path(), path_with_special);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_endpoint_update_is_local() {
|
fn test_endpoint_update_is_local() {
|
||||||
let mut endpoint = Endpoint::try_from("http://localhost:9000/path").unwrap();
|
let mut endpoint = Endpoint::try_from("http://localhost:9000/path").unwrap();
|
||||||
|
|||||||
@@ -232,7 +232,7 @@ impl PoolEndpointList {
|
|||||||
|
|
||||||
for endpoints in pool_endpoint_list.inner.iter_mut() {
|
for endpoints in pool_endpoint_list.inner.iter_mut() {
|
||||||
// Check whether same path is not used in endpoints of a host on different port.
|
// Check whether same path is not used in endpoints of a host on different port.
|
||||||
let mut path_ip_map: HashMap<&str, HashSet<IpAddr>> = HashMap::new();
|
let mut path_ip_map: HashMap<String, HashSet<IpAddr>> = HashMap::new();
|
||||||
let mut host_ip_cache = HashMap::new();
|
let mut host_ip_cache = HashMap::new();
|
||||||
for ep in endpoints.as_ref() {
|
for ep in endpoints.as_ref() {
|
||||||
if !ep.url.has_host() {
|
if !ep.url.has_host() {
|
||||||
@@ -275,8 +275,9 @@ impl PoolEndpointList {
|
|||||||
match path_ip_map.entry(path) {
|
match path_ip_map.entry(path) {
|
||||||
Entry::Occupied(mut e) => {
|
Entry::Occupied(mut e) => {
|
||||||
if e.get().intersection(host_ip_set).count() > 0 {
|
if e.get().intersection(host_ip_set).count() > 0 {
|
||||||
|
let path_key = e.key().clone();
|
||||||
return Err(Error::other(format!(
|
return Err(Error::other(format!(
|
||||||
"same path '{path}' can not be served by different port on same address"
|
"same path '{path_key}' can not be served by different port on same address"
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
e.get_mut().extend(host_ip_set.iter());
|
e.get_mut().extend(host_ip_set.iter());
|
||||||
@@ -295,7 +296,7 @@ impl PoolEndpointList {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let path = ep.get_file_path();
|
let path = ep.get_file_path();
|
||||||
if local_path_set.contains(path) {
|
if local_path_set.contains(&path) {
|
||||||
return Err(Error::other(format!(
|
return Err(Error::other(format!(
|
||||||
"path '{path}' cannot be served by different address on same server"
|
"path '{path}' cannot be served by different address on same server"
|
||||||
)));
|
)));
|
||||||
|
|||||||
Reference in New Issue
Block a user