Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 9b82b15

Browse filesBrowse files
MattiasBuelensmarco-ippolito
authored andcommitted
stream: update ongoing promise in async iterator return() method
PR-URL: #52657 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Debadree Chatterjee <debadree333@gmail.com> Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com>
1 parent 4a3ecbf commit 9b82b15
Copy full SHA for 9b82b15

7 files changed

+139-7Lines changed: 139 additions & 7 deletions

File tree

Expand file treeCollapse file tree
Open diff view settings
Filter options
Expand file treeCollapse file tree
Open diff view settings
Collapse file

‎lib/internal/webstreams/readablestream.js‎

Copy file name to clipboardExpand all lines: lib/internal/webstreams/readablestream.js
+3-1Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -548,12 +548,14 @@ class ReadableStream {
548548
},
549549

550550
return(error) {
551-
return state.current ?
551+
started = true;
552+
state.current = state.current !== undefined ?
552553
PromisePrototypeThen(
553554
state.current,
554555
() => returnSteps(error),
555556
() => returnSteps(error)) :
556557
returnSteps(error);
558+
return state.current;
557559
},
558560

559561
[SymbolAsyncIterator]() { return this; },
Collapse file

‎test/fixtures/wpt/README.md‎

Copy file name to clipboardExpand all lines: test/fixtures/wpt/README.md
+3-3Lines changed: 3 additions & 3 deletions
  • Display the source diff
  • Display the rich diff
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,9 @@ Last update:
2525
- interfaces: https://github.com/web-platform-tests/wpt/tree/df731dab88/interfaces
2626
- performance-timeline: https://github.com/web-platform-tests/wpt/tree/17ebc3aea0/performance-timeline
2727
- resource-timing: https://github.com/web-platform-tests/wpt/tree/22d38586d0/resource-timing
28-
- resources: https://github.com/web-platform-tests/wpt/tree/919874f84f/resources
29-
- streams: https://github.com/web-platform-tests/wpt/tree/3df6d94318/streams
30-
- url: https://github.com/web-platform-tests/wpt/tree/c2d7e70b52/url
28+
- resources: https://github.com/web-platform-tests/wpt/tree/1e140d63ec/resources
29+
- streams: https://github.com/web-platform-tests/wpt/tree/9b03282a99/streams
30+
- url: https://github.com/web-platform-tests/wpt/tree/0f550ab9f5/url
3131
- user-timing: https://github.com/web-platform-tests/wpt/tree/5ae85bf826/user-timing
3232
- wasm/jsapi: https://github.com/web-platform-tests/wpt/tree/cde25e7e3c/wasm/jsapi
3333
- wasm/webapi: https://github.com/web-platform-tests/wpt/tree/fd1b23eeaa/wasm/webapi
Collapse file
+14Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<!DOCTYPE html>
2+
<script type="module">
3+
let a = self.open()
4+
let d = await a.navigator.storage.getDirectory()
5+
let h = await d.getFileHandle("c5c9960b-a637-4232-be3d-3ccc5704852f", {"create": true})
6+
let r = new ReadableStream({
7+
start(c) {
8+
c.enqueue(h)
9+
c.close();
10+
}
11+
});
12+
let w = await h.createWritable({ })
13+
r.pipeThrough({"readable": r, "writable": w}, {})
14+
</script>
Collapse file
+21Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<!DOCTYPE html>
2+
<body>
3+
<script>
4+
window.onload = () => {
5+
const i = document.createElement("iframe");
6+
i.src = "about:blank";
7+
document.body.appendChild(i);
8+
9+
const rs = new i.contentWindow.ReadableStream({
10+
start(controller) { controller.error(); }
11+
});
12+
const ws = new i.contentWindow.WritableStream();
13+
14+
i.remove();
15+
16+
// pipeTo() should not crash with a ReadableStream or WritableStream from
17+
// a detached iframe.
18+
rs.pipeTo(ws);
19+
};
20+
</script>
21+
</body>
Collapse file

‎test/fixtures/wpt/streams/readable-streams/async-iterator.any.js‎

Copy file name to clipboardExpand all lines: test/fixtures/wpt/streams/readable-streams/async-iterator.any.js
+84-2Lines changed: 84 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -475,15 +475,85 @@ promise_test(async () => {
475475
const rs = new ReadableStream();
476476
const it = rs.values();
477477

478-
const iterResults = await Promise.allSettled([it.return('return value'), it.next()]);
478+
const resolveOrder = [];
479+
const iterResults = await Promise.allSettled([
480+
it.return('return value').then(result => {
481+
resolveOrder.push('return');
482+
return result;
483+
}),
484+
it.next().then(result => {
485+
resolveOrder.push('next');
486+
return result;
487+
})
488+
]);
479489

480490
assert_equals(iterResults[0].status, 'fulfilled', 'return() promise status');
481491
assert_iter_result(iterResults[0].value, 'return value', true, 'return()');
482492

483493
assert_equals(iterResults[1].status, 'fulfilled', 'next() promise status');
484494
assert_iter_result(iterResults[1].value, undefined, true, 'next()');
495+
496+
assert_array_equals(resolveOrder, ['return', 'next'], 'next() resolves after return()');
485497
}, 'return(); next() [no awaiting]');
486498

