oven-sh/bun

fetch api is broken due to spec violation

Opened this issue · 2 comments

What version of Bun is running?

1.2.22+6bafe2602

What platform is your computer?

Darwin 24.6.0 arm64 arm

What steps can reproduce the bug?

const x = await fetch('https://example.com')
Buffer.from(await x.clone().arrayBuffer()).fill('x')
console.log(await x.text())

What is the expected behavior?

As in Node.js, Deno and browsers

What do you see instead?

xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Additional information

https://fetch.spec.whatwg.org/

The arrayBuffer() method steps are to return the result of running consume body with this and the following step given a byte sequence bytes: return the result of creating an ArrayBuffer from bytes in this’s relevant realm.

Spec says that arrayBuffer() should always make a copy of the underlying bytes:

creating an ArrayBuffer from bytes

"Creating an ArrayBuffer" says (https://webidl.spec.whatwg.org/#arraybuffer-create):

  1. Write bytes into arrayBuffer.

Which in turn says (https://webidl.spec.whatwg.org/#arraybuffer-write):

  1. For i in the range startingOffset to startingOffset + bytes’s length − 1, inclusive, perform SetValueInBuffer(jsArrayBuffer, i, Uint8, bytes[i - startingOffset], true, Unordered).

i.e. .arrayBuffer() must perform actual memory writes per the specification, it demands a full copy to be made on .arrayBuffer() call, regardless of .clone() or not, and any attempts to shortcut that are a violation of the spec

Not following the spec is what caused this bug

This also allows to create non-equal ArrayBuffer instances referencing the same memory:

const a = new ArrayBuffer(1024)
Buffer.from(a).fill('a')
const r = new Response(a)
const b = await r.clone().arrayBuffer()
const c = await r.clone().arrayBuffer()
const d = await r.arrayBuffer()
console.log(b, c, d, b === c, b === d, c === d)
Buffer.from(b).fill('x')
console.log(b, c, d, b === c, b === d, c === d)