//! Адрес инстанса и границы навигации. //! //! Desktop-обёртка загружает тот же клиент, что и браузер, но только с одного //! адреса: переходы на сторонние сайты уходят в системный браузер //! (docs/client-tauri.md §6). use url::Url; /// Приводит введённый пользователем адрес к абсолютному URL. /// /// Допускаются `http` и `https`; схема по умолчанию — `https`, чтобы в поле /// настроек можно было написать просто `gl.mhspx.su`. pub fn normalize(input: &str) -> Result { let trimmed = input.trim(); if trimmed.is_empty() { return Err("адрес инстанса не заполнен".to_string()); } let candidate = if trimmed.contains("://") { trimmed.to_string() } else { format!("https://{trimmed}") }; let url = Url::parse(&candidate).map_err(|error| format!("некорректный адрес: {error}"))?; match url.scheme() { "http" | "https" => {} other => { return Err(format!( "поддерживаются только http и https, а не «{other}»" )) } } if url.host_str().unwrap_or_default().is_empty() { return Err("в адресе нет имени хоста".to_string()); } Ok(url) } /// Строка адреса для загрузки в окно: без завершающего слэша. pub fn display(url: &Url) -> String { url.as_str().trim_end_matches('/').to_string() } /// Хост адреса — граница, внутри которой разрешена навигация webview. pub fn host(url: &Url) -> String { url.host_str().unwrap_or_default().to_ascii_lowercase() } /// Разрешена ли навигация внутри окна. /// /// Свой инстанс и локальные страницы обёртки (`tauri://localhost`) — да, /// всё остальное открывается в системном браузере. pub fn navigation_allowed(target: &Url, instance_host: &str) -> bool { match target.scheme() { // Локальные ресурсы обёртки: страница настроек. "tauri" | "asset" => true, "http" | "https" => { let host = target.host_str().unwrap_or_default().to_ascii_lowercase(); // На Windows/Linux локальная страница отдаётся как http://tauri.localhost. host == "tauri.localhost" || (!instance_host.is_empty() && host == instance_host) } _ => false, } }