#[derive(Debug, thiserror::Error)]
#[error("Redirect url {redirect_url:?} could not be reconciled with original url {expected_url} as they don't share the same suffix")]
pub struct Error {
redirect_url: String,
expected_url: String,
}
pub(crate) fn base_url(redirect_url: &str, base_url: &str, url: String) -> Result<String, Error> {
let tail = url
.strip_prefix(base_url)
.expect("BUG: caller assures `base_url` is subset of `url`");
redirect_url
.strip_suffix(tail)
.ok_or_else(|| Error {
redirect_url: redirect_url.into(),
expected_url: url,
})
.map(ToOwned::to_owned)
}
pub(crate) fn swap_tails(effective_base_url: Option<&str>, base_url: &str, mut url: String) -> String {
match effective_base_url {
Some(effective_base) => {
url.replace_range(..base_url.len(), effective_base);
url
}
None => url,
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn base_url_complete() {
assert_eq!(
base_url(
"https://redirected.org/b/info/refs?hi",
"https://original/a",
"https://original/a/info/refs?hi".into()
)
.unwrap(),
"https://redirected.org/b"
);
}
#[test]
fn swap_tails_complete() {
assert_eq!(
swap_tails(None, "not interesting", "used".into()),
"used",
"without effective base url, it passes url, no redirect happened yet"
);
assert_eq!(
swap_tails(
Some("https://redirected.org/b"),
"https://original/a",
"https://original/a/info/refs?something".into()
),
"https://redirected.org/b/info/refs?something",
"the tail stays the same if redirection happened"
)
}
}