From 2a25b674feaf7fe3c5e5a47025e1981031e5fc38 Mon Sep 17 00:00:00 2001 From: Roope Salmi Date: Wed, 24 Jul 2024 15:14:09 +0300 Subject: [PATCH 1/7] fix(linux): don't share UserContentManager between webviews Fixes #1308 Init scripts are registered to the UserContentManager, so if it is shared between webviews, the init scripts will conflict. Use a unique UserContentManager for each WebView instead of sharing it across the WebContext. The IPC message handler is also registered to UserContentManager. window_hash is no longer needed as a key to register_script_message_handler since the manager is unique. window_hash is already removed on the dev branch. --- src/webview/webkitgtk/mod.rs | 28 ++++++++-------------------- src/webview/webkitgtk/web_context.rs | 13 ++----------- 2 files changed, 10 insertions(+), 31 deletions(-) diff --git a/src/webview/webkitgtk/mod.rs b/src/webview/webkitgtk/mod.rs index e8d6a6a7a..110731b96 100644 --- a/src/webview/webkitgtk/mod.rs +++ b/src/webview/webkitgtk/mod.rs @@ -9,15 +9,14 @@ use gtk::prelude::*; #[cfg(any(debug_assertions, feature = "devtools"))] use std::sync::atomic::{AtomicBool, Ordering}; use std::{ - collections::hash_map::DefaultHasher, - hash::{Hash, Hasher}, rc::Rc, sync::{Arc, Mutex}, }; use url::Url; use webkit2gtk::{ traits::*, LoadEvent, NavigationPolicyDecision, PolicyDecisionType, URIRequest, - UserContentInjectedFrames, UserScript, UserScriptInjectionTime, WebView, WebViewBuilder, + UserContentInjectedFrames, UserContentManager, UserScript, UserScriptInjectionTime, WebView, + WebViewBuilder, }; use webkit2gtk_sys::{ webkit_get_major_version, webkit_get_micro_version, webkit_get_minor_version, @@ -63,9 +62,11 @@ impl InnerWebView { } }; + let manager = UserContentManager::new(); + let webview = { let mut webview = WebViewBuilder::new(); - webview = webview.user_content_manager(web_context.manager()); + webview = webview.user_content_manager(&manager); webview = webview.web_context(web_context.context()); webview = webview.is_controlled_by_automation(web_context.allows_automation()); webview.build() @@ -77,15 +78,6 @@ impl InnerWebView { let webview = Rc::new(webview); let w = window_rc.clone(); let ipc_handler = attributes.ipc_handler.take(); - let manager = web_context.manager(); - - // Use the window hash as the script handler name to prevent from conflict when sharing same - // web context. - let window_hash = { - let mut hasher = DefaultHasher::new(); - w.id().hash(&mut hasher); - hasher.finish().to_string() - }; // Connect before registering as recommended by the docs manager.connect_script_message_received(None, move |_m, msg| { @@ -99,8 +91,8 @@ impl InnerWebView { } }); - // Register the handler we just connected - manager.register_script_message_handler(&window_hash); + // Register handler on JS side + manager.register_script_message_handler("ipc"); // Allow the webview to close it's own window let close_window = window_rc.clone(); @@ -343,11 +335,7 @@ impl InnerWebView { }; // Initialize message handler - let mut init = String::with_capacity(115 + 20 + 22); - init.push_str("Object.defineProperty(window, 'ipc', {value: Object.freeze({postMessage:function(x){window.webkit.messageHandlers[\""); - init.push_str(&window_hash); - init.push_str("\"].postMessage(x)}})})"); - w.init(&init)?; + w.init("Object.defineProperty(window, 'ipc', { value: Object.freeze({ postMessage: function(x) { window.webkit.messageHandlers['ipc'].postMessage(x) } }) })")?; // Initialize scripts for js in attributes.initialization_scripts { diff --git a/src/webview/webkitgtk/web_context.rs b/src/webview/webkitgtk/web_context.rs index 1b4063993..c80a9f13d 100644 --- a/src/webview/webkitgtk/web_context.rs +++ b/src/webview/webkitgtk/web_context.rs @@ -21,14 +21,13 @@ use std::{ }; use url::Url; use webkit2gtk::{ - traits::*, ApplicationInfo, CookiePersistentStorage, LoadEvent, URIRequest, UserContentManager, - WebContext, WebContextBuilder, WebView, WebsiteDataManagerBuilder, + traits::*, ApplicationInfo, CookiePersistentStorage, LoadEvent, URIRequest, WebContext, + WebContextBuilder, WebView, WebsiteDataManagerBuilder, }; #[derive(Debug)] pub struct WebContextImpl { context: WebContext, - manager: UserContentManager, webview_uri_loader: Rc, registered_protocols: HashSet, automation: bool, @@ -82,7 +81,6 @@ impl WebContextImpl { Self { context, automation, - manager: UserContentManager::new(), registered_protocols: Default::default(), webview_uri_loader: Rc::default(), app_info: Some(app_info), @@ -101,9 +99,6 @@ pub trait WebContextExt { /// The GTK [`WebContext`] of all webviews in the context. fn context(&self) -> &WebContext; - /// The GTK [`UserContentManager`] of all webviews in the context. - fn manager(&self) -> &UserContentManager; - /// Register a custom protocol to the web context. /// /// When duplicate schemes are registered, the duplicate handler will still be submitted and the @@ -150,10 +145,6 @@ impl WebContextExt for super::WebContext { &self.os.context } - fn manager(&self) -> &UserContentManager { - &self.os.manager - } - fn register_uri_scheme(&mut self, name: &str, handler: F) -> crate::Result<()> where F: Fn(&Request>) -> crate::Result>> + 'static, From 9d05853caae0b3e523f8b312b372e4a090cd8bff Mon Sep 17 00:00:00 2001 From: Roope Salmi Date: Wed, 24 Jul 2024 15:14:16 +0300 Subject: [PATCH 2/7] fix(linux): don't try to register URI scheme if it already exists Change from register_uri_scheme to try_register_uri_scheme, which doesn't attempt to register if we already know that one with the same name was registered to the WebContext before. Without this change, I get this error from WebKitGTK: ** (tauri-app:[...]): CRITICAL **: 14:03:50.040: Cannot register URI scheme tauri more than once It doesn't seem to affect functionality, but better to issue a more appropriate warning on our side. --- src/webview/webkitgtk/mod.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/webview/webkitgtk/mod.rs b/src/webview/webkitgtk/mod.rs index 110731b96..cf49acc35 100644 --- a/src/webview/webkitgtk/mod.rs +++ b/src/webview/webkitgtk/mod.rs @@ -343,10 +343,11 @@ impl InnerWebView { } for (name, handler) in attributes.custom_protocols { - match web_context.register_uri_scheme(&name, handler) { + match web_context.try_register_uri_scheme(&name, handler) { // Swallow duplicate scheme errors to preserve current behavior. - // FIXME: we should log this error in the future - Err(Error::DuplicateCustomProtocol(_)) => (), + Err(Error::DuplicateCustomProtocol(_)) => { + log::warn!("Ignoring already registered custom protocol {name}"); + } Err(e) => return Err(e), Ok(_) => (), } From d119e2068ce27e20cd70d6c84c630c276ba07932 Mon Sep 17 00:00:00 2001 From: Roope Salmi Date: Wed, 24 Jul 2024 15:14:19 +0300 Subject: [PATCH 3/7] chore: changelog entry for Linux shared WebContext fix --- .changes/linux-shared-webcontext-ipc.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changes/linux-shared-webcontext-ipc.md diff --git a/.changes/linux-shared-webcontext-ipc.md b/.changes/linux-shared-webcontext-ipc.md new file mode 100644 index 000000000..bcb966ffd --- /dev/null +++ b/.changes/linux-shared-webcontext-ipc.md @@ -0,0 +1,5 @@ +--- +"wry": patch +--- + +Fix Linux IPC handler and initialization scripts when sharing a WebContext between multiple WebViews. From 70e0990ee88969a576ba2b6d5cdaf1c6f0670b1f Mon Sep 17 00:00:00 2001 From: Amr Bashir Date: Thu, 22 Aug 2024 02:34:18 +0300 Subject: [PATCH 4/7] Update src/webview/webkitgtk/mod.rs --- src/webview/webkitgtk/mod.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/webview/webkitgtk/mod.rs b/src/webview/webkitgtk/mod.rs index cf49acc35..1fc042c72 100644 --- a/src/webview/webkitgtk/mod.rs +++ b/src/webview/webkitgtk/mod.rs @@ -335,7 +335,11 @@ impl InnerWebView { }; // Initialize message handler - w.init("Object.defineProperty(window, 'ipc', { value: Object.freeze({ postMessage: function(x) { window.webkit.messageHandlers['ipc'].postMessage(x) } }) })")?; + let mut init = String::with_capacity(115 + 20 + 22); + init.push_str("Object.defineProperty(window, 'ipc', {value: Object.freeze({postMessage:function(x){window.webkit.messageHandlers[\""); + init.push_str(&window_hash); + init.push_str("\"].postMessage(x)}})})"); + w.init(&init)?; // Initialize scripts for js in attributes.initialization_scripts { From 42c5dd0a2266a3008e7c549dca7b108af0d3cde1 Mon Sep 17 00:00:00 2001 From: Amr Bashir Date: Thu, 22 Aug 2024 02:48:30 +0300 Subject: [PATCH 5/7] Update src/webview/webkitgtk/mod.rs --- src/webview/webkitgtk/mod.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/webview/webkitgtk/mod.rs b/src/webview/webkitgtk/mod.rs index 1fc042c72..ea8e70257 100644 --- a/src/webview/webkitgtk/mod.rs +++ b/src/webview/webkitgtk/mod.rs @@ -78,7 +78,13 @@ impl InnerWebView { let webview = Rc::new(webview); let w = window_rc.clone(); let ipc_handler = attributes.ipc_handler.take(); - + // Use the window hash as the script handler name to prevent from conflict when sharing same + // web context. + let window_hash = { + let mut hasher = DefaultHasher::new(); + w.id().hash(&mut hasher); + hasher.finish().to_string() + }; // Connect before registering as recommended by the docs manager.connect_script_message_received(None, move |_m, msg| { #[cfg(feature = "tracing")] From bb9f35905648759333dc037f3bfa85aa236e3fce Mon Sep 17 00:00:00 2001 From: Amr Bashir Date: Thu, 22 Aug 2024 02:48:59 +0300 Subject: [PATCH 6/7] Update src/webview/webkitgtk/mod.rs --- src/webview/webkitgtk/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/webview/webkitgtk/mod.rs b/src/webview/webkitgtk/mod.rs index ea8e70257..c9328ee73 100644 --- a/src/webview/webkitgtk/mod.rs +++ b/src/webview/webkitgtk/mod.rs @@ -85,6 +85,7 @@ impl InnerWebView { w.id().hash(&mut hasher); hasher.finish().to_string() }; + // Connect before registering as recommended by the docs manager.connect_script_message_received(None, move |_m, msg| { #[cfg(feature = "tracing")] From c3900d728c3a36f0bd9e02cb333739d3eb7b4df0 Mon Sep 17 00:00:00 2001 From: Amr Bashir Date: Thu, 22 Aug 2024 02:53:50 +0300 Subject: [PATCH 7/7] Update src/webview/webkitgtk/mod.rs --- src/webview/webkitgtk/mod.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/webview/webkitgtk/mod.rs b/src/webview/webkitgtk/mod.rs index c9328ee73..6fc0212fd 100644 --- a/src/webview/webkitgtk/mod.rs +++ b/src/webview/webkitgtk/mod.rs @@ -9,6 +9,8 @@ use gtk::prelude::*; #[cfg(any(debug_assertions, feature = "devtools"))] use std::sync::atomic::{AtomicBool, Ordering}; use std::{ + collections::hash_map::DefaultHasher, + hash::{Hash, Hasher}, rc::Rc, sync::{Arc, Mutex}, };