ipc-protocol.js 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  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. let customProtocolIpcFailed = false
  16. // on Android we never use it because Android does not have support to reading the request body
  17. const canUseCustomProtocol = osName !== 'android'
  18. function sendIpcMessage(message) {
  19. const { cmd, callback, error, payload, options } = message
  20. if (
  21. !customProtocolIpcFailed &&
  22. (canUseCustomProtocol || cmd === fetchChannelDataCommand)
  23. ) {
  24. const { contentType, data } = processIpcMessage(payload)
  25. fetch(window.__TAURI_INTERNALS__.convertFileSrc(cmd, 'ipc'), {
  26. method: 'POST',
  27. body: data,
  28. headers: {
  29. 'Content-Type': contentType,
  30. 'Tauri-Callback': callback,
  31. 'Tauri-Error': error,
  32. 'Tauri-Invoke-Key': __TAURI_INVOKE_KEY__,
  33. ...((options && options.headers) || {})
  34. }
  35. })
  36. .then((response) => {
  37. const cb =
  38. response.headers.get('Tauri-Response') === 'ok' ? callback : error
  39. // we need to split here because on Android the content-type gets duplicated
  40. switch ((response.headers.get('content-type') || '').split(',')[0]) {
  41. case 'application/json':
  42. return response.json().then((r) => [cb, r])
  43. case 'text/plain':
  44. return response.text().then((r) => [cb, r])
  45. default:
  46. return response.arrayBuffer().then((r) => [cb, r])
  47. }
  48. })
  49. .then(([cb, data]) => {
  50. if (window[`_${cb}`]) {
  51. window[`_${cb}`](data)
  52. } else {
  53. console.warn(
  54. `[TAURI] Couldn't find callback id {cb} in window. This might happen when the app is reloaded while Rust is running an asynchronous operation.`
  55. )
  56. }
  57. })
  58. .catch((e) => {
  59. console.warn(
  60. 'IPC custom protocol failed, Tauri will now use the postMessage interface instead',
  61. e
  62. )
  63. // failed to use the custom protocol IPC (either the webview blocked a custom protocol or it was a CSP error)
  64. // so we need to fallback to the postMessage interface
  65. customProtocolIpcFailed = true
  66. sendIpcMessage(message)
  67. })
  68. } else {
  69. // otherwise use the postMessage interface
  70. const { data } = processIpcMessage({
  71. cmd,
  72. callback,
  73. error,
  74. options: {
  75. ...options,
  76. customProtocolIpcBlocked: customProtocolIpcFailed
  77. },
  78. payload,
  79. __TAURI_INVOKE_KEY__
  80. })
  81. window.ipc.postMessage(data)
  82. }
  83. }
  84. Object.defineProperty(window.__TAURI_INTERNALS__, 'postMessage', {
  85. value: sendIpcMessage
  86. })
  87. })()