ipc-protocol.js 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. // Copyright 2019-2024 Tauri Programme within The Commons Conservancy
  2. // SPDX-License-Identifier: Apache-2.0
  3. // SPDX-License-Identifier: MIT
  4. ;(function () {
  5. /**
  6. * A runtime generated key to ensure an IPC call comes from an initialized frame.
  7. *
  8. * This is declared outside the `window.__TAURI_INVOKE__` definition to prevent
  9. * the key from being leaked by `window.__TAURI_INVOKE__.toString()`.
  10. */
  11. const __TAURI_INVOKE_KEY__ = __TEMPLATE_invoke_key__
  12. const processIpcMessage = __RAW_process_ipc_message_fn__
  13. const osName = __TEMPLATE_os_name__
  14. const fetchChannelDataCommand = __TEMPLATE_fetch_channel_data_command__
  15. const linuxIpcProtocolEnabled = __TEMPLATE_linux_ipc_protocol_enabled__
  16. let customProtocolIpcFailed = false
  17. // on Linux we only use the custom-protocol-based IPC if the linux-ipc-protocol Cargo feature is enabled
  18. // on Android we never use it because Android does not have support to reading the request body
  19. const canUseCustomProtocol =
  20. osName === 'linux' ? linuxIpcProtocolEnabled : osName !== 'android'
  21. function sendIpcMessage(message) {
  22. const { cmd, callback, error, payload, options } = message
  23. if (
  24. !customProtocolIpcFailed &&
  25. (canUseCustomProtocol || cmd === fetchChannelDataCommand)
  26. ) {
  27. const { contentType, data } = processIpcMessage(payload)
  28. fetch(window.__TAURI_INTERNALS__.convertFileSrc(cmd, 'ipc'), {
  29. method: 'POST',
  30. body: data,
  31. headers: {
  32. 'Content-Type': contentType,
  33. 'Tauri-Callback': callback,
  34. 'Tauri-Error': error,
  35. 'Tauri-Invoke-Key': __TAURI_INVOKE_KEY__,
  36. ...((options && options.headers) || {})
  37. }
  38. })
  39. .then((response) => {
  40. const cb =
  41. response.headers.get('Tauri-Response') === 'ok' ? callback : error
  42. // we need to split here because on Android the content-type gets duplicated
  43. switch ((response.headers.get('content-type') || '').split(',')[0]) {
  44. case 'application/json':
  45. return response.json().then((r) => [cb, r])
  46. case 'text/plain':
  47. return response.text().then((r) => [cb, r])
  48. default:
  49. return response.arrayBuffer().then((r) => [cb, r])
  50. }
  51. })
  52. .then(([cb, data]) => {
  53. if (window[`_${cb}`]) {
  54. window[`_${cb}`](data)
  55. } else {
  56. console.warn(
  57. `[TAURI] Couldn't find callback id {cb} in window. This might happen when the app is reloaded while Rust is running an asynchronous operation.`
  58. )
  59. }
  60. })
  61. .catch((e) => {
  62. console.warn(
  63. 'IPC custom protocol failed, Tauri will now use the postMessage interface instead',
  64. e
  65. )
  66. // failed to use the custom protocol IPC (either the webview blocked a custom protocol or it was a CSP error)
  67. // so we need to fallback to the postMessage interface
  68. customProtocolIpcFailed = true
  69. sendIpcMessage(message)
  70. })
  71. } else {
  72. // otherwise use the postMessage interface
  73. const { data } = processIpcMessage({
  74. cmd,
  75. callback,
  76. error,
  77. options: {
  78. ...options,
  79. customProtocolIpcBlocked: customProtocolIpcFailed
  80. },
  81. payload,
  82. __TAURI_INVOKE_KEY__
  83. })
  84. window.ipc.postMessage(data)
  85. }
  86. }
  87. Object.defineProperty(window.__TAURI_INTERNALS__, 'postMessage', {
  88. value: sendIpcMessage
  89. })
  90. })()