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 5632446

Browse filesBrowse files
marcopiracciniaduh95
authored andcommitted
stream: fix TransformStream race on cancel with pending write
Signed-off-by: marcopiraccini <marco.piraccini@gmail.com> PR-URL: #62040 Fixes: #62036 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Paolo Insogna <paolo@cowtech.it> Reviewed-By: Mattias Buelens <mattias@buelens.com>
1 parent db150b2 commit 5632446
Copy full SHA for 5632446

2 files changed

+57-2Lines changed: 57 additions & 2 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/transformstream.js‎

Copy file name to clipboardExpand all lines: lib/internal/webstreams/transformstream.js
+6-2Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,6 @@ const {
7272
const assert = require('internal/assert');
7373

7474
const kSkipThrow = Symbol('kSkipThrow');
75-
7675
const getNonWritablePropertyDescriptor = (value) => {
7776
return {
7877
__proto__: null,
@@ -524,7 +523,12 @@ function transformStreamDefaultControllerError(controller, error) {
524523

525524
async function transformStreamDefaultControllerPerformTransform(controller, chunk) {
526525
try {
527-
return await controller[kState].transformAlgorithm(chunk, controller);
526+
const transformAlgorithm = controller[kState].transformAlgorithm;
527+
if (transformAlgorithm === undefined) {
528+
// Algorithms were cleared by a concurrent cancel/abort/close.
529+
return;
530+
}
531+
return await transformAlgorithm(chunk, controller);
528532
} catch (error) {
529533
transformStreamError(controller[kState].stream, error);
530534
throw error;
Collapse file
+51Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
'use strict';
2+
3+
require('../common');
4+
const { test } = require('node:test');
5+
const assert = require('node:assert');
6+
const { TransformStream } = require('stream/web');
7+
const { setTimeout } = require('timers/promises');
8+
9+
// https://github.com/nodejs/node/issues/62036
10+
11+
test('Late write racing with reader.cancel() should not throw an internal TypeError', async () => {
12+
const stream = new TransformStream({
13+
transform(chunk, controller) {
14+
controller.enqueue(chunk);
15+
},
16+
});
17+
18+
await setTimeout(0);
19+
20+
const reader = stream.readable.getReader();
21+
const writer = stream.writable.getWriter();
22+
23+
// Release backpressure.
24+
const pendingRead = reader.read();
25+
26+
// Simulate client disconnect / shutdown.
27+
const pendingCancel = reader.cancel(new Error('client disconnected'));
28+
29+
// Late write racing with cancel.
30+
const pendingLateWrite = writer.write('late-write');
31+
32+
const [
33+
readResult,
34+
cancelResult,
35+
lateWriteResult,
36+
] = await Promise.allSettled([
37+
pendingRead,
38+
pendingCancel,
39+
pendingLateWrite,
40+
]);
41+
42+
assert.strictEqual(readResult.status, 'fulfilled');
43+
assert.strictEqual(cancelResult.status, 'fulfilled');
44+
if (lateWriteResult.status === 'rejected') {
45+
const err = lateWriteResult.reason;
46+
const isNotAFunction = err instanceof TypeError &&
47+
/transformAlgorithm is not a function/.test(err.message);
48+
assert.ok(!isNotAFunction,
49+
`Internal implementation error leaked: ${err.message}`);
50+
}
51+
});

0 commit comments

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