66 lines
1.8 KiB
Rust
66 lines
1.8 KiB
Rust
/// Match a URL path against a pattern supporting wildcards.
|
|
///
|
|
/// Supported patterns:
|
|
/// - `/api/*` matches `/api/anything` (single level)
|
|
/// - `/api/**` matches `/api/any/depth/here`
|
|
/// - `/exact/path` exact match
|
|
/// - `/prefix*` prefix match
|
|
pub fn path_matches(pattern: &str, path: &str) -> bool {
|
|
// Exact match
|
|
if pattern == path {
|
|
return true;
|
|
}
|
|
|
|
// Double-star: match any depth
|
|
if pattern.ends_with("/**") {
|
|
let prefix = &pattern[..pattern.len() - 3];
|
|
return path == prefix || path.starts_with(&format!("{}/", prefix));
|
|
}
|
|
|
|
// Single-star at end: match single path segment
|
|
if pattern.ends_with("/*") {
|
|
let prefix = &pattern[..pattern.len() - 2];
|
|
if path == prefix {
|
|
return true;
|
|
}
|
|
if path.starts_with(&format!("{}/", prefix)) {
|
|
let rest = &path[prefix.len() + 1..];
|
|
// Single level means no more slashes
|
|
return !rest.contains('/');
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// Star anywhere: use glob matching
|
|
if pattern.contains('*') {
|
|
return glob_match::glob_match(pattern, path);
|
|
}
|
|
|
|
false
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn test_exact_path() {
|
|
assert!(path_matches("/api/users", "/api/users"));
|
|
assert!(!path_matches("/api/users", "/api/posts"));
|
|
}
|
|
|
|
#[test]
|
|
fn test_single_wildcard() {
|
|
assert!(path_matches("/api/*", "/api/users"));
|
|
assert!(path_matches("/api/*", "/api/posts"));
|
|
assert!(!path_matches("/api/*", "/api/users/123"));
|
|
}
|
|
|
|
#[test]
|
|
fn test_double_wildcard() {
|
|
assert!(path_matches("/api/**", "/api/users"));
|
|
assert!(path_matches("/api/**", "/api/users/123"));
|
|
assert!(path_matches("/api/**", "/api/users/123/posts"));
|
|
}
|
|
}
|