fix(res.send): preserve bytes when sending DataView - #7433
Conversation
DataView is an ArrayBuffer view but has no .length, so the binary path produced an empty body with HTTP 200. Copy via byteOffset/byteLength.
kilisamemarisaaa
left a comment
There was a problem hiding this comment.
Formatting correction for my previous review: the CLI escaped its Markdown and truncated the important comparison. The complete finding is below.
I reproduced the DataView bug and confirmed that the two new tests pass. The full suite also passes (1,262 tests) and lint is clean on Node 24.12.0.
There is one compatibility issue with applying this conversion to every non-Buffer view. Buffer.from(typedArray) uses the typed array's elements, while Buffer.from(view.buffer, view.byteOffset, view.byteLength) uses all backing bytes. For example:
res.send(new Uint16Array([0x0102, 0x0304]))On Windows x64 / Node 24.12.0, Express 5.2.1 sends Content-Length: 2 with hex body 0204. This PR head sends Content-Length: 4 with hex body 02010403. That changes existing observable behavior for a view unrelated to the DataView bug.
Could the backing-buffer conversion be scoped to DataView (or otherwise preserve the existing typed-array path), with a regression test for a non-Uint8Array typed array? The current DataView tests can remain as-is.
Keep the existing typed-array path so Uint16Array and similar views still send one byte per element. Add a regression test.
|
recheck |
kilisamemarisaaa
left a comment
There was a problem hiding this comment.
Rechecked at f9330f13a6b0d9cd65e9974a4fbcadc514ff51c9. Scoping the backing-buffer conversion to DataView fully addresses my earlier compatibility concern: DataView payloads now preserve their byte ranges, while Uint16Array retains the existing two-byte 0204 response.
Validation on Windows with Node 24.12.0:
test/res.send.js: 78/78 passed- full
npm test: 1,263/1,263 passed npm run lint: passed
The added non-byte typed-array regression test covers the behavior from the review. I found no remaining blocking issue in this change.
res.send(new DataView(buffer))returned HTTP 200 withContent-Length: 0and an empty body.res.send(new Uint8Array(buffer))on the same bytes sent the payload.ArrayBuffer.isViewis true for DataView, so the value is treated as binary. The length path then useschunk.length/Buffer.from(chunk, encoding). DataView has no.length(only.byteLength), andBuffer.from(dataView)is an empty Buffer.This copies non-Buffer views with
Buffer.from(view.buffer, view.byteOffset, view.byteLength). ExistingBufferandUint8Arraybehavior is unchanged.This does not change bare
ArrayBuffer(still sent as{}JSON). That is covered by #7362.Tests:
test/res.send.jsfor a full DataView and a sliced DataView.