fix(navigation): classify HTTP schemes case-insensitively
This commit is contained in:
@@ -96,8 +96,7 @@ pub(crate) fn pane_host_label(tab: &BrowserTab) -> String {
|
||||
}
|
||||
|
||||
pub(crate) fn pane_url_is_secure(tab: &BrowserTab) -> bool {
|
||||
let url = tab.url().as_str();
|
||||
url.starts_with("https://") || url.starts_with("ely://")
|
||||
tab.url().has_any_scheme(&["https"]) || tab.url().as_str().starts_with("ely://")
|
||||
}
|
||||
|
||||
pub(crate) fn split_canvas_status(tab: &BrowserTab) -> String {
|
||||
@@ -144,3 +143,34 @@ pub(crate) fn render_compact_split_canvas(tab: &BrowserTab) -> AnyElement {
|
||||
)
|
||||
.into_any_element()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use ely_domain::{BrowserTab, ProfileId, SpaceId, TabId, UrlText};
|
||||
|
||||
use super::pane_url_is_secure;
|
||||
|
||||
#[test]
|
||||
fn secure_indicator_preserves_web_and_internal_scheme_semantics()
|
||||
-> Result<(), Box<dyn std::error::Error>> {
|
||||
for (url, expected) in [
|
||||
("https://example.com", true),
|
||||
("HTTPS://Example.com", true),
|
||||
("http://example.com", false),
|
||||
("HTTP://Example.com", false),
|
||||
("custom://example.com", false),
|
||||
("ely://settings", true),
|
||||
("ELY://settings", false),
|
||||
] {
|
||||
let tab = BrowserTab::new(
|
||||
TabId::new(),
|
||||
SpaceId::new(),
|
||||
ProfileId::new(),
|
||||
"Web",
|
||||
UrlText::parse(url)?,
|
||||
);
|
||||
assert_eq!(pane_url_is_secure(&tab), expected, "{url}");
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,7 +81,7 @@ fn render_omnibar(
|
||||
let active_url = active_tab.url().as_str().to_string();
|
||||
let command_focused = shell.command_input.read(cx).focus_handle(cx).is_focused(window);
|
||||
let show_styled = !command_focused && active_url != "ely://new-tab";
|
||||
let secure = active_url.starts_with("https://") || active_url.starts_with("ely://");
|
||||
let secure = super::pane_url_is_secure(active_tab);
|
||||
let omnibar_motion_target = "omnibar-content";
|
||||
let omnibar_press_id = shell.chrome_motion_animation_id(omnibar_motion_target);
|
||||
|
||||
|
||||
@@ -145,7 +145,7 @@ impl ElyShell {
|
||||
let content = self.render_sync_page(snapshot, cx);
|
||||
render_settings_shell(snapshot, "ely://settings/sync", content, cx)
|
||||
}
|
||||
url if super::web_surface::is_external_web_url(url) => {
|
||||
_ if super::web_surface::is_external_web_url(tab.url()) => {
|
||||
self.render_external_web_canvas(tab, snapshot, bottom_corner_radius, cx)
|
||||
}
|
||||
_ => render_default_page(tab),
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use std::collections::BTreeMap;
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
use ely_domain::{BrowserTab, ProfileId, TabId};
|
||||
use ely_domain::{BrowserTab, ProfileId, TabId, UrlText};
|
||||
|
||||
use crate::services::{ProfileDataMode, servo_live::ServoLivePermissionGrant};
|
||||
|
||||
@@ -58,7 +58,7 @@ impl WebSurfaceStore {
|
||||
profile_data_mode: ProfileDataMode,
|
||||
permissions: &[WebSurfaceSitePermission],
|
||||
) -> bool {
|
||||
if !is_external_web_url(tab.url().as_str()) {
|
||||
if !is_external_web_url(tab.url()) {
|
||||
return false;
|
||||
}
|
||||
let requested_url = tab.url().as_str().to_string();
|
||||
@@ -372,8 +372,8 @@ impl WebSurfaceStore {
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn is_external_web_url(url: &str) -> bool {
|
||||
url.starts_with("https://") || url.starts_with("http://")
|
||||
pub(super) fn is_external_web_url(url: &UrlText) -> bool {
|
||||
url.has_any_scheme(&["http", "https"])
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -283,7 +283,7 @@ fn visible_web_surface_tabs(
|
||||
let mut permission_cache = HashMap::new();
|
||||
let mut visible = Vec::new();
|
||||
for tab in tabs {
|
||||
if !super::web_surface::is_external_web_url(tab.url().as_str()) {
|
||||
if !super::web_surface::is_external_web_url(tab.url()) {
|
||||
continue;
|
||||
}
|
||||
let Ok(kind) = core.profile_kind_for(tab.profile_id()) else {
|
||||
@@ -308,7 +308,7 @@ fn visible_web_surface_tabs(
|
||||
|
||||
fn external_web_surface_tab_ids(tabs: &[BrowserTab]) -> Vec<TabId> {
|
||||
tabs.iter()
|
||||
.filter(|tab| super::web_surface::is_external_web_url(tab.url().as_str()))
|
||||
.filter(|tab| super::web_surface::is_external_web_url(tab.url()))
|
||||
.map(|tab| tab.id().clone())
|
||||
.collect()
|
||||
}
|
||||
@@ -316,7 +316,7 @@ fn external_web_surface_tab_ids(tabs: &[BrowserTab]) -> Vec<TabId> {
|
||||
fn external_web_surface_scopes(core: &BrowserCore) -> Vec<(TabId, ProfileId, ProfileDataMode)> {
|
||||
core.open_tabs()
|
||||
.iter()
|
||||
.filter(|tab| super::web_surface::is_external_web_url(tab.url().as_str()))
|
||||
.filter(|tab| super::web_surface::is_external_web_url(tab.url()))
|
||||
.filter_map(|tab| {
|
||||
core.profile_kind_for(tab.profile_id()).ok().map(|kind| {
|
||||
(tab.id().clone(), tab.profile_id().clone(), profile_data_mode_from_kind(kind))
|
||||
|
||||
@@ -123,6 +123,20 @@ fn external_tab_ids_exclude_internal_routes() -> Result<(), Box<dyn std::error::
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn external_tab_ids_include_uppercase_http_schemes() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let mut core = BrowserCore::new(InitialBrowserConfig::ely_defaults()?)?;
|
||||
let https_tab_id = core.snapshot()?.active_tab_id;
|
||||
core.navigate_active_tab(UrlText::parse("HTTPS://Example.com/Path")?)?;
|
||||
assert_eq!(core.active_tab()?.url().as_str(), "HTTPS://Example.com/Path");
|
||||
|
||||
let http_tab_id = core.open_tab(UrlText::parse("HTTP://Example.com/Plain")?);
|
||||
|
||||
assert_eq!(core.active_tab()?.url().as_str(), "HTTP://Example.com/Plain");
|
||||
assert_eq!(external_web_surface_tab_ids(core.open_tabs()), vec![https_tab_id, http_tab_id]);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn external_tab_ids_include_inactive_spaces() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let mut core = BrowserCore::new(InitialBrowserConfig::ely_defaults()?)?;
|
||||
|
||||
@@ -46,10 +46,10 @@ impl ElyShell {
|
||||
return None;
|
||||
};
|
||||
let tab = core.active_tab().ok()?;
|
||||
let requested_url = tab.url().as_str();
|
||||
if !is_external_web_url(requested_url) {
|
||||
if !is_external_web_url(tab.url()) {
|
||||
return None;
|
||||
}
|
||||
let requested_url = tab.url().as_str();
|
||||
|
||||
Some((tab.id().clone(), requested_url.to_string()))
|
||||
}
|
||||
|
||||
@@ -44,6 +44,14 @@ impl UrlText {
|
||||
&self.value
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn has_any_scheme(&self, schemes: &[&str]) -> bool {
|
||||
let Some((scheme, _)) = self.value.split_once(':') else {
|
||||
return false;
|
||||
};
|
||||
schemes.iter().any(|candidate| scheme.eq_ignore_ascii_case(candidate))
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn display_host(&self) -> String {
|
||||
Url::parse(&self.value)
|
||||
@@ -91,3 +99,18 @@ impl fmt::Display for UrlText {
|
||||
f.write_str(&self.value)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::UrlText;
|
||||
|
||||
#[test]
|
||||
fn parsed_scheme_matching_preserves_original_text() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let url = UrlText::parse("HTTPS://Example.com/Path")?;
|
||||
|
||||
assert!(url.has_any_scheme(&["http", "https"]));
|
||||
assert!(!url.has_any_scheme(&["custom"]));
|
||||
assert_eq!(url.as_str(), "HTTPS://Example.com/Path");
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user