1use url::Url;
2
3pub fn normalize_url(input: &str) -> Option<(String, String)> {
4 let mut url = Url::parse(input).ok()?;
5 url.set_fragment(None);
6
7 let host = url.host_str()?.to_ascii_lowercase();
8
9 if (url.scheme() == "http" && url.port() == Some(80))
10 || (url.scheme() == "https" && url.port() == Some(443))
11 {
12 let _ = url.set_port(None);
13 }
14
15 Some((url.to_string(), host))
16}
17
18#[cfg(test)]
19mod tests {
20 use super::*;
21
22 #[test]
23 fn normalizes_https_and_strips_default_port() {
24 let (url, host) = normalize_url("https://example.com:443/path").unwrap();
25 assert_eq!(url, "https://example.com/path");
26 assert_eq!(host, "example.com");
27 }
28
29 #[test]
30 fn strips_fragment() {
31 let (url, _) = normalize_url("https://example.com/page#section").unwrap();
32 assert_eq!(url, "https://example.com/page");
33 }
34
35 #[test]
36 fn rejects_invalid_url() {
37 assert!(normalize_url("not a url").is_none());
38 }
39
40 #[test]
41 fn rejects_mailto() {
42 assert!(normalize_url("mailto:foo@bar.com").is_none());
43 }
44}