//! Small URL-assembly helpers shared by every HTTP caller in the //! workspace. //! //! All clients (desktop, server-internal, server-to-Ollama/Whisper) //! end up building `{base_url}{path}` where `base_url` comes from //! config and may or may not carry a trailing slash. The raw //! `format!("{}{}", base.trim_end_matches('/'), path)` pattern was //! duplicated in seven call sites; centralizing it here keeps any //! future rule (enforce a leading slash on the path, tolerate //! `http://host/` with a path segment, normalize percent-encoding) //! in one place. /// Join a base URL with an absolute path, normalizing any trailing /// slash on the base. The path is expected to start with `/`; no /// validation is performed — callers already pass constants like /// [`crate::UPLOAD_PATH`]. /// /// Examples: /// - `join_url("http://h", "/a")` → `"http://h/a"` /// - `join_url("http://h/", "/a")` → `"http://h/a"` /// - `join_url("http://h//", "/a")` → `"http://h/a"` pub fn join_url(base: &str, path: &str) -> String { let mut out = String::with_capacity(base.len() + path.len()); out.push_str(base.trim_end_matches('/')); out.push_str(path); out } #[cfg(test)] mod tests { use super::*; #[test] fn no_trailing_slash_on_base() { assert_eq!(join_url("http://h", "/a"), "http://h/a"); } #[test] fn single_trailing_slash_on_base() { assert_eq!(join_url("http://h/", "/a"), "http://h/a"); } #[test] fn multiple_trailing_slashes_on_base() { assert_eq!(join_url("http://h///", "/a"), "http://h/a"); } #[test] fn nested_path() { assert_eq!( join_url("https://example.com/", "/api/upload"), "https://example.com/api/upload" ); } }