diff --git a/.changes/fix-cookies-deadlock.md b/.changes/fix-cookies-deadlock.md new file mode 100644 index 000000000..32dd57429 --- /dev/null +++ b/.changes/fix-cookies-deadlock.md @@ -0,0 +1,5 @@ +--- +"wry": patch +--- + +Fix `Webview::cookies` and `Webview::cookies_for_url` deadlock on macOS. \ No newline at end of file diff --git a/src/wkwebview/mod.rs b/src/wkwebview/mod.rs index b80bae84c..0a99f80bf 100644 --- a/src/wkwebview/mod.rs +++ b/src/wkwebview/mod.rs @@ -79,6 +79,7 @@ use std::{ ptr::{null_mut, NonNull}, str::{self, FromStr}, sync::{Arc, Mutex}, + time::Duration, }; #[cfg(feature = "mac-proxy")] @@ -1054,24 +1055,31 @@ unsafe fn window_position(view: &NSView, x: i32, y: i32, height: f64) -> CGPoint CGPoint::new(x as f64, frame.size.height - y as f64 - height) } +/// Wait synchronously for the NSRunLoop to run until a receiver has a message. unsafe fn wait_for_blocking_operation(rx: std::sync::mpsc::Receiver) -> Result { - let interval = 0.0002; + let interval = Duration::from_millis(2); + let interval_as_secs = interval.as_secs_f64(); let limit = 1.; let mut elapsed = 0.; // run event loop until we get the response back, blocking for at most 3 seconds loop { - let rl = objc2_foundation::NSRunLoop::mainRunLoop(); - let d = NSDate::dateWithTimeIntervalSinceNow(interval); - rl.runUntilDate(&d); - if let Ok(response) = rx.try_recv() { + if let Ok(response) = rx.recv_timeout(interval) { return Ok(response); } - elapsed += interval; + elapsed += interval_as_secs; if elapsed >= limit { return Err(Error::Io(std::io::Error::new( std::io::ErrorKind::TimedOut, "timed out waiting for cookies response", ))); } + + // Go progress the event loop if we didn't get the result + let rl = objc2_foundation::NSRunLoop::mainRunLoop(); + let limit_date = NSDate::dateWithTimeIntervalSinceNow(interval_as_secs); + + let mode = NSString::from_str("NSDefaultRunLoopMode"); + + rl.acceptInputForMode_beforeDate(&mode, &limit_date); } }