fix: Resolve : ambiguity in URL path placeholders (#465)

Co-authored-by: Simon Johansson <simon.johansson@infor.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: Gregory Schier <gschier1990@gmail.com>
This commit is contained in:
Simon Johansson
2026-07-01 22:23:27 +02:00
committed by GitHub
parent ea3587f28d
commit 5004c395de
10 changed files with 151 additions and 43 deletions
+16 -1
View File
@@ -34,7 +34,10 @@ fn replace_path_placeholder(p: &HttpUrlParameter, url: &str) -> String {
return url.to_string();
}
let re = regex::Regex::new(format!("(/){}([/?#]|$)", p.name).as_str()).unwrap();
// A path placeholder is terminated by `/`, `?`, `#`, end-of-string, or a literal `:`.
// The `:` boundary is what lets `/:id:increment-importance` substitute the `:id`
// placeholder while leaving `:increment-importance` as literal text.
let re = regex::Regex::new(format!("(/){}([/?#:]|$)", p.name).as_str()).unwrap();
let result = re
.replace_all(url, |cap: &regex::Captures| {
format!(
@@ -83,6 +86,18 @@ mod placeholder_tests {
);
}
#[test]
fn placeholder_followed_by_literal_colon() {
// AIP-136-style custom method: `:id` is the placeholder, `:increment-importance`
// is literal text in the same path segment.
let p =
HttpUrlParameter { name: ":id".into(), value: "42".into(), enabled: true, id: None };
assert_eq!(
replace_path_placeholder(&p, "https://example.com/tasks/:id:increment-importance"),
"https://example.com/tasks/42:increment-importance",
);
}
#[test]
fn placeholder_missing() {
let p = HttpUrlParameter {