mirror of
https://github.com/tauri-apps/tauri.git
synced 2024-10-26 09:58:16 +03:00
This commit is contained in:
parent
c68218b362
commit
a77be97474
5
.changes/ipc-post-message-fallback.md
Normal file
5
.changes/ipc-post-message-fallback.md
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"tauri": patch:enhance
|
||||||
|
---
|
||||||
|
|
||||||
|
Fallback to the postMessage IPC interface if we cannot reach the IPC custom protocol.
|
@ -217,11 +217,6 @@ fn main() {
|
|||||||
alias("desktop", !mobile);
|
alias("desktop", !mobile);
|
||||||
alias("mobile", mobile);
|
alias("mobile", mobile);
|
||||||
|
|
||||||
alias(
|
|
||||||
"ipc_custom_protocol",
|
|
||||||
target_os != "android" && (target_os != "linux" || has_feature("linux-ipc-protocol")),
|
|
||||||
);
|
|
||||||
|
|
||||||
let out_dir = PathBuf::from(var("OUT_DIR").unwrap());
|
let out_dir = PathBuf::from(var("OUT_DIR").unwrap());
|
||||||
|
|
||||||
let checked_features_out_path = out_dir.join("checked_features");
|
let checked_features_out_path = out_dir.join("checked_features");
|
||||||
|
@ -6,72 +6,73 @@
|
|||||||
const processIpcMessage = __RAW_process_ipc_message_fn__
|
const processIpcMessage = __RAW_process_ipc_message_fn__
|
||||||
const osName = __TEMPLATE_os_name__
|
const osName = __TEMPLATE_os_name__
|
||||||
const fetchChannelDataCommand = __TEMPLATE_fetch_channel_data_command__
|
const fetchChannelDataCommand = __TEMPLATE_fetch_channel_data_command__
|
||||||
const useCustomProtocol = __TEMPLATE_use_custom_protocol__
|
const linuxIpcProtocolEnabled = __TEMPLATE_linux_ipc_protocol_enabled__
|
||||||
|
let customProtocolIpcFailed = false
|
||||||
|
|
||||||
Object.defineProperty(window.__TAURI_INTERNALS__, 'postMessage', {
|
// on Linux we only use the custom-protocol-based IPC if the the linux-ipc-protocol Cargo feature is enabled
|
||||||
value: (message) => {
|
// on Android we never use it because Android does not have support to reading the request body
|
||||||
const { cmd, callback, error, payload, options } = message
|
const canUseCustomProtocol =
|
||||||
|
osName === 'linux' ? linuxIpcProtocolEnabled : osName !== 'android'
|
||||||
|
|
||||||
// use custom protocol for IPC if:
|
function sendIpcMessage(message) {
|
||||||
// - the flag is set to true or
|
const { cmd, callback, error, payload, options } = message
|
||||||
// - the command is the fetch data command or
|
|
||||||
// - when not on Linux/Android
|
if (
|
||||||
// AND
|
!customProtocolIpcFailed &&
|
||||||
// - when not on macOS with an https URL
|
(canUseCustomProtocol || cmd === fetchChannelDataCommand)
|
||||||
if (
|
) {
|
||||||
(useCustomProtocol ||
|
const { contentType, data } = processIpcMessage(payload)
|
||||||
cmd === fetchChannelDataCommand ||
|
fetch(window.__TAURI_INTERNALS__.convertFileSrc(cmd, 'ipc'), {
|
||||||
!(osName === 'linux' || osName === 'android')) &&
|
method: 'POST',
|
||||||
!(
|
body: data,
|
||||||
(osName === 'macos' || osName === 'ios') &&
|
headers: {
|
||||||
location.protocol === 'https:'
|
'Content-Type': contentType,
|
||||||
)
|
'Tauri-Callback': callback,
|
||||||
) {
|
'Tauri-Error': error,
|
||||||
const { contentType, data } = processIpcMessage(payload)
|
...options?.headers
|
||||||
fetch(window.__TAURI_INTERNALS__.convertFileSrc(cmd, 'ipc'), {
|
}
|
||||||
method: 'POST',
|
})
|
||||||
body: data,
|
.then((response) => {
|
||||||
headers: {
|
const cb = response.ok ? callback : error
|
||||||
'Content-Type': contentType,
|
// we need to split here because on Android the content-type gets duplicated
|
||||||
'Tauri-Callback': callback,
|
switch ((response.headers.get('content-type') || '').split(',')[0]) {
|
||||||
'Tauri-Error': error,
|
case 'application/json':
|
||||||
...options?.headers
|
return response.json().then((r) => [cb, r])
|
||||||
|
case 'text/plain':
|
||||||
|
return response.text().then((r) => [cb, r])
|
||||||
|
default:
|
||||||
|
return response.arrayBuffer().then((r) => [cb, r])
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.then((response) => {
|
.then(([cb, data]) => {
|
||||||
const cb = response.ok ? callback : error
|
if (window[`_${cb}`]) {
|
||||||
// we need to split here because on Android the content-type gets duplicated
|
window[`_${cb}`](data)
|
||||||
switch (
|
} else {
|
||||||
(response.headers.get('content-type') || '').split(',')[0]
|
console.warn(
|
||||||
) {
|
`[TAURI] Couldn't find callback id {cb} in window. This might happen when the app is reloaded while Rust is running an asynchronous operation.`
|
||||||
case 'application/json':
|
)
|
||||||
return response.json().then((r) => [cb, r])
|
}
|
||||||
case 'text/plain':
|
|
||||||
return response.text().then((r) => [cb, r])
|
|
||||||
default:
|
|
||||||
return response.arrayBuffer().then((r) => [cb, r])
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.then(([cb, data]) => {
|
|
||||||
if (window[`_${cb}`]) {
|
|
||||||
window[`_${cb}`](data)
|
|
||||||
} else {
|
|
||||||
console.warn(
|
|
||||||
`[TAURI] Couldn't find callback id {cb} in window. This might happen when the app is reloaded while Rust is running an asynchronous operation.`
|
|
||||||
)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
// otherwise use the postMessage interface
|
|
||||||
const { data } = processIpcMessage({
|
|
||||||
cmd,
|
|
||||||
callback,
|
|
||||||
error,
|
|
||||||
options,
|
|
||||||
payload
|
|
||||||
})
|
})
|
||||||
window.ipc.postMessage(data)
|
.catch(() => {
|
||||||
}
|
// failed to use the custom protocol IPC (either the webview blocked a custom protocol or it was a CSP error)
|
||||||
|
// so we need to fallback to the postMessage interface
|
||||||
|
customProtocolIpcFailed = true
|
||||||
|
sendIpcMessage(message)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
// otherwise use the postMessage interface
|
||||||
|
const { data } = processIpcMessage({
|
||||||
|
cmd,
|
||||||
|
callback,
|
||||||
|
error,
|
||||||
|
options,
|
||||||
|
payload
|
||||||
|
})
|
||||||
|
window.ipc.postMessage(data)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.defineProperty(window.__TAURI_INTERNALS__, 'postMessage', {
|
||||||
|
value: sendIpcMessage
|
||||||
})
|
})
|
||||||
})()
|
})()
|
||||||
|
@ -1084,7 +1084,7 @@ struct InvokeInitializationScript<'a> {
|
|||||||
process_ipc_message_fn: &'a str,
|
process_ipc_message_fn: &'a str,
|
||||||
os_name: &'a str,
|
os_name: &'a str,
|
||||||
fetch_channel_data_command: &'a str,
|
fetch_channel_data_command: &'a str,
|
||||||
use_custom_protocol: bool,
|
linux_ipc_protocol_enabled: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Make `Wry` the default `Runtime` for `Builder`
|
/// Make `Wry` the default `Runtime` for `Builder`
|
||||||
@ -1117,7 +1117,7 @@ impl<R: Runtime> Builder<R> {
|
|||||||
process_ipc_message_fn: crate::manager::webview::PROCESS_IPC_MESSAGE_FN,
|
process_ipc_message_fn: crate::manager::webview::PROCESS_IPC_MESSAGE_FN,
|
||||||
os_name: std::env::consts::OS,
|
os_name: std::env::consts::OS,
|
||||||
fetch_channel_data_command: crate::ipc::channel::FETCH_CHANNEL_DATA_COMMAND,
|
fetch_channel_data_command: crate::ipc::channel::FETCH_CHANNEL_DATA_COMMAND,
|
||||||
use_custom_protocol: cfg!(ipc_custom_protocol),
|
linux_ipc_protocol_enabled: cfg!(feature = "linux-ipc-protocol"),
|
||||||
}
|
}
|
||||||
.render_default(&Default::default())
|
.render_default(&Default::default())
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
@ -21,7 +21,6 @@ use crate::{webview::Webview, Runtime, StateManager};
|
|||||||
mod authority;
|
mod authority;
|
||||||
pub(crate) mod channel;
|
pub(crate) mod channel;
|
||||||
mod command;
|
mod command;
|
||||||
#[cfg(any(target_os = "macos", target_os = "ios", not(ipc_custom_protocol)))]
|
|
||||||
pub(crate) mod format_callback;
|
pub(crate) mod format_callback;
|
||||||
pub(crate) mod protocol;
|
pub(crate) mod protocol;
|
||||||
|
|
||||||
|
@ -19,7 +19,6 @@ use super::{CallbackFn, InvokeBody, InvokeResponse};
|
|||||||
const TAURI_CALLBACK_HEADER_NAME: &str = "Tauri-Callback";
|
const TAURI_CALLBACK_HEADER_NAME: &str = "Tauri-Callback";
|
||||||
const TAURI_ERROR_HEADER_NAME: &str = "Tauri-Error";
|
const TAURI_ERROR_HEADER_NAME: &str = "Tauri-Error";
|
||||||
|
|
||||||
#[cfg(any(target_os = "macos", target_os = "ios", not(ipc_custom_protocol)))]
|
|
||||||
pub fn message_handler<R: Runtime>(
|
pub fn message_handler<R: Runtime>(
|
||||||
manager: Arc<AppManager<R>>,
|
manager: Arc<AppManager<R>>,
|
||||||
) -> crate::runtime::webview::WebviewIpcHandler<crate::EventLoopMessage, R> {
|
) -> crate::runtime::webview::WebviewIpcHandler<crate::EventLoopMessage, R> {
|
||||||
@ -162,7 +161,6 @@ pub fn get<R: Runtime>(manager: Arc<AppManager<R>>, label: String) -> UriSchemeP
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(target_os = "macos", target_os = "ios", not(ipc_custom_protocol)))]
|
|
||||||
fn handle_ipc_message<R: Runtime>(message: String, manager: &AppManager<R>, label: &str) {
|
fn handle_ipc_message<R: Runtime>(message: String, manager: &AppManager<R>, label: &str) {
|
||||||
if let Some(webview) = manager.get_webview(label) {
|
if let Some(webview) = manager.get_webview(label) {
|
||||||
#[cfg(feature = "tracing")]
|
#[cfg(feature = "tracing")]
|
||||||
@ -374,15 +372,21 @@ fn parse_invoke_request<R: Runtime>(
|
|||||||
.decode_utf8_lossy()
|
.decode_utf8_lossy()
|
||||||
.to_string();
|
.to_string();
|
||||||
|
|
||||||
// the body is not set if ipc_custom_protocol is not enabled so we'll just ignore it
|
// on Android and on Linux (without the linux-ipc-protocol Cargo feature) we cannot read the request body
|
||||||
#[cfg(all(feature = "isolation", ipc_custom_protocol))]
|
// so we must ignore it because some commands use the IPC for faster response
|
||||||
if let crate::Pattern::Isolation { crypto_keys, .. } = &*manager.pattern {
|
let has_payload = !body.is_empty();
|
||||||
#[cfg(feature = "tracing")]
|
|
||||||
let _span = tracing::trace_span!("ipc::request::decrypt_isolation_payload").entered();
|
|
||||||
|
|
||||||
body = crate::utils::pattern::isolation::RawIsolationPayload::try_from(&body)
|
#[cfg(feature = "isolation")]
|
||||||
.and_then(|raw| crypto_keys.decrypt(raw))
|
if let crate::Pattern::Isolation { crypto_keys, .. } = &*manager.pattern {
|
||||||
.map_err(|e| e.to_string())?;
|
// if the platform does not support request body, we ignore it
|
||||||
|
if has_payload {
|
||||||
|
#[cfg(feature = "tracing")]
|
||||||
|
let _span = tracing::trace_span!("ipc::request::decrypt_isolation_payload").entered();
|
||||||
|
|
||||||
|
body = crate::utils::pattern::isolation::RawIsolationPayload::try_from(&body)
|
||||||
|
.and_then(|raw| crypto_keys.decrypt(raw))
|
||||||
|
.map_err(|e| e.to_string())?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let callback = CallbackFn(
|
let callback = CallbackFn(
|
||||||
@ -420,12 +424,12 @@ fn parse_invoke_request<R: Runtime>(
|
|||||||
let body = if content_type == mime::APPLICATION_OCTET_STREAM {
|
let body = if content_type == mime::APPLICATION_OCTET_STREAM {
|
||||||
body.into()
|
body.into()
|
||||||
} else if content_type == mime::APPLICATION_JSON {
|
} else if content_type == mime::APPLICATION_JSON {
|
||||||
if cfg!(ipc_custom_protocol) {
|
// if the platform does not support request body, we ignore it
|
||||||
|
if has_payload {
|
||||||
serde_json::from_slice::<serde_json::Value>(&body)
|
serde_json::from_slice::<serde_json::Value>(&body)
|
||||||
.map_err(|e| e.to_string())?
|
.map_err(|e| e.to_string())?
|
||||||
.into()
|
.into()
|
||||||
} else {
|
} else {
|
||||||
// the body is not set if ipc_custom_protocol is not enabled so we'll just ignore it
|
|
||||||
serde_json::Value::Object(Default::default()).into()
|
serde_json::Value::Object(Default::default()).into()
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -496,12 +496,9 @@ impl<R: Runtime> WebviewManager<R> {
|
|||||||
manager,
|
manager,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
#[cfg(any(target_os = "macos", target_os = "ios", not(ipc_custom_protocol)))]
|
pending.ipc_handler = Some(crate::ipc::protocol::message_handler(
|
||||||
{
|
manager.manager_owned(),
|
||||||
pending.ipc_handler = Some(crate::ipc::protocol::message_handler(
|
));
|
||||||
manager.manager_owned(),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
// in `windows`, we need to force a data_directory
|
// in `windows`, we need to force a data_directory
|
||||||
// but we do respect user-specification
|
// but we do respect user-specification
|
||||||
|
Loading…
Reference in New Issue
Block a user