crw_server/
diagnostics.rs1use crw_core::config::SearchConfig;
8use tracing::Level;
9
10pub fn sanitize_url_origin(raw: &str) -> String {
15 match url::Url::parse(raw) {
16 Ok(u) => match (u.host_str(), u.port()) {
17 (Some(host), Some(port)) => format!("{}://{host}:{port}", u.scheme()),
18 (Some(host), None) => format!("{}://{host}", u.scheme()),
19 (None, _) => "<redacted-url>".to_string(),
20 },
21 Err(_) => "<redacted-url>".to_string(),
22 }
23}
24
25pub fn search_startup_status(cfg: &SearchConfig) -> (Level, String) {
32 if !cfg.enabled {
33 (
34 Level::INFO,
35 "search: disabled ([search].enabled = false)".to_string(),
36 )
37 } else if let Some(url) = &cfg.searxng_url {
38 (
39 Level::INFO,
40 format!("search: enabled (searxng={})", sanitize_url_origin(url)),
41 )
42 } else {
43 (
44 Level::WARN,
45 "search: enabled but no [search].searxng_url — /v1/search will return 503".to_string(),
46 )
47 }
48}
49
50#[cfg(test)]
51mod tests {
52 use super::*;
53
54 #[test]
55 fn sanitize_strips_userinfo_path_query_fragment() {
56 assert_eq!(
57 sanitize_url_origin("https://user:pass@host:9000/searxng/tok123?q=x#frag"),
58 "https://host:9000"
59 );
60 assert_eq!(
61 sanitize_url_origin("http://searxng:8080"),
62 "http://searxng:8080"
63 );
64 assert_eq!(
65 sanitize_url_origin("http://searxng:8080/"),
66 "http://searxng:8080"
67 );
68 assert_eq!(
70 sanitize_url_origin("https://example.com"),
71 "https://example.com"
72 );
73 }
74
75 #[test]
76 fn sanitize_redacts_unparseable() {
77 assert_eq!(sanitize_url_origin("not a url"), "<redacted-url>");
78 }
79
80 fn cfg(enabled: bool, url: Option<&str>) -> SearchConfig {
81 let toml = match url {
82 Some(u) => format!("enabled = {enabled}\nsearxng_url = \"{u}\"\n"),
83 None => format!("enabled = {enabled}\n"),
84 };
85 toml::from_str(&toml).expect("valid SearchConfig")
86 }
87
88 #[test]
89 fn startup_status_enabled_with_url() {
90 let (level, msg) = search_startup_status(&cfg(true, Some("http://searxng:8080")));
91 assert_eq!(level, Level::INFO);
92 assert!(
93 msg.contains("enabled (searxng=http://searxng:8080)"),
94 "{msg}"
95 );
96 }
97
98 #[test]
99 fn startup_status_enabled_no_url_warns() {
100 let (level, msg) = search_startup_status(&cfg(true, None));
101 assert_eq!(level, Level::WARN);
102 assert!(msg.contains("no [search].searxng_url"), "{msg}");
103 }
104
105 #[test]
106 fn startup_status_disabled() {
107 let (level, msg) = search_startup_status(&cfg(false, Some("http://searxng:8080")));
108 assert_eq!(level, Level::INFO);
109 assert!(msg.contains("disabled"), "{msg}");
110 }
111
112 #[test]
113 fn startup_status_never_leaks_credentials() {
114 let (_, msg) = search_startup_status(&cfg(true, Some("https://u:secret@host:8080/tok")));
115 assert!(!msg.contains("secret"), "{msg}");
116 assert!(!msg.contains("tok"), "{msg}");
117 assert!(msg.contains("https://host:8080"), "{msg}");
118 }
119}