tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit 385b95367724fb9618970585ba0b16f59f8edc88
parent c1908042576709900a40049826cc223cbc14b887
Author: Kagami Sascha Rosylight <krosylight@proton.me>
Date:   Thu, 23 Oct 2025 21:34:48 +0000

Bug 1995999: Implement CompressionStreamAlgorithms as a superclass r=smaug

Differential Revision: https://phabricator.services.mozilla.com/D269751

Diffstat:
Mdom/compression/BaseAlgorithms.cpp | 99++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------
Mdom/compression/BaseAlgorithms.h | 37+++++++++++++++++++++++++++++++++----
Mdom/compression/CompressionStream.cpp | 2+-
Mdom/compression/FormatZlib.cpp | 109+++++++++++++++----------------------------------------------------------------
Mdom/compression/FormatZlib.h | 36++++++++++--------------------------
Mdom/compression/FormatZstd.cpp | 8++++----
6 files changed, 154 insertions(+), 137 deletions(-)

diff --git a/dom/compression/BaseAlgorithms.cpp b/dom/compression/BaseAlgorithms.cpp @@ -13,17 +13,90 @@ namespace mozilla::dom::compression { -NS_IMPL_CYCLE_COLLECTION_INHERITED(DecompressionStreamAlgorithms, - TransformerAlgorithmsBase) -NS_IMPL_ADDREF_INHERITED(DecompressionStreamAlgorithms, - TransformerAlgorithmsBase) -NS_IMPL_RELEASE_INHERITED(DecompressionStreamAlgorithms, - TransformerAlgorithmsBase) -NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DecompressionStreamAlgorithms) -NS_INTERFACE_MAP_END_INHERITING(TransformerAlgorithmsBase) +// Step 3 of +// https://compression.spec.whatwg.org/#dom-compressionstream-compressionstream +// Let transformAlgorithm be an algorithm which takes a chunk argument and +// runs the compress and enqueue a chunk algorithm with this and chunk. +MOZ_CAN_RUN_SCRIPT +void CompressionStreamAlgorithms::TransformCallbackImpl( + JS::Handle<JS::Value> aChunk, TransformStreamDefaultController& aController, + ErrorResult& aRv) { + AutoJSAPI jsapi; + if (!jsapi.Init(aController.GetParentObject())) { + aRv.ThrowUnknownError("Internal error"); + return; + } + JSContext* cx = jsapi.cx(); + + // https://compression.spec.whatwg.org/#compress-and-enqueue-a-chunk + + // Step 1: If chunk is not a BufferSource type, then throw a TypeError. + RootedUnion<OwningBufferSource> bufferSource(cx); + if (!bufferSource.Init(cx, aChunk)) { + aRv.MightThrowJSException(); + aRv.StealExceptionFromJSContext(cx); + return; + } + + // Step 2 - 5: (Done in CompressAndEnqueue) + ProcessTypedArraysFixed( + bufferSource, + [&](const Span<uint8_t>& aData) MOZ_CAN_RUN_SCRIPT_BOUNDARY { + CompressAndEnqueue(cx, aData, Flush::No, aController, aRv); + }); +} + +// Step 4 of +// https://compression.spec.whatwg.org/#dom-compressionstream-compressionstream +// Let flushAlgorithm be an algorithm which takes no argument and runs the +// compress flush and enqueue algorithm with this. +MOZ_CAN_RUN_SCRIPT void CompressionStreamAlgorithms::FlushCallbackImpl( + TransformStreamDefaultController& aController, ErrorResult& aRv) { + AutoJSAPI jsapi; + if (!jsapi.Init(aController.GetParentObject())) { + aRv.ThrowUnknownError("Internal error"); + return; + } + JSContext* cx = jsapi.cx(); + + // https://compression.spec.whatwg.org/#compress-flush-and-enqueue + + // Step 1 - 4: (Done in CompressAndEnqueue) + CompressAndEnqueue(cx, Span<const uint8_t>(), Flush::Yes, aController, aRv); +} + +// Shared by: +// https://compression.spec.whatwg.org/#compress-and-enqueue-a-chunk +// https://compression.spec.whatwg.org/#compress-flush-and-enqueue +MOZ_CAN_RUN_SCRIPT void CompressionStreamAlgorithms::CompressAndEnqueue( + JSContext* aCx, Span<const uint8_t> aInput, Flush aFlush, + TransformStreamDefaultController& aController, ErrorResult& aRv) { + MOZ_ASSERT_IF(aFlush == Flush::Yes, !aInput.Length()); + + JS::RootedVector<JSObject*> array(aCx); + + // Step 2: Let buffer be the result of compressing chunk with cs’s + // format and context. + // Step 3: If buffer is empty, return. (implicit as array will be empty then) + // Step 4: Let arrays be the result of buffer into one or more non-empty + // pieces and converting them into Uint8Arrays. + Compress(aCx, aInput, &array, aFlush, aRv); + if (aRv.Failed()) { + return; + } + + // Step 5: For each Uint8Array array, enqueue array in cs's transform. + for (const auto& view : array) { + JS::Rooted<JS::Value> value(aCx, JS::ObjectValue(*view)); + aController.Enqueue(aCx, value, aRv); + if (aRv.Failed()) { + return; + } + } +} // Step 3 of -// https://wicg.github.io/compression/#dom-decompressionstream-decompressionstream +// https://compression.spec.whatwg.org/#dom-decompressionstream-decompressionstream // Let transformAlgorithm be an algorithm which takes a chunk argument and // runs the compress and enqueue a chunk algorithm with this and chunk. MOZ_CAN_RUN_SCRIPT @@ -70,7 +143,7 @@ MOZ_CAN_RUN_SCRIPT void DecompressionStreamAlgorithms::FlushCallbackImpl( } JSContext* cx = jsapi.cx(); - // https://wicg.github.io/compression/#decompress-flush-and-enqueue + // https://compression.spec.whatwg.org/#decompress-flush-and-enqueue // Step 1: Let buffer be the result of decompressing an empty input with // ds's format and context, with the finish flag. @@ -79,8 +152,8 @@ MOZ_CAN_RUN_SCRIPT void DecompressionStreamAlgorithms::FlushCallbackImpl( } // Shared by: -// https://wicg.github.io/compression/#decompress-and-enqueue-a-chunk -// https://wicg.github.io/compression/#decompress-flush-and-enqueue +// https://compression.spec.whatwg.org/#decompress-and-enqueue-a-chunk +// https://compression.spec.whatwg.org/#decompress-flush-and-enqueue MOZ_CAN_RUN_SCRIPT void DecompressionStreamAlgorithms::DecompressAndEnqueue( JSContext* aCx, Span<const uint8_t> aInput, Flush aFlush, TransformStreamDefaultController& aController, ErrorResult& aRv) { @@ -116,7 +189,7 @@ MOZ_CAN_RUN_SCRIPT void DecompressionStreamAlgorithms::DecompressAndEnqueue( } // Step 3 of - // https://wicg.github.io/compression/#decompress-flush-and-enqueue + // https://compression.spec.whatwg.org/#decompress-flush-and-enqueue // If the end of the compressed input has not been reached, then throw a // TypeError. if (aFlush == Flush::Yes && !mObservedStreamEnd) { diff --git a/dom/compression/BaseAlgorithms.h b/dom/compression/BaseAlgorithms.h @@ -17,12 +17,41 @@ namespace mozilla::dom::compression { // with a function defined below. enum class Flush : bool { No, Yes }; -class DecompressionStreamAlgorithms : public TransformerAlgorithmsWrapper { +class CompressionStreamAlgorithms : public TransformerAlgorithmsWrapper { public: - NS_DECL_ISUPPORTS_INHERITED - NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(DecompressionStreamAlgorithms, - TransformerAlgorithmsBase) + // Step 3 of + // https://wicg.github.io/compression/#dom-decompressionstream-decompressionstream + // Let transformAlgorithm be an algorithm which takes a chunk argument and + // runs the compress and enqueue a chunk algorithm with this and chunk. + MOZ_CAN_RUN_SCRIPT + void TransformCallbackImpl(JS::Handle<JS::Value> aChunk, + TransformStreamDefaultController& aController, + ErrorResult& aRv) override; + + // Step 4 of + // https://compression.spec.whatwg.org/#dom-decompressionstream-decompressionstream + // Let flushAlgorithm be an algorithm which takes no argument and runs the + // compress flush and enqueue algorithm with this. + MOZ_CAN_RUN_SCRIPT void FlushCallbackImpl( + TransformStreamDefaultController& aController, ErrorResult& aRv) override; + + protected: + static const uint16_t kBufferSize = 16384; + + ~CompressionStreamAlgorithms() = default; + + virtual void Compress(JSContext* aCx, Span<const uint8_t> aInput, + JS::MutableHandleVector<JSObject*> aOutput, + Flush aFlush, ErrorResult& aRv) = 0; + private: + MOZ_CAN_RUN_SCRIPT void CompressAndEnqueue( + JSContext* aCx, Span<const uint8_t> aInput, Flush aFlush, + TransformStreamDefaultController& aController, ErrorResult& aRv); +}; + +class DecompressionStreamAlgorithms : public TransformerAlgorithmsWrapper { + public: // Step 3 of // https://wicg.github.io/compression/#dom-decompressionstream-decompressionstream // Let transformAlgorithm be an algorithm which takes a chunk argument and diff --git a/dom/compression/CompressionStream.cpp b/dom/compression/CompressionStream.cpp @@ -60,7 +60,7 @@ already_AddRefed<CompressionStream> CompressionStream::Constructor( // Step 6: Set up this's transform with transformAlgorithm set to // transformAlgorithm and flushAlgorithm set to flushAlgorithm. Result<already_AddRefed<CompressionStreamAlgorithms>, nsresult> algorithms = - CompressionStreamAlgorithms::Create(aFormat); + ZLibCompressionStreamAlgorithms::Create(aFormat); if (algorithms.isErr()) { aRv.ThrowUnknownError("Not enough memory"); return nullptr; diff --git a/dom/compression/FormatZlib.cpp b/dom/compression/FormatZlib.cpp @@ -7,30 +7,28 @@ #include "FormatZlib.h" #include "BaseAlgorithms.h" -#include "mozilla/dom/BufferSourceBinding.h" -#include "mozilla/dom/BufferSourceBindingFwd.h" #include "mozilla/dom/CompressionStreamBinding.h" #include "mozilla/dom/TransformStreamDefaultController.h" -#include "mozilla/dom/UnionTypes.h" namespace mozilla::dom::compression { -NS_IMPL_CYCLE_COLLECTION_INHERITED(CompressionStreamAlgorithms, +NS_IMPL_CYCLE_COLLECTION_INHERITED(ZLibCompressionStreamAlgorithms, TransformerAlgorithmsBase) -NS_IMPL_ADDREF_INHERITED(CompressionStreamAlgorithms, TransformerAlgorithmsBase) -NS_IMPL_RELEASE_INHERITED(CompressionStreamAlgorithms, +NS_IMPL_ADDREF_INHERITED(ZLibCompressionStreamAlgorithms, + TransformerAlgorithmsBase) +NS_IMPL_RELEASE_INHERITED(ZLibCompressionStreamAlgorithms, TransformerAlgorithmsBase) -NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(CompressionStreamAlgorithms) +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ZLibCompressionStreamAlgorithms) NS_INTERFACE_MAP_END_INHERITING(TransformerAlgorithmsBase) NS_IMPL_CYCLE_COLLECTION_INHERITED(ZLibDecompressionStreamAlgorithms, - DecompressionStreamAlgorithms) + TransformerAlgorithmsBase) NS_IMPL_ADDREF_INHERITED(ZLibDecompressionStreamAlgorithms, - DecompressionStreamAlgorithms) + TransformerAlgorithmsBase) NS_IMPL_RELEASE_INHERITED(ZLibDecompressionStreamAlgorithms, - DecompressionStreamAlgorithms) + TransformerAlgorithmsBase) NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ZLibDecompressionStreamAlgorithms) -NS_INTERFACE_MAP_END_INHERITING(DecompressionStreamAlgorithms) +NS_INTERFACE_MAP_END_INHERITING(TransformerAlgorithmsBase) inline uint8_t intoZLibFlush(Flush aFlush) { switch (aFlush) { @@ -72,14 +70,15 @@ inline int8_t ZLibWindowBits(CompressionFormat format) { } } -Result<already_AddRefed<CompressionStreamAlgorithms>, nsresult> -CompressionStreamAlgorithms::Create(CompressionFormat format) { - RefPtr<CompressionStreamAlgorithms> alg = new CompressionStreamAlgorithms(); +Result<already_AddRefed<ZLibCompressionStreamAlgorithms>, nsresult> +ZLibCompressionStreamAlgorithms::Create(CompressionFormat format) { + RefPtr<ZLibCompressionStreamAlgorithms> alg = + new ZLibCompressionStreamAlgorithms(); MOZ_TRY(alg->Init(format)); return alg.forget(); } -[[nodiscard]] nsresult CompressionStreamAlgorithms::Init( +[[nodiscard]] nsresult ZLibCompressionStreamAlgorithms::Init( CompressionFormat format) { int8_t err = deflateInit2(&mZStream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, ZLibWindowBits(format), 8 /* default memLevel */, @@ -91,75 +90,16 @@ CompressionStreamAlgorithms::Create(CompressionFormat format) { return NS_OK; } -// Step 3 of -// https://wicg.github.io/compression/#dom-compressionstream-compressionstream -// Let transformAlgorithm be an algorithm which takes a chunk argument and -// runs the compress and enqueue a chunk algorithm with this and chunk. -MOZ_CAN_RUN_SCRIPT -void CompressionStreamAlgorithms::TransformCallbackImpl( - JS::Handle<JS::Value> aChunk, TransformStreamDefaultController& aController, - ErrorResult& aRv) { - AutoJSAPI jsapi; - if (!jsapi.Init(aController.GetParentObject())) { - aRv.ThrowUnknownError("Internal error"); - return; - } - JSContext* cx = jsapi.cx(); - - // https://wicg.github.io/compression/#compress-and-enqueue-a-chunk - - // Step 1: If chunk is not a BufferSource type, then throw a TypeError. - RootedUnion<OwningBufferSource> bufferSource(cx); - if (!bufferSource.Init(cx, aChunk)) { - aRv.MightThrowJSException(); - aRv.StealExceptionFromJSContext(cx); - return; - } - - // Step 2: Let buffer be the result of compressing chunk with cs's format - // and context. - // Step 3 - 5: (Done in CompressAndEnqueue) - ProcessTypedArraysFixed( - bufferSource, - [&](const Span<uint8_t>& aData) MOZ_CAN_RUN_SCRIPT_BOUNDARY { - CompressAndEnqueue(cx, aData, Flush::No, aController, aRv); - }); -} - -// Step 4 of -// https://wicg.github.io/compression/#dom-compressionstream-compressionstream -// Let flushAlgorithm be an algorithm which takes no argument and runs the -// compress flush and enqueue algorithm with this. -MOZ_CAN_RUN_SCRIPT void CompressionStreamAlgorithms::FlushCallbackImpl( - TransformStreamDefaultController& aController, ErrorResult& aRv) { - AutoJSAPI jsapi; - if (!jsapi.Init(aController.GetParentObject())) { - aRv.ThrowUnknownError("Internal error"); - return; - } - JSContext* cx = jsapi.cx(); - - // https://wicg.github.io/compression/#compress-flush-and-enqueue - - // Step 1: Let buffer be the result of compressing an empty input with cs's - // format and context, with the finish flag. - // Step 2 - 4: (Done in CompressAndEnqueue) - CompressAndEnqueue(cx, Span<const uint8_t>(), Flush::Yes, aController, aRv); -} - // Shared by: // https://wicg.github.io/compression/#compress-and-enqueue-a-chunk // https://wicg.github.io/compression/#compress-flush-and-enqueue -MOZ_CAN_RUN_SCRIPT void CompressionStreamAlgorithms::CompressAndEnqueue( - JSContext* aCx, Span<const uint8_t> aInput, Flush aFlush, - TransformStreamDefaultController& aController, ErrorResult& aRv) { - MOZ_ASSERT_IF(aFlush == Flush::Yes, !aInput.Length()); - +void ZLibCompressionStreamAlgorithms::Compress( + JSContext* aCx, Span<const uint8_t> aInput, + JS::MutableHandleVector<JSObject*> aOutput, Flush aFlush, + ErrorResult& aRv) { mZStream.avail_in = aInput.Length(); mZStream.next_in = const_cast<uint8_t*>(aInput.Elements()); - JS::RootedVector<JSObject*> array(aCx); - do { static uint16_t kBufferSize = 16384; UniquePtr<uint8_t[], JS::FreePolicy> buffer( @@ -220,7 +160,7 @@ MOZ_CAN_RUN_SCRIPT void CompressionStreamAlgorithms::CompressAndEnqueue( JS::Rooted<JSObject*> view(aCx, nsJSUtils::MoveBufferAsUint8Array( aCx, written, std::move(buffer))); - if (!view || !array.append(view)) { + if (!view || !aOutput.append(view)) { JS_ClearPendingException(aCx); aRv.ThrowTypeError("Out of memory"); return; @@ -230,18 +170,9 @@ MOZ_CAN_RUN_SCRIPT void CompressionStreamAlgorithms::CompressAndEnqueue( // If deflate returns with avail_out == 0, this function must be called // again with the same value of the flush parameter and more output space // (updated avail_out) - - // Step 5: For each Uint8Array array, enqueue array in cs's transform. - for (const auto& view : array) { - JS::Rooted<JS::Value> value(aCx, JS::ObjectValue(*view)); - aController.Enqueue(aCx, value, aRv); - if (aRv.Failed()) { - return; - } - } } -CompressionStreamAlgorithms::~CompressionStreamAlgorithms() { +ZLibCompressionStreamAlgorithms::~ZLibCompressionStreamAlgorithms() { deflateEnd(&mZStream); }; diff --git a/dom/compression/FormatZlib.h b/dom/compression/FormatZlib.h @@ -20,44 +20,28 @@ enum class CompressionFormat : uint8_t; namespace mozilla::dom::compression { -class CompressionStreamAlgorithms : public TransformerAlgorithmsWrapper { +class ZLibCompressionStreamAlgorithms : public CompressionStreamAlgorithms { public: NS_DECL_ISUPPORTS_INHERITED - NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(CompressionStreamAlgorithms, - TransformerAlgorithmsBase) + NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(ZLibCompressionStreamAlgorithms, + CompressionStreamAlgorithms) - static Result<already_AddRefed<CompressionStreamAlgorithms>, nsresult> Create( - CompressionFormat format); + static Result<already_AddRefed<ZLibCompressionStreamAlgorithms>, nsresult> + Create(CompressionFormat format); private: - CompressionStreamAlgorithms() = default; + ZLibCompressionStreamAlgorithms() = default; [[nodiscard]] nsresult Init(CompressionFormat format); - // Step 3 of - // https://wicg.github.io/compression/#dom-compressionstream-compressionstream - // Let transformAlgorithm be an algorithm which takes a chunk argument and - // runs the compress and enqueue a chunk algorithm with this and chunk. - MOZ_CAN_RUN_SCRIPT - void TransformCallbackImpl(JS::Handle<JS::Value> aChunk, - TransformStreamDefaultController& aController, - ErrorResult& aRv) override; - - // Step 4 of - // https://wicg.github.io/compression/#dom-compressionstream-compressionstream - // Let flushAlgorithm be an algorithm which takes no argument and runs the - // compress flush and enqueue algorithm with this. - MOZ_CAN_RUN_SCRIPT void FlushCallbackImpl( - TransformStreamDefaultController& aController, ErrorResult& aRv) override; - // Shared by: // https://wicg.github.io/compression/#compress-and-enqueue-a-chunk // https://wicg.github.io/compression/#compress-flush-and-enqueue - MOZ_CAN_RUN_SCRIPT void CompressAndEnqueue( - JSContext* aCx, Span<const uint8_t> aInput, Flush aFlush, - TransformStreamDefaultController& aController, ErrorResult& aRv); + void Compress(JSContext* aCx, Span<const uint8_t> aInput, + JS::MutableHandleVector<JSObject*> aOutput, Flush aFlush, + ErrorResult& aRv) override; - ~CompressionStreamAlgorithms() override; + ~ZLibCompressionStreamAlgorithms() override; z_stream mZStream = {}; }; diff --git a/dom/compression/FormatZstd.cpp b/dom/compression/FormatZstd.cpp @@ -13,13 +13,13 @@ namespace mozilla::dom::compression { NS_IMPL_CYCLE_COLLECTION_INHERITED(ZstdDecompressionStreamAlgorithms, - DecompressionStreamAlgorithms) + TransformerAlgorithmsBase) NS_IMPL_ADDREF_INHERITED(ZstdDecompressionStreamAlgorithms, - DecompressionStreamAlgorithms) + TransformerAlgorithmsBase) NS_IMPL_RELEASE_INHERITED(ZstdDecompressionStreamAlgorithms, - DecompressionStreamAlgorithms) + TransformerAlgorithmsBase) NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ZstdDecompressionStreamAlgorithms) -NS_INTERFACE_MAP_END_INHERITING(DecompressionStreamAlgorithms) +NS_INTERFACE_MAP_END_INHERITING(TransformerAlgorithmsBase) Result<already_AddRefed<ZstdDecompressionStreamAlgorithms>, nsresult> ZstdDecompressionStreamAlgorithms::Create() {