Skip to content

Commit 4d81124

Browse files
mrbbotdanielleadams
authored andcommitted
stream: allow transfer of readable byte streams
Updates the `ReadableStream` constructor to mark byte streams as transferable. When transferred, byte streams become regular streams. Refs: #39062 Refs: https://streams.spec.whatwg.org/#rs-transfer PR-URL: #45955 Reviewed-By: Daeyeon Jeong <[email protected]> Reviewed-By: Matteo Collina <[email protected]> Reviewed-By: Benjamin Gruenbaum <[email protected]> Reviewed-By: James M Snell <[email protected]>
1 parent 1497244 commit 4d81124

File tree

2 files changed

+63
-9
lines changed

2 files changed

+63
-9
lines changed

lib/internal/webstreams/readablestream.js

+8-9
Original file line numberDiff line numberDiff line change
@@ -281,17 +281,16 @@ class ReadableStream {
281281
this,
282282
source,
283283
extractHighWaterMark(highWaterMark, 0));
284-
return;
284+
} else {
285+
if (type !== undefined)
286+
throw new ERR_INVALID_ARG_VALUE('source.type', type);
287+
setupReadableStreamDefaultControllerFromSource(
288+
this,
289+
source,
290+
extractHighWaterMark(highWaterMark, 1),
291+
extractSizeAlgorithm(size));
285292
}
286293

287-
if (type !== undefined)
288-
throw new ERR_INVALID_ARG_VALUE('source.type', type);
289-
setupReadableStreamDefaultControllerFromSource(
290-
this,
291-
source,
292-
extractHighWaterMark(highWaterMark, 1),
293-
extractSizeAlgorithm(size));
294-
295294
// eslint-disable-next-line no-constructor-return
296295
return makeTransferable(this);
297296
}

test/parallel/test-whatwg-webstreams-transfer.js

+55
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ const {
1515

1616
const {
1717
isReadableStream,
18+
isReadableByteStreamController,
1819
} = require('internal/webstreams/readablestream');
1920

2021
const {
@@ -25,6 +26,10 @@ const {
2526
isTransformStream,
2627
} = require('internal/webstreams/transformstream');
2728

29+
const {
30+
kState,
31+
} = require('internal/webstreams/util');
32+
2833
const {
2934
makeTransferable,
3035
kClone,
@@ -107,6 +112,56 @@ const theData = 'hello';
107112
assert(readable.locked);
108113
}
109114

115+
{
116+
const { port1, port2 } = new MessageChannel();
117+
port1.onmessageerror = common.mustNotCall();
118+
port2.onmessageerror = common.mustNotCall();
119+
120+
// This test repeats the test above, but with a readable byte stream.
121+
// Note transferring a readable byte stream results in a regular
122+
// value-oriented stream on the other side:
123+
// https://streams.spec.whatwg.org/#abstract-opdef-setupcrossrealmtransformwritable
124+
125+
const theByteData = new Uint8Array([1, 2, 3]);
126+
127+
const readable = new ReadableStream({
128+
type: 'bytes',
129+
start: common.mustCall((controller) => {
130+
// `enqueue` will detach its argument's buffer, so clone first
131+
controller.enqueue(theByteData.slice());
132+
controller.close();
133+
}),
134+
});
135+
assert(isReadableByteStreamController(readable[kState].controller));
136+
137+
port2.onmessage = common.mustCall(({ data }) => {
138+
assert(isReadableStream(data));
139+
assert(!isReadableByteStreamController(data[kState].controller));
140+
141+
const reader = data.getReader();
142+
reader.read().then(common.mustCall((chunk) => {
143+
assert.deepStrictEqual(chunk, { done: false, value: theByteData });
144+
}));
145+
146+
port2.close();
147+
});
148+
149+
port1.onmessage = common.mustCall(({ data }) => {
150+
assert(isReadableStream(data));
151+
assert(!isReadableByteStreamController(data[kState].controller));
152+
assert(!data.locked);
153+
port1.postMessage(data, [data]);
154+
assert(data.locked);
155+
});
156+
157+
assert.throws(() => port2.postMessage(readable), {
158+
code: 'ERR_MISSING_TRANSFERABLE_IN_TRANSFER_LIST',
159+
});
160+
161+
port2.postMessage(readable, [readable]);
162+
assert(readable.locked);
163+
}
164+
110165
{
111166
const { port1, port2 } = new MessageChannel();
112167
port1.onmessageerror = common.mustNotCall();

0 commit comments

Comments
 (0)