1#[cfg(not(any(target_os = "android", target_env = "ohos")))]
6use std::path::{Path, PathBuf};
7
8use servo::net_traits::pub_domains::is_reg_domain;
9use servo::servo_url::ServoUrl;
10
11#[cfg(not(any(target_os = "android", target_env = "ohos")))]
12pub fn parse_url_or_filename(cwd: &Path, input: &str) -> Result<ServoUrl, ()> {
13 match ServoUrl::parse(input) {
14 Ok(url) => Ok(url),
15 Err(url::ParseError::RelativeUrlWithoutBase) => {
16 url::Url::from_file_path(&*cwd.join(input)).map(ServoUrl::from_url)
17 },
18 Err(_) => Err(()),
19 }
20}
21
22#[cfg(not(any(target_os = "android", target_env = "ohos")))]
23pub fn get_default_url(
24 url_opt: Option<&str>,
25 cwd: impl AsRef<Path>,
26 exists: impl FnOnce(&PathBuf) -> bool,
27 preferences: &crate::prefs::ServoShellPreferences,
28) -> ServoUrl {
29 let mut new_url = None;
32 let cmdline_url = url_opt.map(|s| s.to_string()).and_then(|url_string| {
33 parse_url_or_filename(cwd.as_ref(), &url_string)
34 .inspect_err(|&error| {
35 log::warn!("URL parsing failed ({:?}).", error);
36 })
37 .ok()
38 });
39
40 if let Some(url) = cmdline_url.clone() {
41 match (url.scheme(), url.host(), url.to_file_path()) {
43 ("file", None, Ok(ref path)) if exists(path) => {
44 new_url = cmdline_url;
45 },
46 _ => {},
47 }
48 }
49
50 #[allow(
51 clippy::collapsible_if,
52 reason = "let chains are not available in 1.85"
53 )]
54 if new_url.is_none() {
55 if let Some(url_opt) = url_opt {
56 new_url = location_bar_input_to_url(url_opt, &preferences.searchpage);
57 }
58 }
59
60 let pref_url = parse_url_or_filename(cwd.as_ref(), &preferences.homepage).ok();
61 let blank_url = ServoUrl::parse("about:blank").ok();
62
63 new_url.or(pref_url).or(blank_url).unwrap()
64}
65
66pub(crate) fn location_bar_input_to_url(request: &str, searchpage: &str) -> Option<ServoUrl> {
71 let request = request.trim();
72 ServoUrl::parse(request)
73 .ok()
74 .or_else(|| try_as_file(request))
75 .or_else(|| try_as_domain(request))
76 .or_else(|| try_as_search_page(request, searchpage))
77}
78
79fn try_as_file(request: &str) -> Option<ServoUrl> {
80 if request.starts_with('/') {
81 return ServoUrl::parse(&format!("file://{}", request)).ok();
82 }
83 None
84}
85
86fn try_as_domain(request: &str) -> Option<ServoUrl> {
87 fn is_domain_like(s: &str) -> bool {
88 !s.starts_with('/') && s.contains('/') ||
89 (!s.contains(' ') && !s.starts_with('.') && s.split('.').count() > 1)
90 }
91
92 if !request.contains(' ') && is_reg_domain(request) || is_domain_like(request) {
93 return ServoUrl::parse(&format!("https://{}", request)).ok();
94 }
95 None
96}
97
98fn try_as_search_page(request: &str, searchpage: &str) -> Option<ServoUrl> {
99 if request.is_empty() {
100 return None;
101 }
102 ServoUrl::parse(&searchpage.replace("%s", request)).ok()
103}