tor-browser

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

BaseAlgorithms.cpp (7618B)


      1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim:set ts=2 sw=2 sts=2 et cindent: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "BaseAlgorithms.h"
      8 
      9 #include "mozilla/dom/BufferSourceBinding.h"
     10 #include "mozilla/dom/BufferSourceBindingFwd.h"
     11 #include "mozilla/dom/TransformStreamDefaultController.h"
     12 #include "mozilla/dom/UnionTypes.h"
     13 
     14 namespace mozilla::dom::compression {
     15 
     16 // Step 3 of
     17 // https://compression.spec.whatwg.org/#dom-compressionstream-compressionstream
     18 // Let transformAlgorithm be an algorithm which takes a chunk argument and
     19 // runs the compress and enqueue a chunk algorithm with this and chunk.
     20 MOZ_CAN_RUN_SCRIPT
     21 void CompressionStreamAlgorithms::TransformCallbackImpl(
     22    JS::Handle<JS::Value> aChunk, TransformStreamDefaultController& aController,
     23    ErrorResult& aRv) {
     24  AutoJSAPI jsapi;
     25  if (!jsapi.Init(aController.GetParentObject())) {
     26    aRv.ThrowUnknownError("Internal error");
     27    return;
     28  }
     29  JSContext* cx = jsapi.cx();
     30 
     31  // https://compression.spec.whatwg.org/#compress-and-enqueue-a-chunk
     32 
     33  // Step 1: If chunk is not a BufferSource type, then throw a TypeError.
     34  RootedUnion<OwningBufferSource> bufferSource(cx);
     35  if (!bufferSource.Init(cx, aChunk)) {
     36    aRv.MightThrowJSException();
     37    aRv.StealExceptionFromJSContext(cx);
     38    return;
     39  }
     40 
     41  // Step 2 - 5: (Done in CompressAndEnqueue)
     42  ProcessTypedArraysFixed(
     43      bufferSource,
     44      [&](const Span<uint8_t>& aData) MOZ_CAN_RUN_SCRIPT_BOUNDARY {
     45        CompressAndEnqueue(cx, aData, Flush::No, aController, aRv);
     46      });
     47 }
     48 
     49 // Step 4 of
     50 // https://compression.spec.whatwg.org/#dom-compressionstream-compressionstream
     51 // Let flushAlgorithm be an algorithm which takes no argument and runs the
     52 // compress flush and enqueue algorithm with this.
     53 MOZ_CAN_RUN_SCRIPT void CompressionStreamAlgorithms::FlushCallbackImpl(
     54    TransformStreamDefaultController& aController, ErrorResult& aRv) {
     55  AutoJSAPI jsapi;
     56  if (!jsapi.Init(aController.GetParentObject())) {
     57    aRv.ThrowUnknownError("Internal error");
     58    return;
     59  }
     60  JSContext* cx = jsapi.cx();
     61 
     62  // https://compression.spec.whatwg.org/#compress-flush-and-enqueue
     63 
     64  // Step 1 - 4: (Done in CompressAndEnqueue)
     65  CompressAndEnqueue(cx, Span<const uint8_t>(), Flush::Yes, aController, aRv);
     66 }
     67 
     68 // Shared by:
     69 // https://compression.spec.whatwg.org/#compress-and-enqueue-a-chunk
     70 // https://compression.spec.whatwg.org/#compress-flush-and-enqueue
     71 MOZ_CAN_RUN_SCRIPT void CompressionStreamAlgorithms::CompressAndEnqueue(
     72    JSContext* aCx, Span<const uint8_t> aInput, Flush aFlush,
     73    TransformStreamDefaultController& aController, ErrorResult& aRv) {
     74  MOZ_ASSERT_IF(aFlush == Flush::Yes, !aInput.Length());
     75 
     76  JS::RootedVector<JSObject*> array(aCx);
     77 
     78  // Step 2: Let buffer be the result of compressing chunk with cs’s
     79  // format and context.
     80  // Step 3: If buffer is empty, return. (implicit as array will be empty then)
     81  // Step 4: Let arrays be the result of buffer into one or more non-empty
     82  // pieces and converting them into Uint8Arrays.
     83  Compress(aCx, aInput, &array, aFlush, aRv);
     84  if (aRv.Failed()) {
     85    return;
     86  }
     87 
     88  // Step 5: For each Uint8Array array, enqueue array in cs's transform.
     89  for (const auto& view : array) {
     90    JS::Rooted<JS::Value> value(aCx, JS::ObjectValue(*view));
     91    aController.Enqueue(aCx, value, aRv);
     92    if (aRv.Failed()) {
     93      return;
     94    }
     95  }
     96 }
     97 
     98 // Step 3 of
     99 // https://compression.spec.whatwg.org/#dom-decompressionstream-decompressionstream
    100 // Let transformAlgorithm be an algorithm which takes a chunk argument and
    101 // runs the compress and enqueue a chunk algorithm with this and chunk.
    102 MOZ_CAN_RUN_SCRIPT
    103 void DecompressionStreamAlgorithms::TransformCallbackImpl(
    104    JS::Handle<JS::Value> aChunk, TransformStreamDefaultController& aController,
    105    ErrorResult& aRv) {
    106  AutoJSAPI jsapi;
    107  if (!jsapi.Init(aController.GetParentObject())) {
    108    aRv.ThrowUnknownError("Internal error");
    109    return;
    110  }
    111  JSContext* cx = jsapi.cx();
    112 
    113  // https://compression.spec.whatwg.org/#decompress-and-enqueue-a-chunk
    114 
    115  // Step 1: If chunk is not a BufferSource type, then throw a TypeError.
    116  RootedUnion<OwningBufferSource> bufferSource(cx);
    117  if (!bufferSource.Init(cx, aChunk)) {
    118    aRv.MightThrowJSException();
    119    aRv.StealExceptionFromJSContext(cx);
    120    return;
    121  }
    122 
    123  // Step 2: Let buffer be the result of decompressing chunk with ds's format
    124  // and context. If this results in an error, then throw a TypeError.
    125  // Step 3 - 5: (Done in DecompressAndEnqueue)
    126  ProcessTypedArraysFixed(
    127      bufferSource,
    128      [&](const Span<uint8_t>& aData) MOZ_CAN_RUN_SCRIPT_BOUNDARY {
    129        DecompressAndEnqueue(cx, aData, Flush::No, aController, aRv);
    130      });
    131 }
    132 
    133 // Step 4 of
    134 // https://compression.spec.whatwg.org/#dom-decompressionstream-decompressionstream
    135 // Let flushAlgorithm be an algorithm which takes no argument and runs the
    136 // compress flush and enqueue algorithm with this.
    137 MOZ_CAN_RUN_SCRIPT void DecompressionStreamAlgorithms::FlushCallbackImpl(
    138    TransformStreamDefaultController& aController, ErrorResult& aRv) {
    139  AutoJSAPI jsapi;
    140  if (!jsapi.Init(aController.GetParentObject())) {
    141    aRv.ThrowUnknownError("Internal error");
    142    return;
    143  }
    144  JSContext* cx = jsapi.cx();
    145 
    146  // https://compression.spec.whatwg.org/#decompress-flush-and-enqueue
    147 
    148  // Step 1: Let buffer be the result of decompressing an empty input with
    149  // ds's format and context, with the finish flag.
    150  // Step 2 - 6: (Done in DecompressAndEnqueue)
    151  DecompressAndEnqueue(cx, Span<const uint8_t>(), Flush::Yes, aController, aRv);
    152 }
    153 
    154 // Shared by:
    155 // https://compression.spec.whatwg.org/#decompress-and-enqueue-a-chunk
    156 // https://compression.spec.whatwg.org/#decompress-flush-and-enqueue
    157 MOZ_CAN_RUN_SCRIPT void DecompressionStreamAlgorithms::DecompressAndEnqueue(
    158    JSContext* aCx, Span<const uint8_t> aInput, Flush aFlush,
    159    TransformStreamDefaultController& aController, ErrorResult& aRv) {
    160  MOZ_ASSERT_IF(aFlush == Flush::Yes, !aInput.Length());
    161 
    162  JS::RootedVector<JSObject*> array(aCx);
    163 
    164  // Step 2: Let buffer be the result of decompressing chunk with ds’s format
    165  // and context. If this results in an error, then throw a TypeError.
    166  // Step 3: If buffer is empty, return.
    167  // (Skipping, see https://github.com/whatwg/compression/issues/78)
    168  // Step 4: Let arrays be the result of splitting buffer into one or more
    169  // non-empty pieces and converting them into Uint8Arrays.
    170  bool fullyConsumed = Decompress(aCx, aInput, &array, aFlush, aRv);
    171  if (aRv.Failed()) {
    172    return;
    173  }
    174 
    175  // Step 5: For each Uint8Array array, enqueue array in ds's transform.
    176  for (const auto& view : array) {
    177    JS::Rooted<JS::Value> value(aCx, JS::ObjectValue(*view));
    178    aController.Enqueue(aCx, value, aRv);
    179    if (aRv.Failed()) {
    180      return;
    181    }
    182  }
    183 
    184  // Step 6: If the end of the compressed input has been reached, and ds's
    185  // context has not fully consumed chunk, then throw a TypeError.
    186  if (mObservedStreamEnd && !fullyConsumed) {
    187    aRv.ThrowTypeError("Unexpected input after the end of stream");
    188    return;
    189  }
    190 
    191  // Step 3 of
    192  // https://compression.spec.whatwg.org/#decompress-flush-and-enqueue
    193  // If the end of the compressed input has not been reached, then throw a
    194  // TypeError.
    195  if (aFlush == Flush::Yes && !mObservedStreamEnd) {
    196    aRv.ThrowTypeError("The input is ended without reaching the stream end");
    197    return;
    198  }
    199 }
    200 
    201 }  // namespace mozilla::dom::compression