浏览代码

fix(core/ipc): access url through webview native object, closes #6889 (#6976)

Amr Bashir 2 年之前
父节点
当前提交
aecf146909

+ 5 - 0
.changes/core-ipc-failed-navigation.md

@@ -0,0 +1,5 @@
+---
+'tauri': 'patch'
+---
+
+Fix IPC failing after a failed navigation to an external URL.

+ 2 - 9
core/tauri-runtime-wry/src/lib.rs

@@ -214,7 +214,6 @@ impl<T: UserEvent> Context<T> {
 impl<T: UserEvent> Context<T> {
   fn create_webview(&self, pending: PendingWindow<T, Wry<T>>) -> Result<DetachedWindow<T, Wry<T>>> {
     let label = pending.label.clone();
-    let current_url = pending.current_url.clone();
     let menu_ids = pending.menu_ids.clone();
     let js_event_listeners = pending.js_event_listeners.clone();
     let context = self.clone();
@@ -236,7 +235,6 @@ impl<T: UserEvent> Context<T> {
     };
     Ok(DetachedWindow {
       label,
-      current_url,
       dispatcher,
       menu_ids,
       js_event_listeners,
@@ -1987,7 +1985,6 @@ impl<T: UserEvent> Runtime<T> for Wry<T> {
 
   fn create_window(&self, pending: PendingWindow<T, Self>) -> Result<DetachedWindow<T, Self>> {
     let label = pending.label.clone();
-    let current_url = pending.current_url.clone();
     let menu_ids = pending.menu_ids.clone();
     let js_event_listeners = pending.js_event_listeners.clone();
     let window_id = rand::random();
@@ -2014,7 +2011,6 @@ impl<T: UserEvent> Runtime<T> for Wry<T> {
 
     Ok(DetachedWindow {
       label,
-      current_url,
       dispatcher,
       menu_ids,
       js_event_listeners,
@@ -3044,7 +3040,7 @@ fn create_webview<T: UserEvent>(
     mut window_builder,
     ipc_handler,
     label,
-    current_url,
+    url,
     menu_ids,
     js_event_listeners,
     ..
@@ -3093,7 +3089,7 @@ fn create_webview<T: UserEvent>(
   }
   let mut webview_builder = WebViewBuilder::new(window)
     .map_err(|e| Error::CreateWebview(Box::new(e)))?
-    .with_url(current_url.lock().unwrap().as_str())
+    .with_url(&url)
     .unwrap() // safe to unwrap because we validate the URL beforehand
     .with_transparent(is_window_transparent)
     .with_accept_first_mouse(webview_attributes.accept_first_mouse);
@@ -3128,7 +3124,6 @@ fn create_webview<T: UserEvent>(
     webview_builder = webview_builder.with_ipc_handler(create_ipc_handler(
       context,
       label.clone(),
-      current_url,
       menu_ids,
       js_event_listeners,
       handler,
@@ -3239,7 +3234,6 @@ fn create_webview<T: UserEvent>(
 fn create_ipc_handler<T: UserEvent>(
   context: Context<T>,
   label: String,
-  current_url: Arc<Mutex<Url>>,
   menu_ids: Arc<Mutex<HashMap<MenuHash, MenuId>>>,
   js_event_listeners: Arc<Mutex<HashMap<JsEventListenerKey, HashSet<u64>>>>,
   handler: WebviewIpcHandler<T, Wry<T>>,
@@ -3248,7 +3242,6 @@ fn create_ipc_handler<T: UserEvent>(
     let window_id = context.webview_id_map.get(&window.id()).unwrap();
     handler(
       DetachedWindow {
-        current_url: current_url.clone(),
         dispatcher: WryDispatcher {
           window_id,
           context: context.clone(),

+ 4 - 8
core/tauri-runtime/src/window.rs

@@ -238,8 +238,8 @@ pub struct PendingWindow<T: UserEvent, R: Runtime<T>> {
 
   pub web_resource_request_handler: Option<Box<WebResourceRequestHandler>>,
 
-  /// The current webview URL.
-  pub current_url: Arc<Mutex<Url>>,
+  /// The resolved URL to load on the webview.
+  pub url: String,
 }
 
 pub fn is_label_valid(label: &str) -> bool {
@@ -280,7 +280,7 @@ impl<T: UserEvent, R: Runtime<T>> PendingWindow<T, R> {
         js_event_listeners: Default::default(),
         navigation_handler: Default::default(),
         web_resource_request_handler: Default::default(),
-        current_url: Arc::new(Mutex::new("tauri://localhost".parse().unwrap())),
+        url: "tauri://localhost".to_string(),
       })
     }
   }
@@ -311,7 +311,7 @@ impl<T: UserEvent, R: Runtime<T>> PendingWindow<T, R> {
         js_event_listeners: Default::default(),
         navigation_handler: Default::default(),
         web_resource_request_handler: Default::default(),
-        current_url: Arc::new(Mutex::new("tauri://localhost".parse().unwrap())),
+        url: "tauri://localhost".to_string(),
       })
     }
   }
@@ -352,9 +352,6 @@ pub struct JsEventListenerKey {
 /// A webview window that is not yet managed by Tauri.
 #[derive(Debug)]
 pub struct DetachedWindow<T: UserEvent, R: Runtime<T>> {
-  /// The current webview URL.
-  pub current_url: Arc<Mutex<Url>>,
-
   /// Name of the window
   pub label: String,
 
@@ -371,7 +368,6 @@ pub struct DetachedWindow<T: UserEvent, R: Runtime<T>> {
 impl<T: UserEvent, R: Runtime<T>> Clone for DetachedWindow<T, R> {
   fn clone(&self) -> Self {
     Self {
-      current_url: self.current_url.clone(),
       label: self.label.clone(),
       dispatcher: self.dispatcher.clone(),
       menu_ids: self.menu_ids.clone(),

+ 2 - 4
core/tauri/src/manager.rs

@@ -470,7 +470,7 @@ impl<R: Runtime> WindowManager<R> {
       });
     }
 
-    let window_url = pending.current_url.lock().unwrap().clone();
+    let window_url = Url::parse(&pending.url).unwrap();
     let window_origin =
       if cfg!(windows) && window_url.scheme() != "http" && window_url.scheme() != "https" {
         format!("https://{}.localhost", window_url.scheme())
@@ -1165,7 +1165,7 @@ impl<R: Runtime> WindowManager<R> {
       }
     }
 
-    *pending.current_url.lock().unwrap() = url;
+    pending.url = url.to_string();
 
     if !pending.window_builder.has_icon() {
       if let Some(default_window_icon) = self.inner.default_window_icon.clone() {
@@ -1210,7 +1210,6 @@ impl<R: Runtime> WindowManager<R> {
 
     #[cfg(feature = "isolation")]
     let pattern = self.pattern().clone();
-    let current_url_ = pending.current_url.clone();
     let navigation_handler = pending.navigation_handler.take();
     pending.navigation_handler = Some(Box::new(move |url| {
       // always allow navigation events for the isolation iframe and do not emit them for consumers
@@ -1222,7 +1221,6 @@ impl<R: Runtime> WindowManager<R> {
           return true;
         }
       }
-      *current_url_.lock().unwrap() = url.clone();
       if let Some(handler) = &navigation_handler {
         handler(url)
       } else {

+ 7 - 7
core/tauri/src/scope/ipc.rs

@@ -260,7 +260,7 @@ mod tests {
 
   #[test]
   fn scope_not_defined() {
-    let (_app, window) = test_context(vec![RemoteDomainAccessScope::new("app.tauri.app")
+    let (_app, mut window) = test_context(vec![RemoteDomainAccessScope::new("app.tauri.app")
       .add_window("other")
       .enable_tauri_api()]);
 
@@ -277,7 +277,7 @@ mod tests {
 
   #[test]
   fn scope_not_defined_for_window() {
-    let (_app, window) = test_context(vec![RemoteDomainAccessScope::new("tauri.app")
+    let (_app, mut window) = test_context(vec![RemoteDomainAccessScope::new("tauri.app")
       .add_window("second")
       .enable_tauri_api()]);
 
@@ -291,7 +291,7 @@ mod tests {
 
   #[test]
   fn scope_not_defined_for_url() {
-    let (_app, window) = test_context(vec![RemoteDomainAccessScope::new("github.com")
+    let (_app, mut window) = test_context(vec![RemoteDomainAccessScope::new("github.com")
       .add_window("main")
       .enable_tauri_api()]);
 
@@ -353,7 +353,7 @@ mod tests {
 
   #[test]
   fn subpath_is_allowed() {
-    let (app, window) = test_context(vec![RemoteDomainAccessScope::new("tauri.app")
+    let (app, mut window) = test_context(vec![RemoteDomainAccessScope::new("tauri.app")
       .add_window("main")
       .enable_tauri_api()]);
 
@@ -367,7 +367,7 @@ mod tests {
 
   #[test]
   fn tauri_api_not_allowed() {
-    let (_app, window) = test_context(vec![
+    let (_app, mut window) = test_context(vec![
       RemoteDomainAccessScope::new("tauri.app").add_window("main")
     ]);
 
@@ -381,7 +381,7 @@ mod tests {
 
   #[test]
   fn plugin_allowed() {
-    let (_app, window) = test_context(vec![RemoteDomainAccessScope::new("tauri.app")
+    let (_app, mut window) = test_context(vec![RemoteDomainAccessScope::new("tauri.app")
       .add_window("main")
       .add_plugin(PLUGIN_NAME)]);
 
@@ -395,7 +395,7 @@ mod tests {
 
   #[test]
   fn plugin_not_allowed() {
-    let (_app, window) = test_context(vec![
+    let (_app, mut window) = test_context(vec![
       RemoteDomainAccessScope::new("tauri.app").add_window("main")
     ]);
 

+ 0 - 2
core/tauri/src/test/mock_runtime.rs

@@ -69,7 +69,6 @@ impl<T: UserEvent> RuntimeHandle<T> for MockRuntimeHandle {
   ) -> Result<DetachedWindow<T, Self::Runtime>> {
     Ok(DetachedWindow {
       label: pending.label,
-      current_url: Arc::new(Mutex::new("tauri://localhost".parse().unwrap())),
       dispatcher: MockDispatcher {
         context: self.context.clone(),
         last_evaluated_script: Default::default(),
@@ -703,7 +702,6 @@ impl<T: UserEvent> Runtime<T> for MockRuntime {
   fn create_window(&self, pending: PendingWindow<T, Self>) -> Result<DetachedWindow<T, Self>> {
     Ok(DetachedWindow {
       label: pending.label,
-      current_url: Arc::new(Mutex::new("tauri://localhost".parse().unwrap())),
       dispatcher: MockDispatcher {
         context: self.context.clone(),
         last_evaluated_script: Default::default(),

+ 17 - 3
core/tauri/src/window.rs

@@ -681,6 +681,9 @@ pub struct Window<R: Runtime> {
   /// The manager to associate this webview window with.
   manager: WindowManager<R>,
   pub(crate) app_handle: AppHandle<R>,
+
+  #[cfg(test)]
+  pub(crate) current_url: url::Url,
 }
 
 unsafe impl<R: Runtime> raw_window_handle::HasRawWindowHandle for Window<R> {
@@ -695,6 +698,8 @@ impl<R: Runtime> Clone for Window<R> {
       window: self.window.clone(),
       manager: self.manager.clone(),
       app_handle: self.app_handle.clone(),
+      #[cfg(test)]
+      current_url: self.current_url.clone(),
     }
   }
 }
@@ -891,6 +896,8 @@ impl<R: Runtime> Window<R> {
       window,
       manager,
       app_handle,
+      #[cfg(test)]
+      current_url: "http://tauri.app".parse().unwrap(),
     }
   }
 
@@ -1383,13 +1390,20 @@ impl<R: Runtime> Window<R> {
 /// Webview APIs.
 impl<R: Runtime> Window<R> {
   /// Returns the current url of the webview.
+  // TODO: in v2, change this type to Result
+  #[cfg(not(test))]
+  pub fn url(&self) -> Url {
+    self.window.dispatcher.url().unwrap()
+  }
+
+  #[cfg(test)]
   pub fn url(&self) -> Url {
-    self.window.current_url.lock().unwrap().clone()
+    self.current_url.clone()
   }
 
   #[cfg(test)]
-  pub(crate) fn navigate(&self, url: Url) {
-    *self.window.current_url.lock().unwrap() = url;
+  pub(crate) fn navigate(&mut self, url: Url) {
+    self.current_url = url;
   }
 
   /// Handles this window receiving an [`InvokeMessage`].