From 110439a58ab558c752c4928c614b835742a37243 Mon Sep 17 00:00:00 2001 From: amrbashir Date: Wed, 18 Sep 2024 07:02:36 +0300 Subject: [PATCH 1/4] fix(core): share webcontext between webviews closes #10981 --- .changes/share-webcontext.md | 7 +++++ Cargo.lock | 3 +- crates/tauri-runtime-wry/Cargo.toml | 2 +- crates/tauri-runtime-wry/src/lib.rs | 44 ++++++++++++++--------------- 4 files changed, 31 insertions(+), 25 deletions(-) create mode 100644 .changes/share-webcontext.md diff --git a/.changes/share-webcontext.md b/.changes/share-webcontext.md new file mode 100644 index 000000000000..b86bbf2f0894 --- /dev/null +++ b/.changes/share-webcontext.md @@ -0,0 +1,7 @@ +--- +"tauri": "patch:bug" +"tauri-runtime-wry": "patch:bug" +--- + +Fix `localStorage` not shared between webviews that use the same data directory. + diff --git a/Cargo.lock b/Cargo.lock index befd86f0aeac..2f7d4c0662a0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9450,8 +9450,7 @@ dependencies = [ [[package]] name = "wry" version = "0.43.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4d715cf5fe88e9647f3d17b207b6d060d4a88e7171d4ccb2d2c657dd1d44728" +source = "git+https://github.com/tauri-apps/wry?branch=refactor/error-duplicate-custom-protocols#9a10e28b0cd8c47a1bc65665c90aa25ce0f3b787" dependencies = [ "base64 0.22.1", "block", diff --git a/crates/tauri-runtime-wry/Cargo.toml b/crates/tauri-runtime-wry/Cargo.toml index 3a6f357ada71..5d9f2083c0a9 100644 --- a/crates/tauri-runtime-wry/Cargo.toml +++ b/crates/tauri-runtime-wry/Cargo.toml @@ -17,7 +17,7 @@ rustc-args = ["--cfg", "docsrs"] rustdoc-args = ["--cfg", "docsrs"] [dependencies] -wry = { version = "0.43.1", default-features = false, features = [ +wry = { git = "https://github.com/tauri-apps/wry", branch = "refactor/error-duplicate-custom-protocols", default-features = false, features = [ "drag-drop", "protocol", "os-webview", diff --git a/crates/tauri-runtime-wry/src/lib.rs b/crates/tauri-runtime-wry/src/lib.rs index 6718aafdf79b..508e717ae273 100644 --- a/crates/tauri-runtime-wry/src/lib.rs +++ b/crates/tauri-runtime-wry/src/lib.rs @@ -101,7 +101,7 @@ use std::{ cell::RefCell, collections::{ hash_map::Entry::{Occupied, Vacant}, - BTreeMap, HashMap, + BTreeMap, HashMap, HashSet, }, fmt, ops::Deref, @@ -131,7 +131,7 @@ mod undecorated_resizing; mod webview; pub use webview::Webview; -pub type WebContextStore = Arc, WebContext>>>; +pub type WebContextStore = Arc, (WebContext, HashSet)>>>; // window pub type WindowEventHandler = Box; pub type WindowEventListeners = Arc>>; @@ -216,7 +216,6 @@ pub struct Context { next_webview_id: Arc, next_window_event_id: Arc, next_webview_event_id: Arc, - next_webcontext_id: Arc, } impl Context { @@ -246,10 +245,6 @@ impl Context { fn next_webview_event_id(&self) -> u32 { self.next_webview_event_id.fetch_add(1, Ordering::Relaxed) } - - fn next_webcontext_id(&self) -> u32 { - self.next_webcontext_id.fetch_add(1, Ordering::Relaxed) - } } impl Context { @@ -2036,7 +2031,15 @@ impl Deref for WebviewWrapper { impl Drop for WebviewWrapper { fn drop(&mut self) { if Rc::get_mut(&mut self.inner).is_some() { - self.context_store.lock().unwrap().remove(&self.context_key); + let mut context_store = self.context_store.lock().unwrap(); + + if let Some((_, label_store)) = context_store.get_mut(&self.context_key) { + label_store.remove(&self.label); + + if label_store.is_empty() { + context_store.remove(&self.context_key); + } + } } } } @@ -2345,7 +2348,6 @@ impl Wry { next_webview_id: Default::default(), next_window_event_id: Default::default(), next_webview_event_id: Default::default(), - next_webcontext_id: Default::default(), }; Ok(Self { @@ -4101,27 +4103,25 @@ fn create_webview( .lock() .expect("poisoned WebContext store"); let is_first_context = web_context.is_empty(); + // force a unique WebContext when automation is false; + // the context must be stored on the HashMap because it must outlive the WebView on macOS let automation_enabled = std::env::var("TAURI_WEBVIEW_AUTOMATION").as_deref() == Ok("true"); - let web_context_key = // force a unique WebContext when automation is false; - // the context must be stored on the HashMap because it must outlive the WebView on macOS - if automation_enabled { - webview_attributes.data_directory.clone() - } else { - // unique key - let key = context.next_webcontext_id().to_string().into(); - Some(key) - }; + let web_context_key = webview_attributes.data_directory; let entry = web_context.entry(web_context_key.clone()); - let web_context = match entry { - Occupied(occupied) => occupied.into_mut(), + let (web_context, _) = match entry { + Occupied(occupied) => { + let occupied = occupied.into_mut(); + occupied.1.insert(label.clone()); + occupied + } Vacant(vacant) => { - let mut web_context = WebContext::new(webview_attributes.data_directory); + let mut web_context = WebContext::new(web_context_key.clone()); web_context.set_allows_automation(if automation_enabled { is_first_context } else { false }); - vacant.insert(web_context) + vacant.insert((web_context, [label.clone()].into())) } }; From 74eaf0dfad14de45603d8a002a7d67bd692d071b Mon Sep 17 00:00:00 2001 From: amrbashir Date: Wed, 18 Sep 2024 07:42:45 +0300 Subject: [PATCH 2/4] update wry version --- Cargo.lock | 5 +++-- crates/tauri-runtime-wry/Cargo.toml | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2f7d4c0662a0..959a72bde65d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9449,8 +9449,9 @@ dependencies = [ [[package]] name = "wry" -version = "0.43.1" -source = "git+https://github.com/tauri-apps/wry?branch=refactor/error-duplicate-custom-protocols#9a10e28b0cd8c47a1bc65665c90aa25ce0f3b787" +version = "0.44.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d7e385ebabe006332d3863482297408cb39d778db41009f50896ac356d8c49e" dependencies = [ "base64 0.22.1", "block", diff --git a/crates/tauri-runtime-wry/Cargo.toml b/crates/tauri-runtime-wry/Cargo.toml index 5d9f2083c0a9..4d745fbba680 100644 --- a/crates/tauri-runtime-wry/Cargo.toml +++ b/crates/tauri-runtime-wry/Cargo.toml @@ -17,7 +17,7 @@ rustc-args = ["--cfg", "docsrs"] rustdoc-args = ["--cfg", "docsrs"] [dependencies] -wry = { git = "https://github.com/tauri-apps/wry", branch = "refactor/error-duplicate-custom-protocols", default-features = false, features = [ +wry = { version = "0.44", default-features = false, features = [ "drag-drop", "protocol", "os-webview", From 9ca0374e0a8c155937c641eb69f51605b13673cf Mon Sep 17 00:00:00 2001 From: Lucas Fernandes Nogueira Date: Fri, 20 Sep 2024 08:24:09 -0300 Subject: [PATCH 3/4] Update crates/tauri-runtime-wry/src/lib.rs [skip ci] --- crates/tauri-runtime-wry/src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/crates/tauri-runtime-wry/src/lib.rs b/crates/tauri-runtime-wry/src/lib.rs index 24f95e19751e..27c4fdbeebdc 100644 --- a/crates/tauri-runtime-wry/src/lib.rs +++ b/crates/tauri-runtime-wry/src/lib.rs @@ -4109,7 +4109,6 @@ fn create_webview( .lock() .expect("poisoned WebContext store"); let is_first_context = web_context.is_empty(); - // force a unique WebContext when automation is false; // the context must be stored on the HashMap because it must outlive the WebView on macOS let automation_enabled = std::env::var("TAURI_WEBVIEW_AUTOMATION").as_deref() == Ok("true"); let web_context_key = webview_attributes.data_directory; From 193dc4e35ad4caa5ca51d30c807508656679798a Mon Sep 17 00:00:00 2001 From: Lucas Nogueira Date: Sat, 21 Sep 2024 07:28:16 -0300 Subject: [PATCH 4/4] on linux, only register protocol once per context --- crates/tauri-runtime-wry/src/lib.rs | 73 ++++++++++++++++++++--------- 1 file changed, 52 insertions(+), 21 deletions(-) diff --git a/crates/tauri-runtime-wry/src/lib.rs b/crates/tauri-runtime-wry/src/lib.rs index 27c4fdbeebdc..fe9daab805d2 100644 --- a/crates/tauri-runtime-wry/src/lib.rs +++ b/crates/tauri-runtime-wry/src/lib.rs @@ -66,8 +66,8 @@ use tauri_utils::TitleBarStyle; use tauri_utils::{config::WindowConfig, Theme}; use url::Url; use wry::{ - DragDropEvent as WryDragDropEvent, ProxyConfig, ProxyEndpoint, WebContext, WebView, - WebViewBuilder, + DragDropEvent as WryDragDropEvent, ProxyConfig, ProxyEndpoint, WebContext as WryWebContext, + WebView, WebViewBuilder, }; pub use tao; @@ -131,7 +131,16 @@ mod undecorated_resizing; mod webview; pub use webview::Webview; -pub type WebContextStore = Arc, (WebContext, HashSet)>>>; +#[derive(Debug)] +pub struct WebContext { + pub inner: WryWebContext, + pub referenced_by_webviews: HashSet, + // on Linux the custom protocols are associated with the context + // and you cannot register a URI scheme more than once + pub registered_custom_protocols: HashSet, +} + +pub type WebContextStore = Arc, WebContext>>>; // window pub type WindowEventHandler = Box; pub type WindowEventListeners = Arc>>; @@ -2033,10 +2042,10 @@ impl Drop for WebviewWrapper { if Rc::get_mut(&mut self.inner).is_some() { let mut context_store = self.context_store.lock().unwrap(); - if let Some((_, label_store)) = context_store.get_mut(&self.context_key) { - label_store.remove(&self.label); + if let Some(web_context) = context_store.get_mut(&self.context_key) { + web_context.referenced_by_webviews.remove(&self.label); - if label_store.is_empty() { + if web_context.referenced_by_webviews.is_empty() { context_store.remove(&self.context_key); } } @@ -4089,16 +4098,6 @@ fn create_webview( ipc_handler, )); - for (scheme, protocol) in uri_scheme_protocols { - webview_builder = - webview_builder.with_asynchronous_custom_protocol(scheme, move |request, responder| { - protocol( - request, - Box::new(move |response| responder.respond(response)), - ) - }); - } - for script in webview_attributes.initialization_scripts { webview_builder = webview_builder.with_initialization_script(&script); } @@ -4113,23 +4112,55 @@ fn create_webview( let automation_enabled = std::env::var("TAURI_WEBVIEW_AUTOMATION").as_deref() == Ok("true"); let web_context_key = webview_attributes.data_directory; let entry = web_context.entry(web_context_key.clone()); - let (web_context, _) = match entry { + let web_context = match entry { Occupied(occupied) => { let occupied = occupied.into_mut(); - occupied.1.insert(label.clone()); + occupied.referenced_by_webviews.insert(label.clone()); occupied } Vacant(vacant) => { - let mut web_context = WebContext::new(web_context_key.clone()); + let mut web_context = WryWebContext::new(web_context_key.clone()); web_context.set_allows_automation(if automation_enabled { is_first_context } else { false }); - vacant.insert((web_context, [label.clone()].into())) + vacant.insert(WebContext { + inner: web_context, + referenced_by_webviews: [label.clone()].into(), + registered_custom_protocols: HashSet::new(), + }) } }; + for (scheme, protocol) in uri_scheme_protocols { + // on Linux the custom protocols are associated with the web context + // and you cannot register a scheme more than once + if cfg!(any( + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd" + )) { + if web_context.registered_custom_protocols.contains(&scheme) { + continue; + } + + web_context + .registered_custom_protocols + .insert(scheme.clone()); + } + + webview_builder = + webview_builder.with_asynchronous_custom_protocol(scheme, move |request, responder| { + protocol( + request, + Box::new(move |response| responder.respond(response)), + ) + }); + } + if webview_attributes.clipboard { webview_builder.attrs.clipboard = true; } @@ -4157,7 +4188,7 @@ fn create_webview( } let webview = webview_builder - .with_web_context(web_context) + .with_web_context(&mut web_context.inner) .build() .map_err(|e| Error::CreateWebview(Box::new(e)))?;