From 082f8128b8d784c599fdf2c0d857dbbe6abbc7fe Mon Sep 17 00:00:00 2001 From: Florian Schwalm <68847951+egfx-notifications@users.noreply.github.com> Date: Tue, 13 Feb 2024 22:45:23 +0100 Subject: fix(ext/web): Prevent (De-)CompressionStream resource leak on stream cancellation (#21199) Based on #21074 and #20741 I was looking for further potential use cases of `TransformStream` `cancel()` method, so here go `CompressionStream` and `DecompressionStream`. Fixes #14212 --- tests/unit/streams_test.ts | 59 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 58 insertions(+), 1 deletion(-) (limited to 'tests/unit') diff --git a/tests/unit/streams_test.ts b/tests/unit/streams_test.ts index 6db9f666c..80b45e602 100644 --- a/tests/unit/streams_test.ts +++ b/tests/unit/streams_test.ts @@ -1,5 +1,5 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. -import { assertEquals, fail } from "./test_util.ts"; +import { assertEquals, assertRejects, fail } from "./test_util.ts"; const { core, @@ -476,3 +476,60 @@ for (const packetCount of [1, 1024]) { assertEquals(await promise, "resource closed"); }); } + +Deno.test(async function compressionStreamWritableMayBeAborted() { + await Promise.all([ + new CompressionStream("gzip").writable.getWriter().abort(), + new CompressionStream("deflate").writable.getWriter().abort(), + new CompressionStream("deflate-raw").writable.getWriter().abort(), + ]); +}); + +Deno.test(async function compressionStreamReadableMayBeCancelled() { + await Promise.all([ + new CompressionStream("gzip").readable.getReader().cancel(), + new CompressionStream("deflate").readable.getReader().cancel(), + new CompressionStream("deflate-raw").readable.getReader().cancel(), + ]); +}); + +Deno.test(async function decompressionStreamWritableMayBeAborted() { + await Promise.all([ + new DecompressionStream("gzip").writable.getWriter().abort(), + new DecompressionStream("deflate").writable.getWriter().abort(), + new DecompressionStream("deflate-raw").writable.getWriter().abort(), + ]); +}); + +Deno.test(async function decompressionStreamReadableMayBeCancelled() { + await Promise.all([ + new DecompressionStream("gzip").readable.getReader().cancel(), + new DecompressionStream("deflate").readable.getReader().cancel(), + new DecompressionStream("deflate-raw").readable.getReader().cancel(), + ]); +}); + +Deno.test(async function decompressionStreamValidGzipDoesNotThrow() { + const cs = new CompressionStream("gzip"); + const ds = new DecompressionStream("gzip"); + cs.readable.pipeThrough(ds); + const writer = cs.writable.getWriter(); + await writer.write(new Uint8Array([1])); + writer.releaseLock(); + await cs.writable.close(); + let result = new Uint8Array(); + for await (const chunk of ds.readable.values()) { + result = new Uint8Array([...result, ...chunk]); + } + assertEquals(result, new Uint8Array([1])); +}); + +Deno.test(async function decompressionStreamInvalidGzipStillReported() { + await assertRejects( + async () => { + await new DecompressionStream("gzip").writable.close(); + }, + TypeError, + "corrupt gzip stream does not have a matching checksum", + ); +}); -- cgit v1.2.3