Skip to content

Commit 57b6aa4

Browse files
jasnelladuh95
authored andcommitted
stream: ensure from() observes returned rejecting promise correctly
Signed-off-by: James M Snell <jasnell@gmail.com> Assisted-by: Opencode PR-URL: #65658 Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com>
1 parent 0acd81b commit 57b6aa4

2 files changed

Lines changed: 23 additions & 1 deletion

File tree

lib/internal/streams/iter/from.js

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ const {
1515
DataViewPrototypeGetByteLength,
1616
DataViewPrototypeGetByteOffset,
1717
FunctionPrototypeCall,
18+
PromisePrototypeThen,
1819
SymbolAsyncIterator,
1920
SymbolIterator,
2021
TypedArrayPrototypeGetBuffer,
@@ -23,6 +24,8 @@ const {
2324
Uint8Array,
2425
} = primordials;
2526

27+
const { markPromiseAsHandled } = internalBinding('util');
28+
2629
const {
2730
codes: {
2831
ERR_INVALID_ARG_TYPE,
@@ -594,7 +597,11 @@ function from(input) {
594597
// Check toAsyncStreamable protocol (takes precedence over toStreamable and
595598
// iteration protocols)
596599
if (typeof input[toAsyncStreamable] === 'function') {
597-
const result = input[toAsyncStreamable]();
600+
let result = input[toAsyncStreamable]();
601+
if (isPromise(result)) {
602+
result = PromisePrototypeThen(result, undefined, undefined);
603+
markPromiseAsHandled(result);
604+
}
598605
// Synchronous validated source (e.g. Readable batched iterator)
599606
if (result?.[kValidatedSource]) {
600607
return result;

test/parallel/test-stream-iter-from-async.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,20 @@ async function testFromTopLevelProtocolOverIterator() {
235235
assert.strictEqual(result, 'from-protocol');
236236
}
237237

238+
async function testFromHandlesProtocolRejectionUntilIteration() {
239+
const reason = new Error('protocol failed');
240+
const iterable = from({
241+
[Symbol.for('Stream.toAsyncStreamable')]: common.mustCall(
242+
() => Promise.reject(reason)),
243+
});
244+
245+
await new Promise(setImmediate);
246+
await assert.rejects(
247+
iterable[Symbol.asyncIterator]().next(),
248+
(error) => error === reason,
249+
);
250+
}
251+
238252
// DataView input should be converted to Uint8Array (zero-copy)
239253
async function testFromDataView() {
240254
const buf = new ArrayBuffer(5);
@@ -279,5 +293,6 @@ Promise.all([
279293
testFromTopLevelToStreamable(),
280294
testFromTopLevelAsyncPrecedence(),
281295
testFromTopLevelProtocolOverIterator(),
296+
testFromHandlesProtocolRejectionUntilIteration(),
282297
testFromDataView(),
283298
]).then(common.mustCall());

0 commit comments

Comments
 (0)