From f1a01242273280eb179cdfa9d76ed7d88f621817 Mon Sep 17 00:00:00 2001 From: Jonathan Kelley Date: Thu, 7 May 2026 15:11:47 -0700 Subject: [PATCH] backport iframe fix to v0.7 (#5535) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat:Add opt‑in navigation handler for external URLs (#5531) * add navigation handler config option code from https://github.com/DioxusLabs/dioxus/pull/5231 * Re-order branches The branches should be reorder so that the branch that checks for the index and assets is always taken first. Otherwise, they will fail to load for users who forget to allow them in their custom handlers, which will be a crappy experience and hard to debug. * remove return * Change behavior when handler not set --------- Co-authored-by: not a cow * fix: allow navigations but disallow external nav --------- Co-authored-by: Martin Martinez Rivera Co-authored-by: not a cow --- packages/desktop/src/config.rs | 13 +++++++++++++ packages/desktop/src/webview.rs | 29 +++++++++++++++++------------ 2 files changed, 30 insertions(+), 12 deletions(-) diff --git a/packages/desktop/src/config.rs b/packages/desktop/src/config.rs index 78d45bfe9..11c62a1a6 100644 --- a/packages/desktop/src/config.rs +++ b/packages/desktop/src/config.rs @@ -20,6 +20,10 @@ type CustomEventHandler = Box< ), >; +/// A function taking a URL and returning whether the webview should navigate to it or open it in +/// the browser. If missing in the config, all URLs will be allowed. +type NavigationHandler = Box bool + 'static>; + /// The closing behaviour of specific application window. #[derive(Debug, Copy, Clone, Eq, PartialEq)] #[non_exhaustive] @@ -70,6 +74,7 @@ pub struct Config { pub(crate) disable_dma_buf_on_wayland: bool, pub(crate) additional_windows_args: Option, pub(crate) tray_icon_show_window_on_click: bool, + pub(crate) navigation_handler: Option, #[allow(clippy::type_complexity)] pub(crate) on_window: Option, &mut VirtualDom) + 'static>>, @@ -124,6 +129,7 @@ impl Config { on_window: None, additional_windows_args: None, tray_icon_show_window_on_click: true, + navigation_handler: None, } } @@ -350,6 +356,13 @@ impl Config { self.tray_icon_show_window_on_click = show; self } + + /// Set a custom navigation handler for non-dioxus URLs. + /// Return true to allow navigation inside the webview, false to block. + pub fn with_navigation_handler(mut self, f: impl Fn(&str) -> bool + 'static) -> Self { + self.navigation_handler = Some(Box::new(f)); + self + } } impl Default for Config { diff --git a/packages/desktop/src/webview.rs b/packages/desktop/src/webview.rs index 9710721fc..a86a0b30f 100644 --- a/packages/desktop/src/webview.rs +++ b/packages/desktop/src/webview.rs @@ -353,6 +353,7 @@ impl WebviewInstance { } }; + let navigation_handler = cfg.navigation_handler.take(); let page_loaded = AtomicBool::new(false); let mut webview = WebViewBuilder::new_with_web_context(&mut web_context) @@ -367,25 +368,29 @@ impl WebviewInstance { .with_url("dioxus://index.html/") .with_ipc_handler(ipc_handler) .with_navigation_handler(move |var| { - // We don't want to allow any navigation - // We only want to serve the index file and assets + // Serve the index and assets. if var.starts_with("dioxus://") || var.starts_with("http://dioxus.") || var.starts_with("https://dioxus.") { // After the page has loaded once, don't allow any more navigation let page_loaded = page_loaded.swap(true, std::sync::atomic::Ordering::SeqCst); - !page_loaded - } else { - if var.starts_with("http://") - || var.starts_with("https://") - || var.starts_with("mailto:") - { - _ = webbrowser::open(&var); - } - false + return !page_loaded; } - }) // prevent all navigations + + // External links always open somewhere else. Prevents the webview from navigating + if var.starts_with("http://") + || var.starts_with("https://") + || var.starts_with("mailto:") + { + _ = webbrowser::open(&var); + return false; + } + + // By default, external links are allowed. This keeps things like iframes working. + // However, users can customize this to allow/disallow domains/routes/patterns. + navigation_handler.as_ref().map(|f| f(&var)).unwrap_or(true) + }) .with_asynchronous_custom_protocol(String::from("dioxus"), request_handler); // Enable https scheme on android, needed for secure context API, like the geolocation API