Repository: tauri-apps/tauri
File: crates/tauri/scripts/ipc-protocol.js (JavaScript)

Code before:
  // on Android we never use it because Android does not have support to reading the request body
  const canUseCustomProtocol = osName !== 'android'

  function sendIpcMessage(message) {
    const { cmd, callback, error, payload, options } = message

    if (
      !customProtocolIpcFailed
      && (canUseCustomProtocol || cmd === fetchChannelDataCommand)
    ) {
      const { contentType, data } = processIpcMessage(payload)
      const headers = new Headers({
        'Content-Type': contentType,
        'Tauri-Callback': callback,
        'Tauri-Error': error,
        'Tauri-Invoke-Key': __TAURI_INVOKE_KEY__
      })
      if (options?.headers) {
        const overrideHeaders =
          options.headers instanceof Headers
            ? options.headers.entries()
            : Object.entries(options.headers)
        for (const [key, value] of overrideHeaders) {
          headers.set(key, value)
        }
      }
      fetch(window.__TAURI_INTERNALS__.convertFileSrc(cmd, 'ipc'), {
        method: 'POST',
        body: data,
        headers
      })
        .then((response) => {
          const cb =
            response.headers.get('Tauri-Response') === 'ok' ? callback : error
          // we need to split here because on Android the content-type gets duplicated
          switch ((response.headers.get('content-type') || '').split(',')[0]) {
            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.`
            )

Review comment (suggestion):
```suggestion
      const headers = new Headers(options?.headers);
      headers.set("Content-Type", contentType);
      headers.set("Tauri-Callback", callback);
      headers.set("Tauri-Error", error);
      headers.set("Tauri-Invoke-Key", __TAURI_INVOKE_KEY__);
```

I'm just a bit curious, why not implement it this way? It seems more elegant.

I guess it's to preserve previous behavior (allowing users to override preset headers)? But overriding these headers seems like an unreasonable behavior.

Code after:
  // on Android we never use it because Android does not have support to reading the request body
  const canUseCustomProtocol = osName !== 'android'

  function sendIpcMessage(message) {
    const { cmd, callback, error, payload, options } = message

    if (
      !customProtocolIpcFailed
      && (canUseCustomProtocol || cmd === fetchChannelDataCommand)
    ) {
      const { contentType, data } = processIpcMessage(payload)

      const headers = new Headers((options && options.headers) || {})
      headers.set('Content-Type', contentType)
      headers.set('Tauri-Callback', callback)
      headers.set('Tauri-Error', error)
      headers.set('Tauri-Invoke-Key', __TAURI_INVOKE_KEY__)

      fetch(window.__TAURI_INTERNALS__.convertFileSrc(cmd, 'ipc'), {
        method: 'POST',
        body: data,
        headers
      })
        .then((response) => {
          const cb =
            response.headers.get('Tauri-Response') === 'ok' ? callback : error
          // we need to split here because on Android the content-type gets duplicated
          switch ((response.headers.get('content-type') || '').split(',')[0]) {
            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.`
            )
          }
        })
        .catch((e) => {
          console.warn(
            'IPC custom protocol failed, Tauri will now use the postMessage interface instead',
            e
          )
          // failed to use the custom protocol IPC (either the webview blocked a custom protocol or it was a CSP error)