Skip to content

Commit

Permalink
fix(ext/web): Prevent TextDecoderStream resource leak on stream cance…
Browse files Browse the repository at this point in the history
…llation (denoland#21074)

This PR uses the new `cancel` method of `TransformStream` to properly
clean up the internal `TextDecoder` used in `TextDecoderStream` if the
stream is cancelled.

Fixes denoland#13142

Co-authored-by: Bartek Iwańczuk <[email protected]>
  • Loading branch information
egfx-notifications and bartlomieju committed Nov 12, 2023
1 parent 9f4a455 commit 3a7abe6
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 0 deletions.
17 changes: 17 additions & 0 deletions cli/tests/unit/text_encoding_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -319,3 +319,20 @@ Deno.test(function binaryEncode() {
assertEquals(Array.from(bytes), decodeBinary(binaryString));
}
});

Deno.test(
{ permissions: { read: true } },
async function textDecoderStreamCleansUpOnCancel() {
const filename = "cli/tests/testdata/assets/hello.txt";
const file = await Deno.open(filename);
const readable = file.readable.pipeThrough(new TextDecoderStream());
const chunks = [];
for await (const chunk of readable) {
chunks.push(chunk);
// breaking out of the loop prevents normal shutdown at end of async iterator values and triggers the cancel method of the stream instead
break;
}
assertEquals(chunks.length, 1);
assertEquals(chunks[0].length, 12);
},
);
4 changes: 4 additions & 0 deletions ext/web/06_streams.js
Original file line number Diff line number Diff line change
Expand Up @@ -6680,6 +6680,10 @@ webidl.converters.Transformer = webidl
key: "flush",
converter: webidl.converters.Function,
},
{
key: "cancel",
converter: webidl.converters.Function,
},
{
key: "readableType",
converter: webidl.converters.any,
Expand Down
8 changes: 8 additions & 0 deletions ext/web/08_text_encoding.js
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,14 @@ class TextDecoderStream {
return PromiseReject(err);
}
},
cancel: (_reason) => {
try {
const _ = this.#decoder.decode();
return PromiseResolve();
} catch (err) {
return PromiseReject(err);
}
},
});
this[webidl.brand] = webidl.brand;
}
Expand Down

0 comments on commit 3a7abe6

Please sign in to comment.