pub fn normalize_url_path(url_path: &str, url_path_prefix: Option<&str>) -> String {
let url_path_prefix = match url_path_prefix {
Some(prefix) if !prefix.is_empty() => prefix.strip_suffix('/').unwrap_or(prefix),
_ => "",
};
let url_path = url_path.strip_prefix('/').unwrap_or(url_path);
let merged = format!("{}/{}", url_path_prefix, url_path);
let trimmed = merged.strip_suffix('/').unwrap_or(merged.as_str());
let trimmed = trimmed.strip_prefix('/').unwrap_or(trimmed);
let stripped: Vec<&str> = trimmed.split('/').filter(|seg| *seg != "..").collect();
format!("/{}", stripped.join("/"))
}
#[cfg(test)]
mod tests {
use super::normalize_url_path;
#[test]
fn ordinary_paths_are_unaffected() {
assert_eq!(normalize_url_path("/api/v1", None), "/api/v1");
assert_eq!(normalize_url_path("api/v1", None), "/api/v1");
assert_eq!(normalize_url_path("/api/v1/", None), "/api/v1");
}
#[test]
fn a_leading_dot_dot_segment_is_stripped() {
assert_eq!(normalize_url_path("/../outside.txt", None), "/outside.txt");
}
#[test]
fn repeated_leading_dot_dot_segments_are_all_stripped() {
assert_eq!(
normalize_url_path("/../../outside.txt", None),
"/outside.txt"
);
}
#[test]
fn a_mid_path_dot_dot_segment_is_stripped() {
assert_eq!(normalize_url_path("/foo/../bar", None), "/foo/bar");
}
#[test]
fn a_bare_dot_dot_normalises_to_root() {
assert_eq!(normalize_url_path("/..", None), "/");
}
#[test]
fn a_prefix_is_still_applied_alongside_stripping() {
assert_eq!(
normalize_url_path("/../outside.txt", Some("/api")),
"/api/outside.txt"
);
}
}