499+
promise_test(async () => {
500+
let resolveCancelPromise;
501+
const rs = recordingReadableStream({
502+
cancel(reason) {
503+
return new Promise(r => resolveCancelPromise = r);
504+
}
505+
});
506+
const it = rs.values();
507+
508+
let returnResolved = false;
509+
const returnPromise = it.return('return value').then(result => {
510+
returnResolved = true;
511+
return result;
512+
});
513+
await flushAsyncEvents();
514+
assert_false(returnResolved, 'return() should not resolve while cancel() promise is pending');
515+
516+
resolveCancelPromise();
517+
const iterResult1 = await returnPromise;
518+
assert_iter_result(iterResult1, 'return value', true, 'return()');
519+
520+
const iterResult2 = await it.next();
521+
assert_iter_result(iterResult2, undefined, true, 'next()');
522+
}, 'return(); next() with delayed cancel()');
523+
524+
promise_test(async () => {
525+
let resolveCancelPromise;
526+
const rs = recordingReadableStream({
527+
cancel(reason) {
528+
return new Promise(r => resolveCancelPromise = r);
529+
}
530+
});
531+
const it = rs.values();
532+
533+
const resolveOrder = [];
534+
const returnPromise = it.return('return value').then(result => {
535+
resolveOrder.push('return');
536+
return result;
537+
});
538+
const nextPromise = it.next().then(result => {
539+
resolveOrder.push('next');
540+
return result;
541+
});
542+
543+
assert_array_equals(rs.events, ['cancel', 'return value'], 'return() should call cancel()');
544+
assert_array_equals(resolveOrder, [], 'return() should not resolve before cancel() resolves');
545+
546+
resolveCancelPromise();
547+
const iterResult1 = await returnPromise;
548+
assert_iter_result(iterResult1, 'return value', true, 'return() should resolve with original reason');
549+
const iterResult2 = await nextPromise;
550+
assert_iter_result(iterResult2, undefined, true, 'next() should resolve with done result');
551+
552+
assert_array_equals(rs.events, ['cancel', 'return value'], 'no pull() after cancel()');
553+
assert_array_equals(resolveOrder, ['return', 'next'], 'next() should resolve after return() resolves');
554+
555+
}, 'return(); next() with delayed cancel() [no awaiting]');
556+
487557
promise_test(async () => {
488558
const rs = new ReadableStream();
489559
const it = rs.values();
@@ -499,13 +569,25 @@ promise_test(async () => {
499569
const rs = new ReadableStream();
500570
const it = rs.values();
501571

502-
const iterResults = await Promise.allSettled([it.return('return value 1'), it.return('return value 2')]);
572+
const resolveOrder = [];
573+
const iterResults = await Promise.allSettled([
574+
it.return('return value 1').then(result => {
575+
resolveOrder.push('return 1');
576+
return result;
577+
}),
578+
it.return('return value 2').then(result => {
579+
resolveOrder.push('return 2');
580+
return result;
581+
})
582+
]);
503583

504584
assert_equals(iterResults[0].status, 'fulfilled', '1st return() promise status');
505585
assert_iter_result(iterResults[0].value, 'return value 1', true, '1st return()');
506586

507587
assert_equals(iterResults[1].status, 'fulfilled', '2nd return() promise status');
508588
assert_iter_result(iterResults[1].value, 'return value 2', true, '1st return()');
589+
590+
assert_array_equals(resolveOrder, ['return 1', 'return 2'], '2nd return() resolves after 1st return()');
509591
}, 'return(); return() [no awaiting]');
510592

511593
test(() => {
Collapse file
+13Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<!doctype html>
2+
<body>
3+
<script>
4+
const i = document.createElement("iframe");
5+
document.body.appendChild(i);
6+
7+
const rs = new i.contentWindow.ReadableStream();
8+
i.remove();
9+
10+
// tee() on a ReadableStream from a detached iframe should not crash.
11+
rs.tee();
12+
</script>
13+
</body>
Collapse file

‎test/fixtures/wpt/versions.json‎

Copy file name to clipboardExpand all lines: test/fixtures/wpt/versions.json
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@
6464
"path": "resources"
6565
},
6666
"streams": {
67-
"commit": "3df6d94318b225845a0c8e4c7718484f41c9b8ce",
67+
"commit": "9b03282a99ef2314c1c2d5050a105a74a2940019",
6868
"path": "streams"
6969
},
7070
"url": {

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.