From 3a7abe6906c54f9c628215c2b71d67e8db25a519 Mon Sep 17 00:00:00 2001 From: Florian Schwalm <68847951+egfx-notifications@users.noreply.github.com> Date: Sun, 12 Nov 2023 20:47:03 +0100 Subject: [PATCH] fix(ext/web): Prevent TextDecoderStream resource leak on stream cancellation (#21074) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 #13142 Co-authored-by: Bartek IwaƄczuk --- cli/tests/unit/text_encoding_test.ts | 17 +++++++++++++++++ ext/web/06_streams.js | 4 ++++ ext/web/08_text_encoding.js | 8 ++++++++ 3 files changed, 29 insertions(+) diff --git a/cli/tests/unit/text_encoding_test.ts b/cli/tests/unit/text_encoding_test.ts index b76e9a9bf0fa19..270fd07a835e69 100644 --- a/cli/tests/unit/text_encoding_test.ts +++ b/cli/tests/unit/text_encoding_test.ts @@ -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); + }, +); diff --git a/ext/web/06_streams.js b/ext/web/06_streams.js index c5306ca9c3351f..7ce045e6839200 100644 --- a/ext/web/06_streams.js +++ b/ext/web/06_streams.js @@ -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, diff --git a/ext/web/08_text_encoding.js b/ext/web/08_text_encoding.js index 45dbad53822ca7..5f8391e124c2f2 100644 --- a/ext/web/08_text_encoding.js +++ b/ext/web/08_text_encoding.js @@ -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; }