diff --git a/lib/internal/webstreams/adapters.js b/lib/internal/webstreams/adapters.js index 1ffb19b4f59a31..f7ecbed27384a3 100644 --- a/lib/internal/webstreams/adapters.js +++ b/lib/internal/webstreams/adapters.js @@ -56,7 +56,7 @@ const { } = require('buffer'); const { - isArrayBuffer, + isAnyArrayBuffer, } = require('internal/util/types'); const { @@ -230,11 +230,11 @@ function newWritableStreamFromStreamWritable(streamWritable, options = kEmptyObj start(c) { controller = c; }, write(chunk) { - if (!streamWritable.writableObjectMode && isArrayBuffer(chunk)) { - chunk = new Uint8Array(chunk); - } try { options[kValidateChunk]?.(chunk); + if (!streamWritable.writableObjectMode && isAnyArrayBuffer(chunk)) { + chunk = new Uint8Array(chunk); + } if (streamWritable.writableNeedDrain || !streamWritable.write(chunk)) { backpressurePromise = PromiseWithResolvers(); return SafePromisePrototypeFinally( diff --git a/lib/internal/webstreams/compression.js b/lib/internal/webstreams/compression.js index 7ec929d94a0da0..70359d1158eee8 100644 --- a/lib/internal/webstreams/compression.js +++ b/lib/internal/webstreams/compression.js @@ -40,7 +40,7 @@ function lazyZlib() { // Per the Compression Streams spec, chunks must be BufferSource // (ArrayBuffer or ArrayBufferView not backed by SharedArrayBuffer). function validateBufferSourceChunk(chunk) { - if (isArrayBufferView(chunk) && isSharedArrayBuffer(chunk.buffer)) { + if (isSharedArrayBuffer(isArrayBufferView(chunk) ? chunk.buffer : chunk)) { throw new ERR_INVALID_ARG_TYPE( 'chunk', ['ArrayBuffer', 'Buffer', 'TypedArray', 'DataView'], diff --git a/test/parallel/test-webstreams-adapters-writable-buffer-sources.js b/test/parallel/test-webstreams-adapters-writable-buffer-sources.js new file mode 100644 index 00000000000000..995db97e747364 --- /dev/null +++ b/test/parallel/test-webstreams-adapters-writable-buffer-sources.js @@ -0,0 +1,95 @@ +'use strict'; +const common = require('../common'); + +const assert = require('assert'); +const { Buffer } = require('buffer'); +const { Duplex, Writable } = require('stream'); +const { suite, test } = require('node:test'); + +const ctors = [ArrayBuffer, SharedArrayBuffer]; + +suite('underlying Writable', () => { + suite('in non-object mode', () => { + for (const ctor of ctors) { + test(`converts ${ctor.name} chunks`, async () => { + const buffer = new ctor(4); + const writable = new Writable({ + objectMode: false, + write: common.mustCall((chunk, encoding, callback) => { + assert(Buffer.isBuffer(chunk)); + assert.strictEqual(chunk.buffer, buffer); + callback(); + }), + }); + writable.on('error', common.mustNotCall()); + const writer = Writable.toWeb(writable).getWriter(); + await writer.write(buffer); + }); + } + }); + + suite('in object mode', () => { + for (const ctor of ctors) { + test(`passes through ${ctor.name} chunks`, async () => { + const buffer = new ctor(4); + const writable = new Writable({ + objectMode: true, + write: common.mustCall((chunk, encoding, callback) => { + assert(chunk instanceof ctor); + assert.strictEqual(chunk, buffer); + callback(); + }), + }); + writable.on('error', common.mustNotCall()); + const writer = Writable.toWeb(writable).getWriter(); + await writer.write(buffer); + }); + } + }); +}); + +suite('underlying Duplex', () => { + suite('in non-object mode', () => { + for (const ctor of ctors) { + test(`converts ${ctor.name} chunks`, async () => { + const buffer = new ctor(4); + const duplex = new Duplex({ + writableObjectMode: false, + write: common.mustCall((chunk, encoding, callback) => { + assert(Buffer.isBuffer(chunk)); + assert.strictEqual(chunk.buffer, buffer); + callback(); + }), + read() { + this.push(null); + }, + }); + duplex.on('error', common.mustNotCall()); + const writer = Duplex.toWeb(duplex).writable.getWriter(); + await writer.write(buffer); + }); + } + }); + + suite('in object mode', () => { + for (const ctor of ctors) { + test(`passes through ${ctor.name} chunks`, async () => { + const buffer = new ctor(4); + const duplex = new Duplex({ + writableObjectMode: true, + write: common.mustCall((chunk, encoding, callback) => { + assert(chunk instanceof ctor); + assert.strictEqual(chunk, buffer); + callback(); + }), + read() { + this.push(null); + }, + }); + duplex.on('error', common.mustNotCall()); + const writer = Duplex.toWeb(duplex).writable.getWriter(); + await writer.write(buffer); + }); + } + }); +});