use http::Uri;
fn with_transformed_path(url: Uri, build: impl FnOnce(&str) -> String) -> Result<Uri, http::Error> {
let path = url.path();
let cleaned_path = path.strip_suffix('/').unwrap_or(path);
let mut new_path_and_query = build(cleaned_path);
if let Some(query) = url.query() {
new_path_and_query = format!("{new_path_and_query}?{query}");
}
let mut parts = url.into_parts();
parts.path_and_query = Some(new_path_and_query.try_into()?);
Ok(Uri::from_parts(parts)?)
}
pub(crate) fn insert_well_known_path(url: Uri, well_known_path: &str) -> Result<Uri, http::Error> {
with_transformed_path(url, |path| format!("{well_known_path}{path}"))
}
pub(crate) fn append_well_known_path(url: Uri, well_known_path: &str) -> Result<Uri, http::Error> {
with_transformed_path(url, |path| format!("{path}{well_known_path}"))
}
#[cfg(test)]
mod tests {
use rstest::rstest;
use super::*;
#[rstest]
#[case::no_path("https://example.com", "https://example.com/.well-known/x")]
#[case::path_goes_after("https://example.com/a", "https://example.com/.well-known/x/a")]
#[case::trailing_slash("https://example.com/a/", "https://example.com/.well-known/x/a")]
#[case::query_preserved("https://example.com/a?q=1", "https://example.com/.well-known/x/a?q=1")]
fn insert_puts_well_known_before_the_path(#[case] url: &str, #[case] expected: &str) {
let url: Uri = url.parse().unwrap();
assert_eq!(
insert_well_known_path(url, "/.well-known/x")
.unwrap()
.to_string(),
expected
);
}
#[rstest]
#[case::no_path("https://example.com", "https://example.com/.well-known/x")]
#[case::path_goes_before("https://example.com/a", "https://example.com/a/.well-known/x")]
#[case::trailing_slash("https://example.com/a/", "https://example.com/a/.well-known/x")]
fn append_puts_well_known_after_the_path(#[case] url: &str, #[case] expected: &str) {
let url: Uri = url.parse().unwrap();
assert_eq!(
append_well_known_path(url, "/.well-known/x")
.unwrap()
.to_string(),
expected
);
}
}