fix: fix incorrect label passed to ipc protocol (#11268)

* fix: fix incorrect label passed to `ipc` protocol

closes #11171

* update lock file

* Update .changes/incorrect-label-linux-command.md

Co-authored-by: Lucas Fernandes Nogueira <lucas@tauri.app>

* Update .changes/incorrect-label-linux-protocol.md

Co-authored-by: Lucas Fernandes Nogueira <lucas@tauri.app>

* clippy

* try wry from dev

* fix macos build

* fix ios build

* update wry

* Update .changes/incorrect-label-linux-command.md

* wry 0.46

---------

Co-authored-by: Lucas Fernandes Nogueira <lucas@tauri.app>
This commit is contained in:
Amr Bashir
2024-10-12 13:46:51 +03:00
committed by GitHub
parent 069c05e44f
commit 2d087ee4b7
13 changed files with 264 additions and 148 deletions

View File

@@ -0,0 +1,7 @@
---
"tauri": "patch:bug"
"tauri-runtime": "minor:bug"
"tauri-runtime-wry": "minor:bug"
---
On Linux, fix commands, that use `Webview` or `WebviewWindow` as an argument, receiving an incorrect webview when using multi webviews.

View File

@@ -0,0 +1,7 @@
---
"tauri": "minor:bug"
"tauri-runtime": "minor:bug"
"tauri-runtime-wry": "minor:bug"
---
On Linux, fix events only emitted to first webview only when using multi webviews.

View File

@@ -0,0 +1,7 @@
---
"tauri": "minor:bug"
"tauri-runtime": "minor:bug"
"tauri-runtime-wry": "minor:bug"
---
On Linux, fix custom protocols receiving an incorrect webview label when using multi webviews

140
Cargo.lock generated
View File

@@ -5411,7 +5411,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1"
dependencies = [
"malloc_buf",
"objc_exception",
]
[[package]]
@@ -5419,6 +5418,9 @@ name = "objc-sys"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cdb91bdd390c7ce1a8607f35f3ca7151b65afc0ff5ff3b34fa350f7d7c7e4310"
dependencies = [
"cc",
]
[[package]]
name = "objc2"
@@ -5446,6 +5448,30 @@ dependencies = [
"objc2-quartz-core",
]
[[package]]
name = "objc2-cloud-kit"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "74dd3b56391c7a0596a295029734d3c1c5e7e510a4cb30245f8221ccea96b009"
dependencies = [
"bitflags 2.6.0",
"block2",
"objc2",
"objc2-core-location",
"objc2-foundation",
]
[[package]]
name = "objc2-contacts"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a5ff520e9c33812fd374d8deecef01d4a840e7b41862d849513de77e44aa4889"
dependencies = [
"block2",
"objc2",
"objc2-foundation",
]
[[package]]
name = "objc2-core-data"
version = "0.2.2"
@@ -5470,6 +5496,18 @@ dependencies = [
"objc2-metal",
]
[[package]]
name = "objc2-core-location"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "000cfee34e683244f284252ee206a27953279d370e309649dc3ee317b37e5781"
dependencies = [
"block2",
"objc2",
"objc2-contacts",
"objc2-foundation",
]
[[package]]
name = "objc2-encode"
version = "4.0.3"
@@ -5488,6 +5526,18 @@ dependencies = [
"objc2",
]
[[package]]
name = "objc2-link-presentation"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1a1ae721c5e35be65f01a03b6d2ac13a54cb4fa70d8a5da293d7b0020261398"
dependencies = [
"block2",
"objc2",
"objc2-app-kit",
"objc2-foundation",
]
[[package]]
name = "objc2-metal"
version = "0.2.2"
@@ -5513,6 +5563,61 @@ dependencies = [
"objc2-metal",
]
[[package]]
name = "objc2-symbols"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0a684efe3dec1b305badae1a28f6555f6ddd3bb2c2267896782858d5a78404dc"
dependencies = [
"objc2",
"objc2-foundation",
]
[[package]]
name = "objc2-ui-kit"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8bb46798b20cd6b91cbd113524c490f1686f4c4e8f49502431415f3512e2b6f"
dependencies = [
"bitflags 2.6.0",
"block2",
"objc2",
"objc2-cloud-kit",
"objc2-core-data",
"objc2-core-image",
"objc2-core-location",
"objc2-foundation",
"objc2-link-presentation",
"objc2-quartz-core",
"objc2-symbols",
"objc2-uniform-type-identifiers",
"objc2-user-notifications",
]
[[package]]
name = "objc2-uniform-type-identifiers"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "44fa5f9748dbfe1ca6c0b79ad20725a11eca7c2218bceb4b005cb1be26273bfe"
dependencies = [
"block2",
"objc2",
"objc2-foundation",
]
[[package]]
name = "objc2-user-notifications"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "76cfcbf642358e8689af64cee815d139339f3ed8ad05103ed5eaf73db8d84cb3"
dependencies = [
"bitflags 2.6.0",
"block2",
"objc2",
"objc2-core-location",
"objc2-foundation",
]
[[package]]
name = "objc2-web-kit"
version = "0.2.2"
@@ -5526,24 +5631,6 @@ dependencies = [
"objc2-foundation",
]
[[package]]
name = "objc_exception"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ad970fb455818ad6cba4c122ad012fae53ae8b4795f86378bce65e4f6bab2ca4"
dependencies = [
"cc",
]
[[package]]
name = "objc_id"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c92d4ddb4bd7b50d730c215ff871754d0da6b2178849f8a2a2ab69712d0c073b"
dependencies = [
"objc",
]
[[package]]
name = "object"
version = "0.32.2"
@@ -10918,14 +11005,12 @@ dependencies = [
[[package]]
name = "wry"
version = "0.44.1"
version = "0.46.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "440600584cfbd8b0d28eace95c1f2c253db05dae43780b79380aa1e868f04c73"
checksum = "469a3765ecc3e8aa9ccdf3c5a52c82697ec03037cd60494488763880d31a1b3a"
dependencies = [
"base64 0.22.1",
"block",
"cocoa 0.26.0",
"core-graphics 0.24.0",
"block2",
"crossbeam-channel",
"dpi",
"dunce",
@@ -10938,8 +11023,11 @@ dependencies = [
"kuchikiki",
"libc",
"ndk",
"objc",
"objc_id",
"objc2",
"objc2-app-kit",
"objc2-foundation",
"objc2-ui-kit",
"objc2-web-kit",
"once_cell",
"percent-encoding",
"raw-window-handle",

View File

@@ -17,7 +17,7 @@ rustc-args = ["--cfg", "docsrs"]
rustdoc-args = ["--cfg", "docsrs"]
[dependencies]
wry = { version = "0.44.0", default-features = false, features = [
wry = { version = "0.46", default-features = false, features = [
"drag-drop",
"protocol",
"os-webview",
@@ -45,8 +45,10 @@ gtk = { version = "0.18", features = ["v3_24"] }
webkit2gtk = { version = "=2.0", features = ["v2_40"] }
percent-encoding = "2.1"
[target.'cfg(target_os = "macos")'.dependencies]
[target.'cfg(target_vendor = "apple")'.dependencies]
objc2 = "0.5.2"
[target.'cfg(target_os = "macos")'.dependencies]
objc2-foundation = { version = "0.2.2", features = [] }
objc2-app-kit = { version = "0.2.2", features = [
"block2",

View File

@@ -30,6 +30,8 @@ use tauri_runtime::{
UserEvent, WebviewDispatch, WebviewEventId, WindowDispatch, WindowEventId,
};
#[cfg(any(target_os = "macos", target_os = "ios"))]
use objc2::rc::Retained;
#[cfg(target_os = "macos")]
use tao::platform::macos::{EventLoopWindowTargetExtMacOS, WindowBuilderExtMacOS};
#[cfg(target_os = "linux")]
@@ -3323,9 +3325,12 @@ fn handle_user_message<T: UserEvent>(
{
use wry::WebViewExtMacOS;
f(Webview {
webview: webview.webview().cast(),
manager: webview.manager().cast(),
ns_window: webview.ns_window().cast(),
webview: Retained::into_raw(webview.webview()) as *mut objc2::runtime::AnyObject
as *mut std::ffi::c_void,
manager: Retained::into_raw(webview.manager()) as *mut objc2::runtime::AnyObject
as *mut std::ffi::c_void,
ns_window: Retained::into_raw(webview.ns_window()) as *mut objc2::runtime::AnyObject
as *mut std::ffi::c_void,
});
}
#[cfg(target_os = "ios")]
@@ -3334,9 +3339,13 @@ fn handle_user_message<T: UserEvent>(
use wry::WebViewExtIOS;
f(Webview {
webview: webview.inner.webview().cast(),
manager: webview.inner.manager().cast(),
view_controller: window.ui_view_controller().cast(),
webview: Retained::into_raw(webview.inner.webview())
as *mut objc2::runtime::AnyObject
as *mut std::ffi::c_void,
manager: Retained::into_raw(webview.inner.manager())
as *mut objc2::runtime::AnyObject
as *mut std::ffi::c_void,
view_controller: window.ui_view_controller(),
});
}
#[cfg(windows)]
@@ -3963,52 +3972,45 @@ fn create_webview<T: UserEvent>(
..
} = pending;
let builder = match kind {
#[cfg(not(any(
target_os = "windows",
target_os = "macos",
target_os = "ios",
target_os = "android"
)))]
WebviewKind::WindowChild => {
// only way to account for menu bar height, and also works for multiwebviews :)
let vbox = window.default_vbox().unwrap();
WebViewBuilder::new_gtk(vbox)
let mut web_context = context
.main_thread
.web_context
.lock()
.expect("poisoned WebContext store");
let is_first_context = web_context.is_empty();
// 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;
let entry = web_context.entry(web_context_key.clone());
let web_context = match entry {
Occupied(occupied) => {
let occupied = occupied.into_mut();
occupied.referenced_by_webviews.insert(label.clone());
occupied
}
#[cfg(any(
target_os = "windows",
target_os = "macos",
target_os = "ios",
target_os = "android"
))]
WebviewKind::WindowChild => WebViewBuilder::new_as_child(&window),
WebviewKind::WindowContent => {
#[cfg(any(
target_os = "windows",
target_os = "macos",
target_os = "ios",
target_os = "android"
))]
let builder = WebViewBuilder::new(&window);
#[cfg(not(any(
target_os = "windows",
target_os = "macos",
target_os = "ios",
target_os = "android"
)))]
let builder = {
let vbox = window.default_vbox().unwrap();
WebViewBuilder::new_gtk(vbox)
};
builder
Vacant(vacant) => {
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(WebContext {
inner: web_context,
referenced_by_webviews: [label.clone()].into(),
registered_custom_protocols: HashSet::new(),
})
}
};
let mut webview_builder = builder
let mut webview_builder = WebViewBuilder::with_web_context(&mut web_context.inner)
.with_id(&label)
.with_focused(window.is_focused())
.with_url(&url)
.with_transparent(webview_attributes.transparent)
.with_accept_first_mouse(webview_attributes.accept_first_mouse)
.with_incognito(webview_attributes.incognito)
.with_clipboard(webview_attributes.clipboard)
.with_hotkeys_zoom(webview_attributes.zoom_hotkeys_enabled);
if webview_attributes.drag_drop_handler_enabled {
@@ -4177,47 +4179,17 @@ fn create_webview<T: UserEvent>(
webview_builder = webview_builder.with_initialization_script(&script);
}
let mut web_context = context
.main_thread
.web_context
.lock()
.expect("poisoned WebContext store");
let is_first_context = web_context.is_empty();
// 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;
let entry = web_context.entry(web_context_key.clone());
let web_context = match entry {
Occupied(occupied) => {
let occupied = occupied.into_mut();
occupied.referenced_by_webviews.insert(label.clone());
occupied
}
Vacant(vacant) => {
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(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(
#[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;
}
@@ -4227,21 +4199,16 @@ fn create_webview<T: UserEvent>(
.insert(scheme.clone());
}
webview_builder =
webview_builder.with_asynchronous_custom_protocol(scheme, move |request, responder| {
webview_builder = webview_builder.with_asynchronous_custom_protocol(
scheme,
move |webview_id, request, responder| {
protocol(
webview_id,
request,
Box::new(move |response| responder.respond(response)),
)
});
}
if webview_attributes.clipboard {
webview_builder.attrs.clipboard = true;
}
if webview_attributes.incognito {
webview_builder.attrs.incognito = true;
},
);
}
#[cfg(any(debug_assertions, feature = "devtools"))]
@@ -4262,10 +4229,47 @@ fn create_webview<T: UserEvent>(
}
}
let webview = webview_builder
.with_web_context(&mut web_context.inner)
.build()
.map_err(|e| Error::CreateWebview(Box::new(e)))?;
let webview = match kind {
#[cfg(not(any(
target_os = "windows",
target_os = "macos",
target_os = "ios",
target_os = "android"
)))]
WebviewKind::WindowChild => {
// only way to account for menu bar height, and also works for multiwebviews :)
let vbox = window.default_vbox().unwrap();
webview_builder.build_gtk(vbox)
}
#[cfg(any(
target_os = "windows",
target_os = "macos",
target_os = "ios",
target_os = "android"
))]
WebviewKind::WindowChild => webview_builder.build(&window),
WebviewKind::WindowContent => {
#[cfg(any(
target_os = "windows",
target_os = "macos",
target_os = "ios",
target_os = "android"
))]
let builder = webview_builder.build(&window);
#[cfg(not(any(
target_os = "windows",
target_os = "macos",
target_os = "ios",
target_os = "android"
)))]
let builder = {
let vbox = window.default_vbox().unwrap();
webview_builder.build_gtk(vbox)
};
builder
}
}
.map_err(|e| Error::CreateWebview(Box::new(dbg!(e))))?;
if kind == WebviewKind::WindowContent {
#[cfg(any(
@@ -4369,7 +4373,7 @@ fn inner_size(
if !has_children && !webviews.is_empty() {
use wry::WebViewExtMacOS;
let webview = webviews.first().unwrap();
let view: &objc2_app_kit::NSView = unsafe { &*webview.webview().cast() };
let view = unsafe { Retained::cast::<objc2_app_kit::NSView>(webview.webview()) };
let view_frame = view.frame();
let logical: TaoLogicalSize<f64> = (view_frame.size.width, view_frame.size.height).into();
return logical.to_physical(window.scale_factor());

View File

@@ -18,7 +18,7 @@ use std::{
sync::Arc,
};
type UriSchemeProtocol = dyn Fn(http::Request<Vec<u8>>, Box<dyn FnOnce(http::Response<Cow<'static, [u8]>>) + Send>)
type UriSchemeProtocol = dyn Fn(&str, http::Request<Vec<u8>>, Box<dyn FnOnce(http::Response<Cow<'static, [u8]>>) + Send>)
+ Send
+ Sync
+ 'static;
@@ -129,7 +129,7 @@ impl<T: UserEvent, R: Runtime<T>> PendingWebview<T, R> {
pub fn register_uri_scheme_protocol<
N: Into<String>,
H: Fn(http::Request<Vec<u8>>, Box<dyn FnOnce(http::Response<Cow<'static, [u8]>>) + Send>)
H: Fn(&str, http::Request<Vec<u8>>, Box<dyn FnOnce(http::Response<Cow<'static, [u8]>>) + Send>)
+ Send
+ Sync
+ 'static,

View File

@@ -35,8 +35,8 @@ pub fn message_handler<R: Runtime>(
Box::new(move |webview, request| handle_ipc_message(request, &manager, &webview.label))
}
pub fn get<R: Runtime>(manager: Arc<AppManager<R>>, label: String) -> UriSchemeProtocolHandler {
Box::new(move |request, responder| {
pub fn get<R: Runtime>(manager: Arc<AppManager<R>>) -> UriSchemeProtocolHandler {
Box::new(move |label, request, responder| {
#[cfg(feature = "tracing")]
let span = tracing::trace_span!(
"ipc::request",
@@ -46,7 +46,6 @@ pub fn get<R: Runtime>(manager: Arc<AppManager<R>>, label: String) -> UriSchemeP
.entered();
let manager = manager.clone();
let label = label.clone();
let respond = move |mut response: http::Response<Cow<'static, [u8]>>| {
response
@@ -61,7 +60,7 @@ pub fn get<R: Runtime>(manager: Arc<AppManager<R>>, label: String) -> UriSchemeP
match *request.method() {
Method::POST => {
if let Some(webview) = manager.get_webview(&label) {
if let Some(webview) = manager.get_webview(label) {
match parse_invoke_request(&manager, request) {
Ok(request) => {
#[cfg(feature = "tracing")]

View File

@@ -212,15 +212,17 @@ impl<R: Runtime> WebviewManager<R> {
registered_scheme_protocols.push(uri_scheme.clone());
let protocol = protocol.clone();
let app_handle = manager.app_handle().clone();
let webview_label = label.to_string();
pending.register_uri_scheme_protocol(uri_scheme.clone(), move |request, responder| {
let context = UriSchemeContext {
app_handle: &app_handle,
webview_label: webview_label.as_str(),
};
(protocol.protocol)(context, request, UriSchemeResponder(responder))
});
pending.register_uri_scheme_protocol(
uri_scheme.clone(),
move |webview_id, request, responder| {
let context = UriSchemeContext {
app_handle: &app_handle,
webview_label: webview_id,
};
(protocol.protocol)(context, request, UriSchemeResponder(responder))
},
);
}
let window_url = Url::parse(&pending.url).unwrap();
@@ -252,16 +254,16 @@ impl<R: Runtime> WebviewManager<R> {
&window_origin,
web_resource_request_handler,
);
pending.register_uri_scheme_protocol("tauri", move |request, responder| {
protocol(request, UriSchemeResponder(responder))
pending.register_uri_scheme_protocol("tauri", move |webview_id, request, responder| {
protocol(webview_id, request, UriSchemeResponder(responder))
});
registered_scheme_protocols.push("tauri".into());
}
if !registered_scheme_protocols.contains(&"ipc".into()) {
let protocol = crate::ipc::protocol::get(manager.manager_owned(), pending.label.clone());
pending.register_uri_scheme_protocol("ipc", move |request, responder| {
protocol(request, UriSchemeResponder(responder))
let protocol = crate::ipc::protocol::get(manager.manager_owned());
pending.register_uri_scheme_protocol("ipc", move |webview_id, request, responder| {
protocol(webview_id, request, UriSchemeResponder(responder))
});
registered_scheme_protocols.push("ipc".into());
}
@@ -299,8 +301,8 @@ impl<R: Runtime> WebviewManager<R> {
.asset_protocol
.clone();
let protocol = crate::protocol::asset::get(asset_scope.clone(), window_origin.clone());
pending.register_uri_scheme_protocol("asset", move |request, responder| {
protocol(request, UriSchemeResponder(responder))
pending.register_uri_scheme_protocol("asset", move |webview_id, request, responder| {
protocol(webview_id, request, UriSchemeResponder(responder))
});
}
@@ -319,8 +321,8 @@ impl<R: Runtime> WebviewManager<R> {
*crypto_keys.aes_gcm().raw(),
window_origin,
);
pending.register_uri_scheme_protocol(schema, move |request, responder| {
protocol(request, UriSchemeResponder(responder))
pending.register_uri_scheme_protocol(schema, move |webview_id, request, responder| {
protocol(webview_id, request, UriSchemeResponder(responder))
});
}

View File

@@ -12,7 +12,7 @@ use tokio::io::{AsyncReadExt, AsyncSeekExt, AsyncWriteExt};
pub fn get(scope: scope::fs::Scope, window_origin: String) -> UriSchemeProtocolHandler {
Box::new(
move |request, responder| match get_response(request, &scope, &window_origin) {
move |_, request, responder| match get_response(request, &scope, &window_origin) {
Ok(response) => responder.respond(response),
Err(e) => responder.respond(
http::Response::builder()

View File

@@ -30,7 +30,7 @@ pub fn get<R: Runtime>(
let assets = assets as Arc<dyn Assets<R>>;
Box::new(move |request, responder| {
Box::new(move |_, request, responder| {
let response = match request_to_path(&request).as_str() {
"index.html" => match assets.get(&"index.html".into()) {
Some(asset) => {

View File

@@ -42,7 +42,7 @@ pub fn get<R: Runtime>(
#[cfg(all(dev, mobile))]
let response_cache = Arc::new(Mutex::new(HashMap::new()));
Box::new(move |request, responder| {
Box::new(move |_, request, responder| {
match get_response(
request,
&manager,

View File

@@ -49,7 +49,7 @@ pub(crate) type WebResourceRequestHandler =
dyn Fn(http::Request<Vec<u8>>, &mut http::Response<Cow<'static, [u8]>>) + Send + Sync;
pub(crate) type NavigationHandler = dyn Fn(&Url) -> bool + Send;
pub(crate) type UriSchemeProtocolHandler =
Box<dyn Fn(http::Request<Vec<u8>>, UriSchemeResponder) + Send + Sync>;
Box<dyn Fn(&str, http::Request<Vec<u8>>, UriSchemeResponder) + Send + Sync>;
pub(crate) type OnPageLoad<R> = dyn Fn(Webview<R>, PageLoadPayload<'_>) + Send + Sync + 'static;
pub(crate) type DownloadHandler<R> = dyn Fn(Webview<R>, DownloadEvent<'_>) -> bool + Send + Sync;