ferron/util/
match_location.rs

1pub fn match_location(path: &str, req_path: &str) -> bool {
2  let mut path_without_trailing_slashes = path;
3  while path_without_trailing_slashes.ends_with("/") {
4    path_without_trailing_slashes =
5      &path_without_trailing_slashes[..(path_without_trailing_slashes.len() - 1)];
6  }
7
8  let mut path_prepared = path_without_trailing_slashes.to_owned();
9  let mut req_path_prepared = req_path.to_owned();
10
11  while path_prepared.contains("//") {
12    path_prepared = path_prepared.replace("//", "/");
13  }
14
15  while req_path_prepared.contains("//") {
16    req_path_prepared = path_prepared.replace("//", "/");
17  }
18
19  if cfg!(windows) {
20    path_prepared = path_prepared.to_lowercase();
21    req_path_prepared = req_path_prepared.to_lowercase();
22  }
23
24  path_prepared == req_path_prepared || req_path_prepared.starts_with(&format!("{path_prepared}/"))
25}
26
27#[cfg(test)]
28mod tests {
29  use super::match_location;
30
31  #[test]
32  fn test_exact_match() {
33    assert!(match_location("/home", "/home"));
34    assert!(match_location("/api/v1", "/api/v1"));
35  }
36
37  #[test]
38  fn test_trailing_slash() {
39    assert!(match_location("/home/", "/home"));
40    assert!(match_location("/home", "/home/"));
41    assert!(match_location("/api/v1/", "/api/v1"));
42  }
43
44  #[test]
45  fn test_subpath_match() {
46    assert!(match_location("/api", "/api/v1"));
47    assert!(match_location("/users", "/users/profile"));
48  }
49
50  #[test]
51  fn test_non_matching_paths() {
52    assert!(!match_location("/home", "/dashboard"));
53    assert!(!match_location("/api", "/user"));
54  }
55
56  #[test]
57  fn test_multiple_slashes() {
58    assert!(match_location("/api//v1", "/api/v1"));
59    assert!(match_location("//home///", "/home"));
60  }
61
62  #[test]
63  fn test_case_insensitivity_on_windows() {
64    #[cfg(windows)]
65    {
66      assert!(match_location("/API", "/api"));
67      assert!(match_location("/Home", "/home"));
68    }
69  }
70}