fix(navigation): classify HTTP schemes case-insensitively

This commit is contained in:
2026-07-09 23:08:15 -04:00
parent 755a6aabd8
commit a6e3aeaf46
8 changed files with 80 additions and 13 deletions
+32 -2
View File
@@ -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(())
}
}
+1 -1
View File
@@ -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);
+1 -1
View File
@@ -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),
+4 -4
View File
@@ -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()))
}
+23
View File
@@ -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(())
}
}