tor-browser

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

ReadableStream.cpp (54750B)


      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 "mozilla/dom/ReadableStream.h"
      8 
      9 #include "ReadIntoRequest.h"
     10 #include "ReadableStreamPipeTo.h"
     11 #include "ReadableStreamTee.h"
     12 #include "StreamUtils.h"
     13 #include "TeeState.h"
     14 #include "js/Array.h"
     15 #include "js/Exception.h"
     16 #include "js/Iterator.h"
     17 #include "js/PropertyAndElement.h"
     18 #include "js/TypeDecls.h"
     19 #include "js/Value.h"
     20 #include "mozilla/AlreadyAddRefed.h"
     21 #include "mozilla/Assertions.h"
     22 #include "mozilla/Attributes.h"
     23 #include "mozilla/CycleCollectedJSContext.h"
     24 #include "mozilla/HoldDropJSObjects.h"
     25 #include "mozilla/StaticPrefs_dom.h"
     26 #include "mozilla/dom/BindingCallContext.h"
     27 #include "mozilla/dom/ByteStreamHelpers.h"
     28 #include "mozilla/dom/Promise-inl.h"
     29 #include "mozilla/dom/QueueWithSizes.h"
     30 #include "mozilla/dom/QueuingStrategyBinding.h"
     31 #include "mozilla/dom/ReadRequest.h"
     32 #include "mozilla/dom/ReadableByteStreamController.h"
     33 #include "mozilla/dom/ReadableStreamBYOBReader.h"
     34 #include "mozilla/dom/ReadableStreamBYOBRequest.h"
     35 #include "mozilla/dom/ReadableStreamBinding.h"
     36 #include "mozilla/dom/ReadableStreamControllerBase.h"
     37 #include "mozilla/dom/ReadableStreamDefaultController.h"
     38 #include "mozilla/dom/ReadableStreamDefaultReader.h"
     39 #include "mozilla/dom/RootedDictionary.h"
     40 #include "mozilla/dom/ScriptSettings.h"
     41 #include "mozilla/dom/UnderlyingSourceBinding.h"
     42 #include "mozilla/dom/UnderlyingSourceCallbackHelpers.h"
     43 #include "mozilla/dom/WritableStream.h"
     44 #include "mozilla/dom/WritableStreamDefaultWriter.h"
     45 #include "nsCOMPtr.h"
     46 #include "nsIGlobalObject.h"
     47 #include "nsISupports.h"
     48 
     49 inline void ImplCycleCollectionTraverse(
     50    nsCycleCollectionTraversalCallback& aCallback,
     51    mozilla::Variant<mozilla::Nothing,
     52                     RefPtr<mozilla::dom::ReadableStreamDefaultReader>>&
     53        aReader,
     54    const char* aName, uint32_t aFlags = 0) {
     55  if (aReader.is<RefPtr<mozilla::dom::ReadableStreamDefaultReader>>()) {
     56    ImplCycleCollectionTraverse(
     57        aCallback,
     58        aReader.as<RefPtr<mozilla::dom::ReadableStreamDefaultReader>>(), aName,
     59        aFlags);
     60  }
     61 }
     62 
     63 inline void ImplCycleCollectionUnlink(
     64    mozilla::Variant<mozilla::Nothing,
     65                     RefPtr<mozilla::dom::ReadableStreamDefaultReader>>&
     66        aReader) {
     67  aReader = AsVariant(mozilla::Nothing());
     68 }
     69 
     70 namespace mozilla::dom {
     71 
     72 using namespace streams_abstract;
     73 
     74 // Only needed for refcounted objects.
     75 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_WITH_JS_MEMBERS(
     76    ReadableStream, (mGlobal, mController, mReader), (mStoredError))
     77 
     78 NS_IMPL_CYCLE_COLLECTING_ADDREF(ReadableStream)
     79 NS_IMPL_CYCLE_COLLECTING_RELEASE(ReadableStream)
     80 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ReadableStream)
     81  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
     82  NS_INTERFACE_MAP_ENTRY(nsISupports)
     83 NS_INTERFACE_MAP_END
     84 
     85 ReadableStream::ReadableStream(nsIGlobalObject* aGlobal,
     86                               HoldDropJSObjectsCaller aHoldDropCaller)
     87    : mGlobal(aGlobal), mReader(nullptr), mHoldDropCaller(aHoldDropCaller) {
     88  if (mHoldDropCaller == HoldDropJSObjectsCaller::Implicit) {
     89    mozilla::HoldJSObjects(this);
     90  }
     91 }
     92 
     93 ReadableStream::ReadableStream(const GlobalObject& aGlobal,
     94                               HoldDropJSObjectsCaller aHoldDropCaller)
     95    : mGlobal(do_QueryInterface(aGlobal.GetAsSupports())),
     96      mReader(nullptr),
     97      mHoldDropCaller(aHoldDropCaller) {
     98  if (mHoldDropCaller == HoldDropJSObjectsCaller::Implicit) {
     99    mozilla::HoldJSObjects(this);
    100  }
    101 }
    102 
    103 ReadableStream::~ReadableStream() {
    104  if (mHoldDropCaller == HoldDropJSObjectsCaller::Implicit) {
    105    mozilla::DropJSObjects(this);
    106  }
    107 }
    108 
    109 JSObject* ReadableStream::WrapObject(JSContext* aCx,
    110                                     JS::Handle<JSObject*> aGivenProto) {
    111  return ReadableStream_Binding::Wrap(aCx, this, aGivenProto);
    112 }
    113 
    114 ReadableStreamDefaultReader* ReadableStream::GetDefaultReader() {
    115  return mReader->AsDefault();
    116 }
    117 
    118 void ReadableStream::SetReader(ReadableStreamGenericReader* aReader) {
    119  mReader = aReader;
    120 }
    121 
    122 namespace streams_abstract {
    123 
    124 // https://streams.spec.whatwg.org/#readable-stream-has-byob-reader
    125 bool ReadableStreamHasBYOBReader(ReadableStream* aStream) {
    126  // Step 1. Let reader be stream.[[reader]].
    127  ReadableStreamGenericReader* reader = aStream->GetReader();
    128 
    129  // Step 2. If reader is undefined, return false.
    130  if (!reader) {
    131    return false;
    132  }
    133 
    134  // Step 3. If reader implements ReadableStreamBYOBReader, return true.
    135  // Step 4. Return false.
    136  return reader->IsBYOB();
    137 }
    138 
    139 // https://streams.spec.whatwg.org/#readable-stream-has-default-reader
    140 bool ReadableStreamHasDefaultReader(ReadableStream* aStream) {
    141  // Step 1. Let reader be stream.[[reader]].
    142  ReadableStreamGenericReader* reader = aStream->GetReader();
    143 
    144  // Step 2. If reader is undefined, return false.
    145  if (!reader) {
    146    return false;
    147  }
    148 
    149  // Step 3. If reader implements ReadableStreamDefaultReader, return true.
    150  // Step 4. Return false.
    151  return reader->IsDefault();
    152 }
    153 
    154 }  // namespace streams_abstract
    155 
    156 // Streams Spec: 4.2.4: https://streams.spec.whatwg.org/#rs-prototype
    157 /* static */
    158 already_AddRefed<ReadableStream> ReadableStream::Constructor(
    159    const GlobalObject& aGlobal,
    160    const Optional<JS::Handle<JSObject*>>& aUnderlyingSource,
    161    const QueuingStrategy& aStrategy, ErrorResult& aRv) {
    162  // Step 1.
    163  JS::Rooted<JSObject*> underlyingSourceObj(
    164      aGlobal.Context(),
    165      aUnderlyingSource.WasPassed() ? aUnderlyingSource.Value() : nullptr);
    166 
    167  // Step 2.
    168  RootedDictionary<UnderlyingSource> underlyingSourceDict(aGlobal.Context());
    169  if (underlyingSourceObj) {
    170    JS::Rooted<JS::Value> objValue(aGlobal.Context(),
    171                                   JS::ObjectValue(*underlyingSourceObj));
    172    dom::BindingCallContext callCx(aGlobal.Context(),
    173                                   "ReadableStream.constructor");
    174    aRv.MightThrowJSException();
    175    if (!underlyingSourceDict.Init(callCx, objValue)) {
    176      aRv.StealExceptionFromJSContext(aGlobal.Context());
    177      return nullptr;
    178    }
    179  }
    180 
    181  // Step 3.
    182  RefPtr<ReadableStream> readableStream =
    183      new ReadableStream(aGlobal, HoldDropJSObjectsCaller::Implicit);
    184 
    185  // Step 4.
    186  if (underlyingSourceDict.mType.WasPassed()) {
    187    // Implicit assertion on above check.
    188    MOZ_ASSERT(underlyingSourceDict.mType.Value() == ReadableStreamType::Bytes);
    189 
    190    // Step 4.1
    191    if (aStrategy.mSize.WasPassed()) {
    192      aRv.ThrowRangeError("Implementation preserved member 'size'");
    193      return nullptr;
    194    }
    195 
    196    // Step 4.2
    197    double highWaterMark = ExtractHighWaterMark(aStrategy, 0, aRv);
    198    if (aRv.Failed()) {
    199      return nullptr;
    200    }
    201 
    202    // Step 4.3
    203    SetUpReadableByteStreamControllerFromUnderlyingSource(
    204        aGlobal.Context(), readableStream, underlyingSourceObj,
    205        underlyingSourceDict, highWaterMark, aRv);
    206    if (aRv.Failed()) {
    207      return nullptr;
    208    }
    209 
    210    return readableStream.forget();
    211  }
    212 
    213  // Step 5.1 (implicit in above check)
    214  // Step 5.2. Extract callback.
    215  //
    216  // Implementation Note: The specification demands that if the size doesn't
    217  // exist, we instead would provide an algorithm that returns 1. Instead, we
    218  // will teach callers that a missing callback should simply return 1, rather
    219  // than gin up a fake callback here.
    220  //
    221  // This decision may need to be revisited if the default action ever diverges
    222  // within the specification.
    223  RefPtr<QueuingStrategySize> sizeAlgorithm =
    224      aStrategy.mSize.WasPassed() ? &aStrategy.mSize.Value() : nullptr;
    225 
    226  // Step 5.3
    227  double highWaterMark = ExtractHighWaterMark(aStrategy, 1, aRv);
    228  if (aRv.Failed()) {
    229    return nullptr;
    230  }
    231 
    232  // Step 5.4.
    233  SetupReadableStreamDefaultControllerFromUnderlyingSource(
    234      aGlobal.Context(), readableStream, underlyingSourceObj,
    235      underlyingSourceDict, highWaterMark, sizeAlgorithm, aRv);
    236  if (aRv.Failed()) {
    237    return nullptr;
    238  }
    239 
    240  return readableStream.forget();
    241 }
    242 
    243 // https://streams.spec.whatwg.org/#readable-stream-from-iterable
    244 class ReadableStreamFromAlgorithms final
    245    : public UnderlyingSourceAlgorithmsWrapper {
    246 public:
    247  NS_DECL_ISUPPORTS_INHERITED
    248  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(
    249      ReadableStreamFromAlgorithms, UnderlyingSourceAlgorithmsWrapper)
    250 
    251  ReadableStreamFromAlgorithms(nsIGlobalObject* aGlobal,
    252                               JS::Handle<JSObject*> aIteratorRecord)
    253      : mGlobal(aGlobal), mIteratorRecordMaybeCrossRealm(aIteratorRecord) {
    254    mozilla::HoldJSObjects(this);
    255  };
    256 
    257  // Step 3. Let startAlgorithm be an algorithm that returns undefined.
    258  // Note: Provided by UnderlyingSourceAlgorithmsWrapper::StartCallback.
    259 
    260  // Step 4. Let pullAlgorithm be the following steps:
    261  MOZ_CAN_RUN_SCRIPT already_AddRefed<Promise> PullCallbackImpl(
    262      JSContext* aCx, ReadableStreamControllerBase& aController,
    263      ErrorResult& aRv) override {
    264    aRv.MightThrowJSException();
    265 
    266    JS::Rooted<JSObject*> iteratorRecord(aCx, mIteratorRecordMaybeCrossRealm);
    267    JSAutoRealm ar(aCx, iteratorRecord);
    268 
    269    // Step 1. Let nextResult be IteratorNext(iteratorRecord).
    270    JS::Rooted<JS::Value> nextResult(aCx);
    271    if (!JS::IteratorNext(aCx, iteratorRecord, &nextResult)) {
    272      // Step 2. If nextResult is an abrupt completion, return a promise
    273      // rejected with nextResult.[[Value]].
    274      aRv.StealExceptionFromJSContext(aCx);
    275      return nullptr;
    276    }
    277 
    278    // Step 3. Let nextPromise be a promise resolved with nextResult.[[Value]].
    279    RefPtr<Promise> nextPromise = Promise::CreateInfallible(mGlobal);
    280    nextPromise->MaybeResolve(nextResult);
    281 
    282    // Step 4. Return the result of reacting to nextPromise with the following
    283    // fulfillment steps, given iterResult:
    284    auto result = nextPromise->ThenWithCycleCollectedArgs(
    285        [](JSContext* aCx, JS::Handle<JS::Value> aIterResult, ErrorResult& aRv,
    286           const RefPtr<ReadableStreamDefaultController>& aController)
    287            MOZ_CAN_RUN_SCRIPT_FOR_DEFINITION -> already_AddRefed<Promise> {
    288              aRv.MightThrowJSException();
    289 
    290              // Step 4.1. If Type(iterResult) is not Object, throw a TypeError.
    291              if (!aIterResult.isObject()) {
    292                aRv.ThrowTypeError("next() returned a non-object value");
    293                return nullptr;
    294              }
    295 
    296              JS::Rooted<JSObject*> iterResult(aCx, &aIterResult.toObject());
    297 
    298              // Step 4.2. Let done be ? IteratorComplete(iterResult).
    299              bool done = false;
    300              if (!JS::IteratorComplete(aCx, iterResult, &done)) {
    301                aRv.StealExceptionFromJSContext(aCx);
    302                return nullptr;
    303              }
    304 
    305              // Step 4.3. If done is true:
    306              if (done) {
    307                // Step 4.3.1. Perform !
    308                // ReadableStreamDefaultControllerClose(stream.[[controller]]).
    309                ReadableStreamDefaultControllerClose(aCx, aController, aRv);
    310              } else {
    311                // Step 4.4. Otherwise:
    312                // Step 4.4.1. Let value be ? IteratorValue(iterResult).
    313                JS::Rooted<JS::Value> value(aCx);
    314                if (!JS::IteratorValue(aCx, iterResult, &value)) {
    315                  aRv.StealExceptionFromJSContext(aCx);
    316                  return nullptr;
    317                }
    318 
    319                // Step 4.4.2. Perform !
    320                // ReadableStreamDefaultControllerEnqueue(stream.[[controller]],
    321                // value).
    322                ReadableStreamDefaultControllerEnqueue(aCx, aController, value,
    323                                                       aRv);
    324              }
    325 
    326              return nullptr;
    327            },
    328        RefPtr(aController.AsDefault()));
    329    if (result.isErr()) {
    330      aRv.Throw(result.unwrapErr());
    331      return nullptr;
    332    }
    333    return result.unwrap().forget();
    334  };
    335 
    336  // Step 5. Let cancelAlgorithm be the following steps, given reason:
    337  MOZ_CAN_RUN_SCRIPT already_AddRefed<Promise> CancelCallbackImpl(
    338      JSContext* aCx, const Optional<JS::Handle<JS::Value>>& aReason,
    339      ErrorResult& aRv) override {
    340    aRv.MightThrowJSException();
    341 
    342    JS::Rooted<JSObject*> iteratorRecord(aCx, mIteratorRecordMaybeCrossRealm);
    343    JSAutoRealm ar(aCx, iteratorRecord);
    344 
    345    // Step 1. Let iterator be iteratorRecord.[[Iterator]].
    346    JS::Rooted<JS::Value> iterator(aCx);
    347    if (!JS::GetIteratorRecordIterator(aCx, iteratorRecord, &iterator)) {
    348      aRv.StealExceptionFromJSContext(aCx);
    349      return nullptr;
    350    }
    351 
    352    // Step 2. Let returnMethod be GetMethod(iterator, "return").
    353    JS::Rooted<JS::Value> returnMethod(aCx);
    354    if (!JS::GetReturnMethod(aCx, iterator, &returnMethod)) {
    355      // Step 3. If returnMethod is an abrupt completion, return a promise
    356      // rejected with returnMethod.[[Value]].
    357      aRv.StealExceptionFromJSContext(aCx);
    358      return nullptr;
    359    }
    360 
    361    // Step 4. If returnMethod.[[Value]] is undefined, return a promise resolved
    362    // with undefined.
    363    if (returnMethod.isUndefined()) {
    364      return Promise::CreateResolvedWithUndefined(mGlobal, aRv);
    365    }
    366 
    367    // Step 5. Let returnResult be Call(returnMethod.[[Value]], iterator, «
    368    // reason »).
    369    JS::Rooted<JS::Value> reason(aCx, aReason.Value());
    370    if (!JS_WrapValue(aCx, &reason)) {
    371      JS_ClearPendingException(aCx);
    372      aRv.Throw(NS_ERROR_UNEXPECTED);
    373      return nullptr;
    374    }
    375 
    376    JS::Rooted<JS::Value> returnResult(aCx);
    377    if (!JS::Call(aCx, iterator, returnMethod, JS::HandleValueArray(reason),
    378                  &returnResult)) {
    379      // Step 6. If returnResult is an abrupt completion, return a promise
    380      // rejected with returnResult.[[Value]].
    381      aRv.StealExceptionFromJSContext(aCx);
    382      return nullptr;
    383    }
    384 
    385    // Step 7. Let returnPromise be a promise resolved with
    386    // returnResult.[[Value]].
    387    RefPtr<Promise> returnPromise = Promise::CreateInfallible(mGlobal);
    388    returnPromise->MaybeResolve(returnResult);
    389 
    390    // Step 8. Return the result of reacting to returnPromise with the following
    391    // fulfillment steps, given iterResult:
    392    auto result = returnPromise->ThenWithCycleCollectedArgs(
    393        [](JSContext* aCx, JS::Handle<JS::Value> aIterResult, ErrorResult& aRv)
    394            MOZ_CAN_RUN_SCRIPT_FOR_DEFINITION -> already_AddRefed<Promise> {
    395              // Step 8.1. If Type(iterResult) is not Object, throw a TypeError.
    396              if (!aIterResult.isObject()) {
    397                aRv.ThrowTypeError("return() returned a non-object value");
    398                return nullptr;
    399              }
    400 
    401              // Step 8.2. Return undefined.
    402              return nullptr;
    403            });
    404    if (result.isErr()) {
    405      aRv.Throw(result.unwrapErr());
    406      return nullptr;
    407    }
    408    return result.unwrap().forget();
    409  };
    410 
    411 protected:
    412  ~ReadableStreamFromAlgorithms() override { mozilla::DropJSObjects(this); };
    413 
    414 private:
    415  // Virtually const, but are cycle collected
    416  nsCOMPtr<nsIGlobalObject> mGlobal;
    417  JS::Heap<JSObject*> mIteratorRecordMaybeCrossRealm;
    418 };
    419 
    420 NS_IMPL_CYCLE_COLLECTION_INHERITED_WITH_JS_MEMBERS(
    421    ReadableStreamFromAlgorithms, UnderlyingSourceAlgorithmsWrapper, (mGlobal),
    422    (mIteratorRecordMaybeCrossRealm))
    423 NS_IMPL_ADDREF_INHERITED(ReadableStreamFromAlgorithms,
    424                         UnderlyingSourceAlgorithmsWrapper)
    425 NS_IMPL_RELEASE_INHERITED(ReadableStreamFromAlgorithms,
    426                          UnderlyingSourceAlgorithmsWrapper)
    427 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ReadableStreamFromAlgorithms)
    428 NS_INTERFACE_MAP_END_INHERITING(UnderlyingSourceAlgorithmsWrapper)
    429 
    430 // https://streams.spec.whatwg.org/#readable-stream-from-iterable
    431 static already_AddRefed<ReadableStream> MOZ_CAN_RUN_SCRIPT
    432 ReadableStreamFromIterable(JSContext* aCx, nsIGlobalObject* aGlobal,
    433                           JS::Handle<JS::Value> aAsyncIterable,
    434                           ErrorResult& aRv) {
    435  aRv.MightThrowJSException();
    436 
    437  // Step 1. Let stream be undefined. (not required)
    438  // Step 2. Let iteratorRecord be ? GetIterator(asyncIterable, async).
    439  JS::Rooted<JSObject*> iteratorRecord(
    440      aCx, JS::GetIteratorObject(aCx, aAsyncIterable, true));
    441  if (!iteratorRecord) {
    442    aRv.StealExceptionFromJSContext(aCx);
    443    return nullptr;
    444  }
    445 
    446  // Steps 3-5. are in ReadableStreamFromAlgorithms.
    447  auto algorithms =
    448      MakeRefPtr<ReadableStreamFromAlgorithms>(aGlobal, iteratorRecord);
    449 
    450  // Step 6. Set stream to ! CreateReadableStream(startAlgorithm, pullAlgorithm,
    451  // cancelAlgorithm, 0).
    452  // Step 7. Return stream.
    453  return ReadableStream::CreateAbstract(aCx, aGlobal, algorithms,
    454                                        mozilla::Some(0.0), nullptr, aRv);
    455 }
    456 
    457 /* static */
    458 already_AddRefed<ReadableStream> ReadableStream::From(
    459    const GlobalObject& aGlobal, JS::Handle<JS::Value> aAsyncIterable,
    460    ErrorResult& aRv) {
    461  // Step 1. Return ? ReadableStreamFromIterable(asyncIterable).
    462  nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
    463  return ReadableStreamFromIterable(aGlobal.Context(), global, aAsyncIterable,
    464                                    aRv);
    465 }
    466 
    467 // Dealing with const this ptr is a pain, so just re-implement.
    468 // https://streams.spec.whatwg.org/#is-readable-stream-locked
    469 bool ReadableStream::Locked() const {
    470  // Step 1 + 2.
    471  return mReader;
    472 }
    473 
    474 namespace streams_abstract {
    475 // https://streams.spec.whatwg.org/#initialize-readable-stream
    476 static void InitializeReadableStream(ReadableStream* aStream) {
    477  // Step 1.
    478  aStream->SetState(ReadableStream::ReaderState::Readable);
    479 
    480  // Step 2.
    481  aStream->SetReader(nullptr);
    482  aStream->SetStoredError(JS::UndefinedHandleValue);
    483 
    484  // Step 3.
    485  aStream->SetDisturbed(false);
    486 }
    487 }  // namespace streams_abstract
    488 
    489 // https://streams.spec.whatwg.org/#create-readable-stream
    490 MOZ_CAN_RUN_SCRIPT
    491 already_AddRefed<ReadableStream> ReadableStream::CreateAbstract(
    492    JSContext* aCx, nsIGlobalObject* aGlobal,
    493    UnderlyingSourceAlgorithmsBase* aAlgorithms,
    494    mozilla::Maybe<double> aHighWaterMark, QueuingStrategySize* aSizeAlgorithm,
    495    ErrorResult& aRv) {
    496  // Step 1. If highWaterMark was not passed, set it to 1.
    497  double highWaterMark = aHighWaterMark.valueOr(1.0);
    498 
    499  // Step 2. consumers of sizeAlgorithm
    500  //         handle null algorithms correctly.
    501  // Step 3.
    502  MOZ_ASSERT(IsNonNegativeNumber(highWaterMark));
    503  // Step 4.
    504  RefPtr<ReadableStream> stream =
    505      new ReadableStream(aGlobal, HoldDropJSObjectsCaller::Implicit);
    506 
    507  // Step 5.
    508  InitializeReadableStream(stream);
    509 
    510  // Step 6.
    511  RefPtr<ReadableStreamDefaultController> controller =
    512      new ReadableStreamDefaultController(aGlobal);
    513 
    514  // Step 7.
    515  SetUpReadableStreamDefaultController(aCx, stream, controller, aAlgorithms,
    516                                       highWaterMark, aSizeAlgorithm, aRv);
    517 
    518  // Step 8.
    519  return stream.forget();
    520 }
    521 
    522 namespace streams_abstract {
    523 // https://streams.spec.whatwg.org/#readable-stream-close
    524 void ReadableStreamClose(JSContext* aCx, ReadableStream* aStream,
    525                         ErrorResult& aRv) {
    526  // Step 1.
    527  MOZ_ASSERT(aStream->State() == ReadableStream::ReaderState::Readable);
    528 
    529  // Step 2.
    530  aStream->SetState(ReadableStream::ReaderState::Closed);
    531 
    532  // Step 3.
    533  ReadableStreamGenericReader* reader = aStream->GetReader();
    534 
    535  // Step 4.
    536  if (!reader) {
    537    return;
    538  }
    539 
    540  // Step 5.
    541  reader->ClosedPromise()->MaybeResolveWithUndefined();
    542 
    543  // Step 6.
    544  if (reader->IsDefault()) {
    545    // Step 6.1. Let readRequests be reader.[[readRequests]].
    546    // Move LinkedList out of DefaultReader onto stack to avoid the potential
    547    // for concurrent modification, which could invalidate the iterator.
    548    //
    549    // See https://bugs.chromium.org/p/chromium/issues/detail?id=1045874 as an
    550    // example of the kind of issue that could occur.
    551    LinkedList<RefPtr<ReadRequest>> readRequests =
    552        std::move(reader->AsDefault()->ReadRequests());
    553 
    554    // Step 6.2. Set reader.[[readRequests]] to an empty list.
    555    // Note: The std::move already cleared this anyway.
    556    reader->AsDefault()->ReadRequests().clear();
    557 
    558    // Step 6.3. For each readRequest of readRequests,
    559    // Drain the local list and destroy elements along the way.
    560    while (RefPtr<ReadRequest> readRequest = readRequests.popFirst()) {
    561      // Step 6.3.1. Perform readRequest’s close steps.
    562      readRequest->CloseSteps(aCx, aRv);
    563      if (aRv.Failed()) {
    564        return;
    565      }
    566    }
    567  }
    568 }
    569 
    570 // https://streams.spec.whatwg.org/#readable-stream-cancel
    571 already_AddRefed<Promise> ReadableStreamCancel(JSContext* aCx,
    572                                               ReadableStream* aStream,
    573                                               JS::Handle<JS::Value> aError,
    574                                               ErrorResult& aRv) {
    575  // Step 1.
    576  aStream->SetDisturbed(true);
    577 
    578  // Step 2.
    579  if (aStream->State() == ReadableStream::ReaderState::Closed) {
    580    RefPtr<Promise> promise =
    581        Promise::CreateInfallible(aStream->GetParentObject());
    582    promise->MaybeResolveWithUndefined();
    583    return promise.forget();
    584  }
    585 
    586  // Step 3.
    587  if (aStream->State() == ReadableStream::ReaderState::Errored) {
    588    JS::Rooted<JS::Value> storedError(aCx, aStream->StoredError());
    589    return Promise::CreateRejected(aStream->GetParentObject(), storedError,
    590                                   aRv);
    591  }
    592 
    593  // Step 4.
    594  ReadableStreamClose(aCx, aStream, aRv);
    595  if (aRv.Failed()) {
    596    return nullptr;
    597  }
    598 
    599  // Step 5.
    600  ReadableStreamGenericReader* reader = aStream->GetReader();
    601 
    602  // Step 6.
    603  if (reader && reader->IsBYOB()) {
    604    // Step 6.1. Let readIntoRequests be reader.[[readIntoRequests]].
    605    LinkedList<RefPtr<ReadIntoRequest>> readIntoRequests =
    606        std::move(reader->AsBYOB()->ReadIntoRequests());
    607 
    608    // Step 6.2. Set reader.[[readIntoRequests]] to an empty list.
    609    // Note: The std::move already cleared this anyway.
    610    reader->AsBYOB()->ReadIntoRequests().clear();
    611 
    612    // Step 6.3. For each readIntoRequest of readIntoRequests,
    613    while (RefPtr<ReadIntoRequest> readIntoRequest =
    614               readIntoRequests.popFirst()) {
    615      // Step 6.3.1.Perform readIntoRequest’s close steps, given undefined.
    616      readIntoRequest->CloseSteps(aCx, JS::UndefinedHandleValue, aRv);
    617      if (aRv.Failed()) {
    618        return nullptr;
    619      }
    620    }
    621  }
    622 
    623  // Step 7.
    624  RefPtr<ReadableStreamControllerBase> controller(aStream->Controller());
    625  RefPtr<Promise> sourceCancelPromise =
    626      controller->CancelSteps(aCx, aError, aRv);
    627  if (aRv.Failed()) {
    628    return nullptr;
    629  }
    630 
    631  // Step 8.
    632  RefPtr<Promise> promise =
    633      Promise::CreateInfallible(sourceCancelPromise->GetParentObject());
    634 
    635  // ThenWithCycleCollectedArgs will carry promise, keeping it alive until the
    636  // callback executes.
    637  Result<RefPtr<Promise>, nsresult> returnResult =
    638      sourceCancelPromise->ThenWithCycleCollectedArgs(
    639          [](JSContext*, JS::Handle<JS::Value>, ErrorResult&,
    640             RefPtr<Promise> newPromise) {
    641            newPromise->MaybeResolveWithUndefined();
    642            return newPromise.forget();
    643          },
    644          promise);
    645 
    646  if (returnResult.isErr()) {
    647    aRv.Throw(returnResult.unwrapErr());
    648    return nullptr;
    649  }
    650 
    651  return returnResult.unwrap().forget();
    652 }
    653 
    654 }  // namespace streams_abstract
    655 
    656 // https://streams.spec.whatwg.org/#rs-cancel
    657 already_AddRefed<Promise> ReadableStream::Cancel(JSContext* aCx,
    658                                                 JS::Handle<JS::Value> aReason,
    659                                                 ErrorResult& aRv) {
    660  // Step 1. If ! IsReadableStreamLocked(this) is true,
    661  // return a promise rejected with a TypeError exception.
    662  if (Locked()) {
    663    aRv.ThrowTypeError("Cannot cancel a stream locked by a reader.");
    664    return nullptr;
    665  }
    666 
    667  // Step 2. Return ! ReadableStreamCancel(this, reason).
    668  RefPtr<ReadableStream> thisRefPtr = this;
    669  return ReadableStreamCancel(aCx, thisRefPtr, aReason, aRv);
    670 }
    671 
    672 namespace streams_abstract {
    673 // https://streams.spec.whatwg.org/#acquire-readable-stream-reader
    674 already_AddRefed<ReadableStreamDefaultReader>
    675 AcquireReadableStreamDefaultReader(ReadableStream* aStream, ErrorResult& aRv) {
    676  // Step 1.
    677  RefPtr<ReadableStreamDefaultReader> reader =
    678      new ReadableStreamDefaultReader(aStream->GetParentObject());
    679 
    680  // Step 2.
    681  SetUpReadableStreamDefaultReader(reader, aStream, aRv);
    682  if (aRv.Failed()) {
    683    return nullptr;
    684  }
    685 
    686  // Step 3.
    687  return reader.forget();
    688 }
    689 }  // namespace streams_abstract
    690 
    691 // https://streams.spec.whatwg.org/#rs-get-reader
    692 void ReadableStream::GetReader(const ReadableStreamGetReaderOptions& aOptions,
    693                               OwningReadableStreamReader& resultReader,
    694                               ErrorResult& aRv) {
    695  // Step 1. If options["mode"] does not exist,
    696  // return ? AcquireReadableStreamDefaultReader(this).
    697  if (!aOptions.mMode.WasPassed()) {
    698    RefPtr<ReadableStreamDefaultReader> defaultReader =
    699        AcquireReadableStreamDefaultReader(this, aRv);
    700    if (aRv.Failed()) {
    701      return;
    702    }
    703    resultReader.SetAsReadableStreamDefaultReader() = defaultReader;
    704    return;
    705  }
    706 
    707  // Step 2. Assert: options["mode"] is "byob".
    708  MOZ_ASSERT(aOptions.mMode.Value() == ReadableStreamReaderMode::Byob);
    709 
    710  // Step 3. Return ? AcquireReadableStreamBYOBReader(this).
    711  RefPtr<ReadableStreamBYOBReader> byobReader =
    712      AcquireReadableStreamBYOBReader(this, aRv);
    713  if (aRv.Failed()) {
    714    return;
    715  }
    716  resultReader.SetAsReadableStreamBYOBReader() = byobReader;
    717 }
    718 
    719 namespace streams_abstract {
    720 // https://streams.spec.whatwg.org/#is-readable-stream-locked
    721 bool IsReadableStreamLocked(ReadableStream* aStream) {
    722  // Step 1 + 2.
    723  return aStream->Locked();
    724 }
    725 }  // namespace streams_abstract
    726 
    727 // https://streams.spec.whatwg.org/#rs-pipe-through
    728 MOZ_CAN_RUN_SCRIPT already_AddRefed<ReadableStream> ReadableStream::PipeThrough(
    729    const ReadableWritablePair& aTransform, const StreamPipeOptions& aOptions,
    730    ErrorResult& aRv) {
    731  // Step 1: If ! IsReadableStreamLocked(this) is true, throw a TypeError
    732  // exception.
    733  if (IsReadableStreamLocked(this)) {
    734    aRv.ThrowTypeError("Cannot pipe from a locked stream.");
    735    return nullptr;
    736  }
    737 
    738  // Step 2: If ! IsWritableStreamLocked(transform["writable"]) is true, throw a
    739  // TypeError exception.
    740  if (IsWritableStreamLocked(aTransform.mWritable)) {
    741    aRv.ThrowTypeError("Cannot pipe to a locked stream.");
    742    return nullptr;
    743  }
    744 
    745  // Step 3: Let signal be options["signal"] if it exists, or undefined
    746  // otherwise.
    747  RefPtr<AbortSignal> signal =
    748      aOptions.mSignal.WasPassed() ? &aOptions.mSignal.Value() : nullptr;
    749 
    750  // Step 4: Let promise be ! ReadableStreamPipeTo(this, transform["writable"],
    751  // options["preventClose"], options["preventAbort"], options["preventCancel"],
    752  // signal).
    753  RefPtr<WritableStream> writable = aTransform.mWritable;
    754  RefPtr<Promise> promise = ReadableStreamPipeTo(
    755      this, writable, aOptions.mPreventClose, aOptions.mPreventAbort,
    756      aOptions.mPreventCancel, signal, aRv);
    757  if (aRv.Failed()) {
    758    return nullptr;
    759  }
    760 
    761  // Step 5: Set promise.[[PromiseIsHandled]] to true.
    762  MOZ_ALWAYS_TRUE(promise->SetAnyPromiseIsHandled());
    763 
    764  // Step 6: Return transform["readable"].
    765  return do_AddRef(aTransform.mReadable.get());
    766 };
    767 
    768 namespace streams_abstract {
    769 
    770 // https://streams.spec.whatwg.org/#readable-stream-get-num-read-requests
    771 double ReadableStreamGetNumReadRequests(ReadableStream* aStream) {
    772  // Step 1.
    773  MOZ_ASSERT(ReadableStreamHasDefaultReader(aStream));
    774 
    775  // Step 2.
    776  return double(aStream->GetDefaultReader()->ReadRequests().length());
    777 }
    778 
    779 // https://streams.spec.whatwg.org/#readable-stream-error
    780 void ReadableStreamError(JSContext* aCx, ReadableStream* aStream,
    781                         JS::Handle<JS::Value> aValue, ErrorResult& aRv) {
    782  // Step 1.
    783  MOZ_ASSERT(aStream->State() == ReadableStream::ReaderState::Readable);
    784 
    785  // Step 2.
    786  aStream->SetState(ReadableStream::ReaderState::Errored);
    787 
    788  // Step 3.
    789  aStream->SetStoredError(aValue);
    790 
    791  // Step 4.
    792  ReadableStreamGenericReader* reader = aStream->GetReader();
    793 
    794  // Step 5.
    795  if (!reader) {
    796    return;
    797  }
    798 
    799  // Step 6.
    800  reader->ClosedPromise()->MaybeReject(aValue);
    801 
    802  // Step 7.
    803  reader->ClosedPromise()->SetSettledPromiseIsHandled();
    804 
    805  // Step 8.
    806  if (reader->IsDefault()) {
    807    // Step 8.1. Perform ! ReadableStreamDefaultReaderErrorReadRequests(reader,
    808    // e).
    809    RefPtr<ReadableStreamDefaultReader> defaultReader = reader->AsDefault();
    810    ReadableStreamDefaultReaderErrorReadRequests(aCx, defaultReader, aValue,
    811                                                 aRv);
    812    if (aRv.Failed()) {
    813      return;
    814    }
    815  } else {
    816    // Step 9. Otherwise,
    817    // Step 9.1. Assert: reader implements ReadableStreamBYOBReader.
    818    MOZ_ASSERT(reader->IsBYOB());
    819 
    820    // Step 9.2. Perform ! ReadableStreamBYOBReaderErrorReadIntoRequests(reader,
    821    // e).
    822    RefPtr<ReadableStreamBYOBReader> byobReader = reader->AsBYOB();
    823    ReadableStreamBYOBReaderErrorReadIntoRequests(aCx, byobReader, aValue, aRv);
    824    if (aRv.Failed()) {
    825      return;
    826    }
    827  }
    828 }
    829 
    830 // https://streams.spec.whatwg.org/#rs-default-controller-close
    831 void ReadableStreamFulfillReadRequest(JSContext* aCx, ReadableStream* aStream,
    832                                      JS::Handle<JS::Value> aChunk, bool aDone,
    833                                      ErrorResult& aRv) {
    834  // Step 1.
    835  MOZ_ASSERT(ReadableStreamHasDefaultReader(aStream));
    836 
    837  // Step 2.
    838  ReadableStreamDefaultReader* reader = aStream->GetDefaultReader();
    839 
    840  // Step 3.
    841  MOZ_ASSERT(!reader->ReadRequests().isEmpty());
    842 
    843  // Step 4+5.
    844  RefPtr<ReadRequest> readRequest = reader->ReadRequests().popFirst();
    845 
    846  // Step 6.
    847  if (aDone) {
    848    readRequest->CloseSteps(aCx, aRv);
    849    if (aRv.Failed()) {
    850      return;
    851    }
    852  }
    853 
    854  // Step 7.
    855  readRequest->ChunkSteps(aCx, aChunk, aRv);
    856 }
    857 
    858 // https://streams.spec.whatwg.org/#readable-stream-add-read-request
    859 void ReadableStreamAddReadRequest(ReadableStream* aStream,
    860                                  ReadRequest* aReadRequest) {
    861  // Step 1.
    862  MOZ_ASSERT(aStream->GetReader()->IsDefault());
    863  // Step 2.
    864  MOZ_ASSERT(aStream->State() == ReadableStream::ReaderState::Readable);
    865  // Step 3.
    866  aStream->GetDefaultReader()->ReadRequests().insertBack(aReadRequest);
    867 }
    868 
    869 }  // namespace streams_abstract
    870 
    871 // https://streams.spec.whatwg.org/#abstract-opdef-readablestreamdefaulttee
    872 // Step 14, 15
    873 MOZ_CAN_RUN_SCRIPT already_AddRefed<Promise>
    874 ReadableStreamDefaultTeeSourceAlgorithms::CancelCallback(
    875    JSContext* aCx, const Optional<JS::Handle<JS::Value>>& aReason,
    876    ErrorResult& aRv) {
    877  // Step 1.
    878  mTeeState->SetCanceled(mBranch, true);
    879 
    880  // Step 2.
    881  mTeeState->SetReason(mBranch, aReason.Value());
    882 
    883  // Step 3.
    884 
    885  if (mTeeState->Canceled(OtherTeeBranch(mBranch))) {
    886    // Step 3.1
    887 
    888    JS::Rooted<JSObject*> compositeReason(aCx, JS::NewArrayObject(aCx, 2));
    889    if (!compositeReason) {
    890      aRv.StealExceptionFromJSContext(aCx);
    891      return nullptr;
    892    }
    893 
    894    JS::Rooted<JS::Value> reason1(aCx, mTeeState->Reason1());
    895    if (!JS_SetElement(aCx, compositeReason, 0, reason1)) {
    896      aRv.StealExceptionFromJSContext(aCx);
    897      return nullptr;
    898    }
    899 
    900    JS::Rooted<JS::Value> reason2(aCx, mTeeState->Reason2());
    901    if (!JS_SetElement(aCx, compositeReason, 1, reason2)) {
    902      aRv.StealExceptionFromJSContext(aCx);
    903      return nullptr;
    904    }
    905 
    906    // Step 3.2
    907    JS::Rooted<JS::Value> compositeReasonValue(
    908        aCx, JS::ObjectValue(*compositeReason));
    909    RefPtr<ReadableStream> stream(mTeeState->GetStream());
    910    RefPtr<Promise> cancelResult =
    911        ReadableStreamCancel(aCx, stream, compositeReasonValue, aRv);
    912    if (aRv.Failed()) {
    913      return nullptr;
    914    }
    915 
    916    // Step 3.3
    917    mTeeState->CancelPromise()->MaybeResolve(cancelResult);
    918  }
    919 
    920  // Step 4.
    921  return do_AddRef(mTeeState->CancelPromise());
    922 }
    923 
    924 // https://streams.spec.whatwg.org/#abstract-opdef-readablestreamdefaulttee
    925 MOZ_CAN_RUN_SCRIPT
    926 static void ReadableStreamDefaultTee(JSContext* aCx, ReadableStream* aStream,
    927                                     bool aCloneForBranch2,
    928                                     nsTArray<RefPtr<ReadableStream>>& aResult,
    929                                     ErrorResult& aRv) {
    930  // Step 1. Implicit.
    931  // Step 2. Implicit.
    932 
    933  // Steps 3-12 are contained in the construction of Tee State.
    934  RefPtr<TeeState> teeState = TeeState::Create(aStream, aCloneForBranch2, aRv);
    935  if (aRv.Failed()) {
    936    return;
    937  }
    938 
    939  // Step 13 - 16
    940  auto branch1Algorithms = MakeRefPtr<ReadableStreamDefaultTeeSourceAlgorithms>(
    941      teeState, TeeBranch::Branch1);
    942  auto branch2Algorithms = MakeRefPtr<ReadableStreamDefaultTeeSourceAlgorithms>(
    943      teeState, TeeBranch::Branch2);
    944 
    945  // Step 17.
    946  nsCOMPtr<nsIGlobalObject> global(
    947      do_AddRef(teeState->GetStream()->GetParentObject()));
    948  teeState->SetBranch1(ReadableStream::CreateAbstract(
    949      aCx, global, branch1Algorithms, mozilla::Nothing(), nullptr, aRv));
    950  if (aRv.Failed()) {
    951    return;
    952  }
    953 
    954  // Step 18.
    955  teeState->SetBranch2(ReadableStream::CreateAbstract(
    956      aCx, global, branch2Algorithms, mozilla::Nothing(), nullptr, aRv));
    957  if (aRv.Failed()) {
    958    return;
    959  }
    960 
    961  // Step 19.
    962  teeState->GetReader()->ClosedPromise()->AddCallbacksWithCycleCollectedArgs(
    963      [](JSContext* aCx, JS::Handle<JS::Value> aValue, ErrorResult& aRv,
    964         TeeState* aTeeState) {},
    965      [](JSContext* aCx, JS::Handle<JS::Value> aReason, ErrorResult& aRv,
    966         TeeState* aTeeState) {
    967        // Step 19.1.
    968        ReadableStreamDefaultControllerError(
    969            aCx, aTeeState->Branch1()->DefaultController(), aReason, aRv);
    970        if (aRv.Failed()) {
    971          return;
    972        }
    973 
    974        // Step 19.2
    975        ReadableStreamDefaultControllerError(
    976            aCx, aTeeState->Branch2()->DefaultController(), aReason, aRv);
    977        if (aRv.Failed()) {
    978          return;
    979        }
    980 
    981        // Step 19.3
    982        if (!aTeeState->Canceled1() || !aTeeState->Canceled2()) {
    983          aTeeState->CancelPromise()->MaybeResolveWithUndefined();
    984        }
    985      },
    986      RefPtr(teeState));
    987 
    988  // Step 20.
    989  aResult.AppendElement(teeState->Branch1());
    990  aResult.AppendElement(teeState->Branch2());
    991 }
    992 
    993 // https://streams.spec.whatwg.org/#rs-pipe-to
    994 already_AddRefed<Promise> ReadableStream::PipeTo(
    995    WritableStream& aDestination, const StreamPipeOptions& aOptions,
    996    ErrorResult& aRv) {
    997  // Step 1. If !IsReadableStreamLocked(this) is true, return a promise rejected
    998  // with a TypeError exception.
    999  if (IsReadableStreamLocked(this)) {
   1000    aRv.ThrowTypeError("Cannot pipe from a locked stream.");
   1001    return nullptr;
   1002  }
   1003 
   1004  // Step 2. If !IsWritableStreamLocked(destination) is true, return a promise
   1005  //         rejected with a TypeError exception.
   1006  if (IsWritableStreamLocked(&aDestination)) {
   1007    aRv.ThrowTypeError("Cannot pipe to a locked stream.");
   1008    return nullptr;
   1009  }
   1010 
   1011  // Step 3. Let signal be options["signal"] if it exists, or undefined
   1012  // otherwise.
   1013  RefPtr<AbortSignal> signal =
   1014      aOptions.mSignal.WasPassed() ? &aOptions.mSignal.Value() : nullptr;
   1015 
   1016  // Step 4. Return ! ReadableStreamPipeTo(this, destination,
   1017  // options["preventClose"], options["preventAbort"], options["preventCancel"],
   1018  // signal).
   1019  return ReadableStreamPipeTo(this, &aDestination, aOptions.mPreventClose,
   1020                              aOptions.mPreventAbort, aOptions.mPreventCancel,
   1021                              signal, aRv);
   1022 }
   1023 
   1024 // https://streams.spec.whatwg.org/#readable-stream-tee
   1025 MOZ_CAN_RUN_SCRIPT
   1026 static void ReadableStreamTee(JSContext* aCx, ReadableStream* aStream,
   1027                              bool aCloneForBranch2,
   1028                              nsTArray<RefPtr<ReadableStream>>& aResult,
   1029                              ErrorResult& aRv) {
   1030  // Step 1. Implicit.
   1031  // Step 2. Implicit.
   1032  // Step 3.
   1033  if (aStream->Controller()->IsByte()) {
   1034    ReadableByteStreamTee(aCx, aStream, aResult, aRv);
   1035    return;
   1036  }
   1037  // Step 4.
   1038  ReadableStreamDefaultTee(aCx, aStream, aCloneForBranch2, aResult, aRv);
   1039 }
   1040 
   1041 void ReadableStream::Tee(JSContext* aCx,
   1042                         nsTArray<RefPtr<ReadableStream>>& aResult,
   1043                         ErrorResult& aRv) {
   1044  ReadableStreamTee(aCx, this, false, aResult, aRv);
   1045 }
   1046 
   1047 void ReadableStream::IteratorData::Traverse(
   1048    nsCycleCollectionTraversalCallback& cb) {
   1049  ReadableStream::IteratorData* tmp = this;
   1050  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mReader);
   1051 }
   1052 void ReadableStream::IteratorData::Unlink() {
   1053  ReadableStream::IteratorData* tmp = this;
   1054  NS_IMPL_CYCLE_COLLECTION_UNLINK(mReader);
   1055 }
   1056 
   1057 // https://streams.spec.whatwg.org/#rs-get-iterator
   1058 void ReadableStream::InitAsyncIteratorData(
   1059    IteratorData& aData, Iterator::IteratorType aType,
   1060    const ReadableStreamIteratorOptions& aOptions, ErrorResult& aRv) {
   1061  // Step 1. Let reader be ? AcquireReadableStreamDefaultReader(stream).
   1062  RefPtr<ReadableStreamDefaultReader> reader =
   1063      AcquireReadableStreamDefaultReader(this, aRv);
   1064  if (aRv.Failed()) {
   1065    return;
   1066  }
   1067 
   1068  // Step 2. Set iterator’s reader to reader.
   1069  aData.mReader = reader;
   1070 
   1071  // Step 3. Let preventCancel be args[0]["preventCancel"].
   1072  // Step 4. Set iterator’s prevent cancel to preventCancel.
   1073  aData.mPreventCancel = aOptions.mPreventCancel;
   1074 }
   1075 
   1076 // https://streams.spec.whatwg.org/#rs-asynciterator-prototype-next
   1077 // Step 4.
   1078 struct IteratorReadRequest : public ReadRequest {
   1079 public:
   1080  NS_DECL_ISUPPORTS_INHERITED
   1081  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(IteratorReadRequest, ReadRequest)
   1082 
   1083  RefPtr<Promise> mPromise;
   1084  RefPtr<ReadableStreamDefaultReader> mReader;
   1085 
   1086  explicit IteratorReadRequest(Promise* aPromise,
   1087                               ReadableStreamDefaultReader* aReader)
   1088      : mPromise(aPromise), mReader(aReader) {}
   1089 
   1090  // chunk steps, given chunk
   1091  void ChunkSteps(JSContext* aCx, JS::Handle<JS::Value> aChunk,
   1092                  ErrorResult& aRv) override {
   1093    // Step 1. Resolve promise with chunk.
   1094    mPromise->MaybeResolve(aChunk);
   1095  }
   1096 
   1097  // close steps
   1098  void CloseSteps(JSContext* aCx, ErrorResult& aRv) override {
   1099    // Step 1. Perform ! ReadableStreamDefaultReaderRelease(reader).
   1100    ReadableStreamDefaultReaderRelease(aCx, mReader, aRv);
   1101    if (aRv.Failed()) {
   1102      mPromise->MaybeRejectWithUndefined();
   1103      return;
   1104    }
   1105 
   1106    // Step 2. Resolve promise with end of iteration.
   1107    iterator_utils::ResolvePromiseForFinished(mPromise);
   1108  }
   1109 
   1110  // error steps, given e
   1111  void ErrorSteps(JSContext* aCx, JS::Handle<JS::Value> aError,
   1112                  ErrorResult& aRv) override {
   1113    // Step 1. Perform ! ReadableStreamDefaultReaderRelease(reader).
   1114    ReadableStreamDefaultReaderRelease(aCx, mReader, aRv);
   1115    if (aRv.Failed()) {
   1116      mPromise->MaybeRejectWithUndefined();
   1117      return;
   1118    }
   1119 
   1120    // Step 2. Reject promise with e.
   1121    mPromise->MaybeReject(aError);
   1122  }
   1123 
   1124 protected:
   1125  virtual ~IteratorReadRequest() = default;
   1126 };
   1127 
   1128 NS_IMPL_CYCLE_COLLECTION_INHERITED(IteratorReadRequest, ReadRequest, mPromise,
   1129                                   mReader)
   1130 
   1131 NS_IMPL_ADDREF_INHERITED(IteratorReadRequest, ReadRequest)
   1132 NS_IMPL_RELEASE_INHERITED(IteratorReadRequest, ReadRequest)
   1133 
   1134 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(IteratorReadRequest)
   1135 NS_INTERFACE_MAP_END_INHERITING(ReadRequest)
   1136 
   1137 // https://streams.spec.whatwg.org/#rs-asynciterator-prototype-next
   1138 already_AddRefed<Promise> ReadableStream::GetNextIterationResult(
   1139    Iterator* aIterator, ErrorResult& aRv) {
   1140  // Step 1. Let reader be iterator’s reader.
   1141  RefPtr<ReadableStreamDefaultReader> reader = aIterator->Data().mReader;
   1142 
   1143  // Step 2. Assert: reader.[[stream]] is not undefined.
   1144  MOZ_ASSERT(reader->GetStream());
   1145 
   1146  // Step 3. Let promise be a new promise.
   1147  RefPtr<Promise> promise = Promise::CreateInfallible(GetParentObject());
   1148 
   1149  // Step 4. Let readRequest be a new read request with the following items:
   1150  RefPtr<ReadRequest> request = new IteratorReadRequest(promise, reader);
   1151 
   1152  // Step 5. Perform ! ReadableStreamDefaultReaderRead(this, readRequest).
   1153  AutoJSAPI jsapi;
   1154  if (!jsapi.Init(mGlobal)) {
   1155    aRv.ThrowUnknownError("Internal error");
   1156    return nullptr;
   1157  }
   1158 
   1159  ReadableStreamDefaultReaderRead(jsapi.cx(), reader, request, aRv);
   1160  if (aRv.Failed()) {
   1161    return nullptr;
   1162  }
   1163 
   1164  // Step 6. Return promise.
   1165  return promise.forget();
   1166 }
   1167 
   1168 // https://streams.spec.whatwg.org/#rs-asynciterator-prototype-return
   1169 already_AddRefed<Promise> ReadableStream::IteratorReturn(
   1170    JSContext* aCx, Iterator* aIterator, JS::Handle<JS::Value> aValue,
   1171    ErrorResult& aRv) {
   1172  // Step 1. Let reader be iterator’s reader.
   1173  RefPtr<ReadableStreamDefaultReader> reader = aIterator->Data().mReader;
   1174 
   1175  // Step 2. Assert: reader.[[stream]] is not undefined.
   1176  MOZ_ASSERT(reader->GetStream());
   1177 
   1178  // Step 3. Assert: reader.[[readRequests]] is empty, as the async iterator
   1179  // machinery guarantees that any previous calls to next() have settled before
   1180  // this is called.
   1181  MOZ_ASSERT(reader->ReadRequests().isEmpty());
   1182 
   1183  // Step 4. If iterator’s prevent cancel is false:
   1184  if (!aIterator->Data().mPreventCancel) {
   1185    // Step 4.1. Let result be ! ReadableStreamReaderGenericCancel(reader, arg).
   1186    RefPtr<ReadableStream> stream(reader->GetStream());
   1187    RefPtr<Promise> result = ReadableStreamCancel(aCx, stream, aValue, aRv);
   1188    if (NS_WARN_IF(aRv.Failed())) {
   1189      return nullptr;
   1190    }
   1191 
   1192    MOZ_DIAGNOSTIC_ASSERT(
   1193        reader->GetStream(),
   1194        "We shouldn't have a null stream here (bug 1821169).");
   1195    if (!reader->GetStream()) {
   1196      aRv.Throw(NS_ERROR_FAILURE);
   1197      return nullptr;
   1198    }
   1199 
   1200    // Step 4.2. Perform ! ReadableStreamDefaultReaderRelease(reader).
   1201    ReadableStreamDefaultReaderRelease(aCx, reader, aRv);
   1202    if (NS_WARN_IF(aRv.Failed())) {
   1203      return nullptr;
   1204    }
   1205 
   1206    // Step 4.3. Return result.
   1207    return result.forget();
   1208  }
   1209 
   1210  // Step 5. Perform ! ReadableStreamDefaultReaderRelease(reader).
   1211  ReadableStreamDefaultReaderRelease(aCx, reader, aRv);
   1212  if (NS_WARN_IF(aRv.Failed())) {
   1213    return nullptr;
   1214  }
   1215 
   1216  // Step 6. Return a promise resolved with undefined.
   1217  return Promise::CreateResolvedWithUndefined(GetParentObject(), aRv);
   1218 }
   1219 
   1220 namespace streams_abstract {
   1221 // https://streams.spec.whatwg.org/#readable-stream-add-read-into-request
   1222 void ReadableStreamAddReadIntoRequest(ReadableStream* aStream,
   1223                                      ReadIntoRequest* aReadIntoRequest) {
   1224  // Step 1. Assert: stream.[[reader]] implements ReadableStreamBYOBReader.
   1225  MOZ_ASSERT(aStream->GetReader()->IsBYOB());
   1226 
   1227  // Step 2. Assert: stream.[[state]] is "readable" or "closed".
   1228  MOZ_ASSERT(aStream->State() == ReadableStream::ReaderState::Readable ||
   1229             aStream->State() == ReadableStream::ReaderState::Closed);
   1230 
   1231  // Step 3. Append readRequest to stream.[[reader]].[[readIntoRequests]].
   1232  aStream->GetReader()->AsBYOB()->ReadIntoRequests().insertBack(
   1233      aReadIntoRequest);
   1234 }
   1235 }  // namespace streams_abstract
   1236 
   1237 // https://streams.spec.whatwg.org/#abstract-opdef-createreadablebytestream
   1238 already_AddRefed<ReadableStream> ReadableStream::CreateByteAbstract(
   1239    JSContext* aCx, nsIGlobalObject* aGlobal,
   1240    UnderlyingSourceAlgorithmsBase* aAlgorithms, ErrorResult& aRv) {
   1241  // Step 1. Let stream be a new ReadableStream.
   1242  RefPtr<ReadableStream> stream =
   1243      new ReadableStream(aGlobal, HoldDropJSObjectsCaller::Implicit);
   1244 
   1245  // Step 2. Perform ! InitializeReadableStream(stream).
   1246  InitializeReadableStream(stream);
   1247 
   1248  // Step 3. Let controller be a new ReadableByteStreamController.
   1249  RefPtr<ReadableByteStreamController> controller =
   1250      new ReadableByteStreamController(aGlobal);
   1251 
   1252  // Step 4. Perform ? SetUpReadableByteStreamController(stream, controller,
   1253  // startAlgorithm, pullAlgorithm, cancelAlgorithm, 0, undefined).
   1254  SetUpReadableByteStreamController(aCx, stream, controller, aAlgorithms, 0,
   1255                                    mozilla::Nothing(), aRv);
   1256  if (aRv.Failed()) {
   1257    return nullptr;
   1258  }
   1259 
   1260  // Return stream.
   1261  return stream.forget();
   1262 }
   1263 
   1264 // https://streams.spec.whatwg.org/#readablestream-set-up
   1265 // (except this instead creates a new ReadableStream rather than accepting an
   1266 // existing instance)
   1267 // _BOUNDARY because `aAlgorithms->StartCallback` (called by
   1268 // SetUpReadableStreamDefaultController below) should not be able to run script
   1269 // in this case.
   1270 MOZ_CAN_RUN_SCRIPT_BOUNDARY already_AddRefed<ReadableStream>
   1271 ReadableStream::CreateNative(JSContext* aCx, nsIGlobalObject* aGlobal,
   1272                             UnderlyingSourceAlgorithmsWrapper& aAlgorithms,
   1273                             mozilla::Maybe<double> aHighWaterMark,
   1274                             QueuingStrategySize* aSizeAlgorithm,
   1275                             ErrorResult& aRv) {
   1276  // an optional number highWaterMark (default 1)
   1277  double highWaterMark = aHighWaterMark.valueOr(1);
   1278  // and if given, highWaterMark must be a non-negative, non-NaN number.
   1279  MOZ_ASSERT(IsNonNegativeNumber(highWaterMark));
   1280 
   1281  // Step 1: Let startAlgorithm be an algorithm that returns undefined.
   1282  // Step 2: Let pullAlgorithmWrapper be an algorithm that runs these steps:
   1283  // Step 3: Let cancelAlgorithmWrapper be an algorithm that runs these steps:
   1284  // (Done by UnderlyingSourceAlgorithmsWrapper)
   1285 
   1286  // Step 4: If sizeAlgorithm was not given, then set it to an algorithm that
   1287  // returns 1. (Callers will treat nullptr as such, see
   1288  // ReadableStream::Constructor for details)
   1289 
   1290  // Step 5: Perform ! InitializeReadableStream(stream).
   1291  RefPtr<ReadableStream> stream =
   1292      new ReadableStream(aGlobal, HoldDropJSObjectsCaller::Implicit);
   1293 
   1294  // Step 6: Let controller be a new ReadableStreamDefaultController.
   1295  auto controller = MakeRefPtr<ReadableStreamDefaultController>(aGlobal);
   1296 
   1297  // Step 7: Perform ! SetUpReadableStreamDefaultController(stream, controller,
   1298  // startAlgorithm, pullAlgorithmWrapper, cancelAlgorithmWrapper,
   1299  // highWaterMark, sizeAlgorithm).
   1300  SetUpReadableStreamDefaultController(aCx, stream, controller, &aAlgorithms,
   1301                                       highWaterMark, aSizeAlgorithm, aRv);
   1302  if (aRv.Failed()) {
   1303    return nullptr;
   1304  }
   1305  return stream.forget();
   1306 }
   1307 
   1308 // https://streams.spec.whatwg.org/#readablestream-set-up-with-byte-reading-support
   1309 // _BOUNDARY because `aAlgorithms->StartCallback` (called by
   1310 // SetUpReadableByteStreamController below) should not be able to run script in
   1311 // this case.
   1312 MOZ_CAN_RUN_SCRIPT_BOUNDARY void ReadableStream::SetUpByteNative(
   1313    JSContext* aCx, UnderlyingSourceAlgorithmsWrapper& aAlgorithms,
   1314    mozilla::Maybe<double> aHighWaterMark, ErrorResult& aRv) {
   1315  // an optional number highWaterMark (default 0)
   1316  double highWaterMark = aHighWaterMark.valueOr(0);
   1317  // and if given, highWaterMark must be a non-negative, non-NaN number.
   1318  MOZ_ASSERT(IsNonNegativeNumber(highWaterMark));
   1319 
   1320  // Step 1: Let startAlgorithm be an algorithm that returns undefined.
   1321  // Step 2: Let pullAlgorithmWrapper be an algorithm that runs these steps:
   1322  // Step 3: Let cancelAlgorithmWrapper be an algorithm that runs these steps:
   1323  // (Done by UnderlyingSourceAlgorithmsWrapper)
   1324 
   1325  // Step 4: Perform ! InitializeReadableStream(stream).
   1326  // (Covered by constructor)
   1327 
   1328  // Step 5: Let controller be a new ReadableByteStreamController.
   1329  auto controller = MakeRefPtr<ReadableByteStreamController>(GetParentObject());
   1330 
   1331  // Step 6: Perform ! SetUpReadableByteStreamController(stream, controller,
   1332  // startAlgorithm, pullAlgorithmWrapper, cancelAlgorithmWrapper,
   1333  // highWaterMark, undefined).
   1334  SetUpReadableByteStreamController(aCx, this, controller, &aAlgorithms,
   1335                                    highWaterMark, Nothing(), aRv);
   1336 }
   1337 
   1338 already_AddRefed<ReadableStream> ReadableStream::CreateByteNative(
   1339    JSContext* aCx, nsIGlobalObject* aGlobal,
   1340    UnderlyingSourceAlgorithmsWrapper& aAlgorithms,
   1341    mozilla::Maybe<double> aHighWaterMark, ErrorResult& aRv) {
   1342  RefPtr<ReadableStream> stream =
   1343      new ReadableStream(aGlobal, HoldDropJSObjectsCaller::Implicit);
   1344  stream->SetUpByteNative(aCx, aAlgorithms, aHighWaterMark, aRv);
   1345  if (aRv.Failed()) {
   1346    return nullptr;
   1347  }
   1348  return stream.forget();
   1349 }
   1350 
   1351 // https://streams.spec.whatwg.org/#readablestream-close
   1352 void ReadableStream::CloseNative(JSContext* aCx, ErrorResult& aRv) {
   1353  MOZ_ASSERT_IF(mController->GetAlgorithms(),
   1354                mController->GetAlgorithms()->IsNative());
   1355  // Step 1: If stream.[[controller]] implements ReadableByteStreamController,
   1356  if (mController->IsByte()) {
   1357    RefPtr<ReadableByteStreamController> controller = mController->AsByte();
   1358 
   1359    // Step 1.1: Perform !
   1360    // ReadableByteStreamControllerClose(stream.[[controller]]).
   1361    ReadableByteStreamControllerClose(aCx, controller, aRv);
   1362    if (aRv.Failed()) {
   1363      return;
   1364    }
   1365 
   1366    // Step 1.2: If stream.[[controller]].[[pendingPullIntos]] is not empty,
   1367    // perform ! ReadableByteStreamControllerRespond(stream.[[controller]], 0).
   1368    if (!controller->PendingPullIntos().isEmpty()) {
   1369      ReadableByteStreamControllerRespond(aCx, controller, 0, aRv);
   1370    }
   1371    return;
   1372  }
   1373 
   1374  // Step 2: Otherwise, perform !
   1375  // ReadableStreamDefaultControllerClose(stream.[[controller]]).
   1376  RefPtr<ReadableStreamDefaultController> controller = mController->AsDefault();
   1377  ReadableStreamDefaultControllerClose(aCx, controller, aRv);
   1378 }
   1379 
   1380 // https://streams.spec.whatwg.org/#readablestream-error
   1381 void ReadableStream::ErrorNative(JSContext* aCx, JS::Handle<JS::Value> aError,
   1382                                 ErrorResult& aRv) {
   1383  // Step 1: If stream.[[controller]] implements ReadableByteStreamController,
   1384  // then perform ! ReadableByteStreamControllerError(stream.[[controller]], e).
   1385  if (mController->IsByte()) {
   1386    ReadableByteStreamControllerError(mController->AsByte(), aError, aRv);
   1387    return;
   1388  }
   1389  // Step 2: Otherwise, perform !
   1390  // ReadableStreamDefaultControllerError(stream.[[controller]], e).
   1391  ReadableStreamDefaultControllerError(aCx, mController->AsDefault(), aError,
   1392                                       aRv);
   1393 }
   1394 
   1395 // https://streams.spec.whatwg.org/#readablestream-current-byob-request-view
   1396 static void CurrentBYOBRequestView(JSContext* aCx,
   1397                                   ReadableByteStreamController& aController,
   1398                                   JS::MutableHandle<JSObject*> aRetVal,
   1399                                   ErrorResult& aRv) {
   1400  // Step 1. Assert: stream.[[controller]] implements
   1401  // ReadableByteStreamController. (implicit)
   1402 
   1403  // Step 2: Let byobRequest be !
   1404  // ReadableByteStreamControllerGetBYOBRequest(stream.[[controller]]).
   1405  RefPtr<ReadableStreamBYOBRequest> byobRequest =
   1406      ReadableByteStreamControllerGetBYOBRequest(aCx, &aController, aRv);
   1407  // Step 3: If byobRequest is null, then return null.
   1408  if (!byobRequest) {
   1409    aRetVal.set(nullptr);
   1410    return;
   1411  }
   1412  // Step 4: Return byobRequest.[[view]].
   1413  byobRequest->GetView(aCx, aRetVal);
   1414 }
   1415 
   1416 static bool HasSameBufferView(JSContext* aCx, JS::Handle<JSObject*> aX,
   1417                              JS::Handle<JSObject*> aY, ErrorResult& aRv) {
   1418  bool isShared;
   1419  JS::Rooted<JSObject*> viewedBufferX(
   1420      aCx, JS_GetArrayBufferViewBuffer(aCx, aX, &isShared));
   1421  if (!viewedBufferX) {
   1422    aRv.StealExceptionFromJSContext(aCx);
   1423    return false;
   1424  }
   1425 
   1426  JS::Rooted<JSObject*> viewedBufferY(
   1427      aCx, JS_GetArrayBufferViewBuffer(aCx, aY, &isShared));
   1428  if (!viewedBufferY) {
   1429    aRv.StealExceptionFromJSContext(aCx);
   1430    return false;
   1431  }
   1432 
   1433  return viewedBufferX == viewedBufferY;
   1434 }
   1435 
   1436 // https://streams.spec.whatwg.org/#readablestream-enqueue
   1437 void ReadableStream::EnqueueNative(JSContext* aCx, JS::Handle<JS::Value> aChunk,
   1438                                   ErrorResult& aRv) {
   1439  MOZ_ASSERT(mController->GetAlgorithms()->IsNative());
   1440 
   1441  // Step 1: If stream.[[controller]] implements
   1442  // ReadableStreamDefaultController,
   1443  if (mController->IsDefault()) {
   1444    // Step 1.1: Perform !
   1445    // ReadableStreamDefaultControllerEnqueue(stream.[[controller]], chunk).
   1446    RefPtr<ReadableStreamDefaultController> controller =
   1447        mController->AsDefault();
   1448    ReadableStreamDefaultControllerEnqueue(aCx, controller, aChunk, aRv);
   1449    return;
   1450  }
   1451 
   1452  // Step 2.1: Assert: stream.[[controller]] implements
   1453  // ReadableByteStreamController.
   1454  MOZ_ASSERT(mController->IsByte());
   1455  RefPtr<ReadableByteStreamController> controller = mController->AsByte();
   1456 
   1457  // Step 2.2: Assert: chunk is an ArrayBufferView.
   1458  MOZ_ASSERT(aChunk.isObject() &&
   1459             JS_IsArrayBufferViewObject(&aChunk.toObject()));
   1460  JS::Rooted<JSObject*> chunk(aCx, &aChunk.toObject());
   1461 
   1462  // Step 3: Let byobView be the current BYOB request view for stream.
   1463  JS::Rooted<JSObject*> byobView(aCx);
   1464  CurrentBYOBRequestView(aCx, *controller, &byobView, aRv);
   1465  if (aRv.Failed()) {
   1466    return;
   1467  }
   1468 
   1469  // Step 4: If byobView is non-null, and chunk.[[ViewedArrayBuffer]] is
   1470  // byobView.[[ViewedArrayBuffer]], then:
   1471  if (byobView && HasSameBufferView(aCx, chunk, byobView, aRv)) {
   1472    // Step 4.1: Assert: chunk.[[ByteOffset]] is byobView.[[ByteOffset]].
   1473    MOZ_ASSERT(JS_GetArrayBufferViewByteOffset(chunk) ==
   1474               JS_GetArrayBufferViewByteOffset(byobView));
   1475    // Step 4.2: Assert: chunk.[[ByteLength]] ≤ byobView.[[ByteLength]].
   1476    MOZ_ASSERT(JS_GetArrayBufferViewByteLength(chunk) <=
   1477               JS_GetArrayBufferViewByteLength(byobView));
   1478    // Step 4.3: Perform ?
   1479    // ReadableByteStreamControllerRespond(stream.[[controller]],
   1480    // chunk.[[ByteLength]]).
   1481    ReadableByteStreamControllerRespond(
   1482        aCx, controller, JS_GetArrayBufferViewByteLength(chunk), aRv);
   1483    return;
   1484  }
   1485 
   1486  if (aRv.Failed()) {
   1487    return;
   1488  }
   1489 
   1490  // Step 5: Otherwise, perform ?
   1491  // ReadableByteStreamControllerEnqueue(stream.[[controller]], chunk).
   1492  ReadableByteStreamControllerEnqueue(aCx, controller, chunk, aRv);
   1493 }
   1494 
   1495 // https://streams.spec.whatwg.org/#readablestream-current-byob-request-view
   1496 void ReadableStream::GetCurrentBYOBRequestView(
   1497    JSContext* aCx, JS::MutableHandle<JSObject*> aView, ErrorResult& aRv) {
   1498  aView.set(nullptr);
   1499 
   1500  // Step 1: Assert: stream.[[controller]] implements
   1501  // ReadableByteStreamController.
   1502  MOZ_ASSERT(mController->IsByte());
   1503 
   1504  // Step 2: Let byobRequest be !
   1505  // ReadableByteStreamControllerGetBYOBRequest(stream.[[controller]]).
   1506  RefPtr<ReadableStreamBYOBRequest> byobRequest =
   1507      mController->AsByte()->GetByobRequest(aCx, aRv);
   1508 
   1509  // Step 3: If byobRequest is null, then return null.
   1510  if (!byobRequest || aRv.Failed()) {
   1511    return;
   1512  }
   1513 
   1514  // Step 4: Return byobRequest.[[view]].
   1515  byobRequest->GetView(aCx, aView);
   1516 }
   1517 
   1518 // https://streams.spec.whatwg.org/#readablestream-get-a-reader
   1519 // To get a reader for a ReadableStream stream, return ?
   1520 // AcquireReadableStreamDefaultReader(stream). The result will be a
   1521 // ReadableStreamDefaultReader.
   1522 already_AddRefed<mozilla::dom::ReadableStreamDefaultReader>
   1523 ReadableStream::GetReader(ErrorResult& aRv) {
   1524  return AcquireReadableStreamDefaultReader(this, aRv);
   1525 }
   1526 
   1527 }  // namespace mozilla::dom