tor-browser

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

ReadableStreamDefaultReader.cpp (14915B)


      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/ReadableStreamDefaultReader.h"
      8 
      9 #include "js/PropertyAndElement.h"
     10 #include "js/TypeDecls.h"
     11 #include "js/Value.h"
     12 #include "jsapi.h"
     13 #include "mozilla/dom/AutoEntryScript.h"
     14 #include "mozilla/dom/ReadableStream.h"
     15 #include "mozilla/dom/ReadableStreamDefaultReaderBinding.h"
     16 #include "mozilla/dom/RootedDictionary.h"
     17 #include "mozilla/dom/UnderlyingSourceBinding.h"
     18 #include "nsCOMPtr.h"
     19 #include "nsCycleCollectionParticipant.h"
     20 #include "nsISupports.h"
     21 #include "nsWrapperCache.h"
     22 
     23 namespace mozilla::dom {
     24 
     25 using namespace streams_abstract;
     26 
     27 NS_IMPL_CYCLE_COLLECTION(ReadableStreamGenericReader, mClosedPromise, mStream,
     28                         mGlobal)
     29 NS_IMPL_CYCLE_COLLECTING_ADDREF(ReadableStreamGenericReader)
     30 NS_IMPL_CYCLE_COLLECTING_RELEASE(ReadableStreamGenericReader)
     31 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(ReadableStreamGenericReader)
     32 NS_IMPL_CYCLE_COLLECTION_TRACE_END
     33 
     34 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ReadableStreamGenericReader)
     35  NS_INTERFACE_MAP_ENTRY(nsISupports)
     36 NS_INTERFACE_MAP_END
     37 
     38 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_INHERITED(ReadableStreamDefaultReader,
     39                                                ReadableStreamGenericReader,
     40                                                mReadRequests)
     41 NS_IMPL_ADDREF_INHERITED(ReadableStreamDefaultReader,
     42                         ReadableStreamGenericReader)
     43 NS_IMPL_RELEASE_INHERITED(ReadableStreamDefaultReader,
     44                          ReadableStreamGenericReader)
     45 
     46 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ReadableStreamDefaultReader)
     47  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
     48 NS_INTERFACE_MAP_END_INHERITING(ReadableStreamGenericReader)
     49 
     50 ReadableStreamDefaultReader::ReadableStreamDefaultReader(nsISupports* aGlobal)
     51    : ReadableStreamGenericReader(do_QueryInterface(aGlobal)) {}
     52 
     53 ReadableStreamDefaultReader::~ReadableStreamDefaultReader() {
     54  mReadRequests.clear();
     55 }
     56 
     57 JSObject* ReadableStreamDefaultReader::WrapObject(
     58    JSContext* aCx, JS::Handle<JSObject*> aGivenProto) {
     59  return ReadableStreamDefaultReader_Binding::Wrap(aCx, this, aGivenProto);
     60 }
     61 
     62 namespace streams_abstract {
     63 // https://streams.spec.whatwg.org/#readable-stream-reader-generic-initialize
     64 bool ReadableStreamReaderGenericInitialize(ReadableStreamGenericReader* aReader,
     65                                           ReadableStream* aStream) {
     66  // Step 1.
     67  aReader->SetStream(aStream);
     68 
     69  // Step 2.
     70  aStream->SetReader(aReader);
     71 
     72  aReader->SetClosedPromise(
     73      Promise::CreateInfallible(aReader->GetParentObject()));
     74 
     75  switch (aStream->State()) {
     76      // Step 3.
     77    case ReadableStream::ReaderState::Readable:
     78      // Step 3.1
     79      // Promise created above.
     80      return true;
     81    // Step 4.
     82    case ReadableStream::ReaderState::Closed:
     83      // Step 4.1.
     84      aReader->ClosedPromise()->MaybeResolve(JS::UndefinedHandleValue);
     85 
     86      return true;
     87    // Step 5.
     88    case ReadableStream::ReaderState::Errored: {
     89      // Step 5.1 Implicit
     90      // Step 5.2
     91      JS::RootingContext* rcx = RootingCx();
     92      JS::Rooted<JS::Value> rootedError(rcx, aStream->StoredError());
     93      aReader->ClosedPromise()->MaybeReject(rootedError);
     94 
     95      // Step 5.3
     96      aReader->ClosedPromise()->SetSettledPromiseIsHandled();
     97      return true;
     98    }
     99    default:
    100      MOZ_ASSERT_UNREACHABLE("Unknown ReaderState");
    101      return false;
    102  }
    103 }
    104 }  // namespace streams_abstract
    105 
    106 // https://streams.spec.whatwg.org/#default-reader-constructor &&
    107 // https://streams.spec.whatwg.org/#set-up-readable-stream-default-reader
    108 /* static */
    109 already_AddRefed<ReadableStreamDefaultReader>
    110 ReadableStreamDefaultReader::Constructor(const GlobalObject& aGlobal,
    111                                         ReadableStream& aStream,
    112                                         ErrorResult& aRv) {
    113  RefPtr<ReadableStreamDefaultReader> reader =
    114      new ReadableStreamDefaultReader(aGlobal.GetAsSupports());
    115 
    116  // https://streams.spec.whatwg.org/#set-up-readable-stream-default-reader
    117  // Step 1.
    118  if (aStream.Locked()) {
    119    aRv.ThrowTypeError(
    120        "Cannot create a new reader for a readable stream already locked by "
    121        "another reader.");
    122    return nullptr;
    123  }
    124 
    125  // Step 2.
    126  RefPtr<ReadableStream> streamPtr = &aStream;
    127  if (!ReadableStreamReaderGenericInitialize(reader, streamPtr)) {
    128    return nullptr;
    129  }
    130 
    131  // Step 3.
    132  reader->mReadRequests.clear();
    133 
    134  return reader.forget();
    135 }
    136 
    137 void Read_ReadRequest::ChunkSteps(JSContext* aCx, JS::Handle<JS::Value> aChunk,
    138                                  ErrorResult& aRv) {
    139  // https://streams.spec.whatwg.org/#default-reader-read Step 3.
    140  // chunk steps, given chunk:
    141  //  Step 1. Resolve promise with «[ "value" → chunk, "done" → false ]».
    142 
    143  // Value may need to be wrapped if stream and reader are in different
    144  // compartments.
    145  JS::Rooted<JS::Value> chunk(aCx, aChunk);
    146  if (!JS_WrapValue(aCx, &chunk)) {
    147    aRv.StealExceptionFromJSContext(aCx);
    148    return;
    149  }
    150 
    151  RootedDictionary<ReadableStreamReadResult> result(aCx);
    152  result.mValue = chunk;
    153  result.mDone.Construct(false);
    154 
    155  // Ensure that the object is created with the current global.
    156  JS::Rooted<JS::Value> value(aCx);
    157  if (!ToJSValue(aCx, std::move(result), &value)) {
    158    aRv.StealExceptionFromJSContext(aCx);
    159    return;
    160  }
    161 
    162  mPromise->MaybeResolve(value);
    163 }
    164 
    165 void Read_ReadRequest::CloseSteps(JSContext* aCx, ErrorResult& aRv) {
    166  // https://streams.spec.whatwg.org/#default-reader-read Step 3.
    167  // close steps:
    168  //  Step 1. Resolve promise with «[ "value" → undefined, "done" → true ]».
    169  RootedDictionary<ReadableStreamReadResult> result(aCx);
    170  result.mValue.setUndefined();
    171  result.mDone.Construct(true);
    172 
    173  JS::Rooted<JS::Value> value(aCx);
    174  if (!ToJSValue(aCx, std::move(result), &value)) {
    175    aRv.StealExceptionFromJSContext(aCx);
    176    return;
    177  }
    178 
    179  mPromise->MaybeResolve(value);
    180 }
    181 
    182 void Read_ReadRequest::ErrorSteps(JSContext* aCx, JS::Handle<JS::Value> e,
    183                                  ErrorResult& aRv) {
    184  // https://streams.spec.whatwg.org/#default-reader-read Step 3.
    185  // error steps:
    186  //  Step 1. Reject promise with e.
    187  mPromise->MaybeReject(e);
    188 }
    189 
    190 NS_IMPL_CYCLE_COLLECTION(ReadRequest)
    191 NS_IMPL_CYCLE_COLLECTION_INHERITED(Read_ReadRequest, ReadRequest, mPromise)
    192 NS_IMPL_CYCLE_COLLECTING_ADDREF(ReadRequest)
    193 NS_IMPL_CYCLE_COLLECTING_RELEASE(ReadRequest)
    194 
    195 NS_IMPL_ADDREF_INHERITED(Read_ReadRequest, ReadRequest)
    196 NS_IMPL_RELEASE_INHERITED(Read_ReadRequest, ReadRequest)
    197 
    198 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ReadRequest)
    199  NS_INTERFACE_MAP_ENTRY(nsISupports)
    200 NS_INTERFACE_MAP_END
    201 
    202 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Read_ReadRequest)
    203 NS_INTERFACE_MAP_END_INHERITING(ReadRequest)
    204 
    205 namespace streams_abstract {
    206 // https://streams.spec.whatwg.org/#readable-stream-default-reader-read
    207 void ReadableStreamDefaultReaderRead(JSContext* aCx,
    208                                     ReadableStreamGenericReader* aReader,
    209                                     ReadRequest* aRequest, ErrorResult& aRv) {
    210  // Step 1.
    211  ReadableStream* stream = aReader->GetStream();
    212 
    213  // Step 2.
    214  MOZ_ASSERT(stream);
    215 
    216  // Step 3.
    217  stream->SetDisturbed(true);
    218 
    219  switch (stream->State()) {
    220    // Step 4.
    221    case ReadableStream::ReaderState::Closed: {
    222      aRequest->CloseSteps(aCx, aRv);
    223      return;
    224    }
    225 
    226    case ReadableStream::ReaderState::Errored: {
    227      JS::Rooted<JS::Value> storedError(aCx, stream->StoredError());
    228      aRequest->ErrorSteps(aCx, storedError, aRv);
    229      return;
    230    }
    231 
    232    case ReadableStream::ReaderState::Readable: {
    233      RefPtr<ReadableStreamControllerBase> controller(stream->Controller());
    234      MOZ_ASSERT(controller);
    235      controller->PullSteps(aCx, aRequest, aRv);
    236      return;
    237    }
    238  }
    239 }
    240 }  // namespace streams_abstract
    241 
    242 // Return a raw pointer here to avoid refcounting, but make sure it's safe
    243 // (the object should be kept alive by the callee).
    244 // https://streams.spec.whatwg.org/#default-reader-read
    245 already_AddRefed<Promise> ReadableStreamDefaultReader::Read(ErrorResult& aRv) {
    246  // Step 1.
    247  if (!mStream) {
    248    aRv.ThrowTypeError("Reading is not possible after calling releaseLock.");
    249    return nullptr;
    250  }
    251 
    252  // Step 2.
    253  RefPtr<Promise> promise = Promise::CreateInfallible(GetParentObject());
    254 
    255  // Step 3.
    256  RefPtr<ReadRequest> request = new Read_ReadRequest(promise);
    257 
    258  // Step 4.
    259  AutoEntryScript aes(mGlobal, "ReadableStreamDefaultReader::Read");
    260  JSContext* cx = aes.cx();
    261 
    262  ReadableStreamDefaultReaderRead(cx, this, request, aRv);
    263  if (aRv.Failed()) {
    264    return nullptr;
    265  }
    266 
    267  // Step 5.
    268  return promise.forget();
    269 }
    270 
    271 namespace streams_abstract {
    272 
    273 // https://streams.spec.whatwg.org/#readable-stream-reader-generic-release
    274 void ReadableStreamReaderGenericRelease(ReadableStreamGenericReader* aReader,
    275                                        ErrorResult& aRv) {
    276  // Step 1. Let stream be reader.[[stream]].
    277  RefPtr<ReadableStream> stream = aReader->GetStream();
    278 
    279  // Step 2. Assert: stream is not undefined.
    280  MOZ_ASSERT(stream);
    281 
    282  // Step 3. Assert: stream.[[reader]] is reader.
    283  MOZ_ASSERT(stream->GetReader() == aReader);
    284 
    285  // Step 4. If stream.[[state]] is "readable", reject reader.[[closedPromise]]
    286  // with a TypeError exception.
    287  if (stream->State() == ReadableStream::ReaderState::Readable) {
    288    aReader->ClosedPromise()->MaybeRejectWithTypeError(
    289        "Releasing lock on readable stream");
    290  } else {
    291    // Step 5. Otherwise, set reader.[[closedPromise]] to a promise rejected
    292    // with a TypeError exception.
    293    RefPtr<Promise> promise = Promise::CreateRejectedWithTypeError(
    294        aReader->GetParentObject(), "Lock Released"_ns, aRv);
    295    aReader->SetClosedPromise(promise.forget());
    296  }
    297 
    298  // Step 6. Set reader.[[closedPromise]].[[PromiseIsHandled]] to true.
    299  aReader->ClosedPromise()->SetSettledPromiseIsHandled();
    300 
    301  // Step 7. Perform ! stream.[[controller]].[[ReleaseSteps]]().
    302  stream->Controller()->ReleaseSteps();
    303 
    304  // Step 8. Set stream.[[reader]] to undefined.
    305  stream->SetReader(nullptr);
    306 
    307  // Step 9. Set reader.[[stream]] to undefined.
    308  aReader->SetStream(nullptr);
    309 }
    310 
    311 // https://streams.spec.whatwg.org/#abstract-opdef-readablestreamdefaultreadererrorreadrequests
    312 void ReadableStreamDefaultReaderErrorReadRequests(
    313    JSContext* aCx, ReadableStreamDefaultReader* aReader,
    314    JS::Handle<JS::Value> aError, ErrorResult& aRv) {
    315  // Step 1. Let readRequests be reader.[[readRequests]].
    316  LinkedList<RefPtr<ReadRequest>> readRequests =
    317      std::move(aReader->ReadRequests());
    318 
    319  // Step 2. Set reader.[[readRequests]] to a new empty list.
    320  // Note: The std::move already cleared this anyway.
    321  aReader->ReadRequests().clear();
    322 
    323  // Step 3. For each readRequest of readRequests,
    324  while (RefPtr<ReadRequest> readRequest = readRequests.popFirst()) {
    325    // Step 3.1. Perform readRequest’s error steps, given e.
    326    readRequest->ErrorSteps(aCx, aError, aRv);
    327    if (aRv.Failed()) {
    328      return;
    329    }
    330  }
    331 }
    332 
    333 // https://streams.spec.whatwg.org/#abstract-opdef-readablestreamdefaultreaderrelease
    334 void ReadableStreamDefaultReaderRelease(JSContext* aCx,
    335                                        ReadableStreamDefaultReader* aReader,
    336                                        ErrorResult& aRv) {
    337  // Step 1. Perform ! ReadableStreamReaderGenericRelease(reader).
    338  ReadableStreamReaderGenericRelease(aReader, aRv);
    339  if (aRv.Failed()) {
    340    return;
    341  }
    342 
    343  // Step 2. Let e be a new TypeError exception.
    344  ErrorResult rv;
    345  rv.ThrowTypeError("Releasing lock");
    346  JS::Rooted<JS::Value> error(aCx);
    347  MOZ_ALWAYS_TRUE(ToJSValue(aCx, std::move(rv), &error));
    348 
    349  // Step 3. Perform ! ReadableStreamDefaultReaderErrorReadRequests(reader, e).
    350  ReadableStreamDefaultReaderErrorReadRequests(aCx, aReader, error, aRv);
    351 }
    352 
    353 }  // namespace streams_abstract
    354 
    355 // https://streams.spec.whatwg.org/#default-reader-release-lock
    356 void ReadableStreamDefaultReader::ReleaseLock(ErrorResult& aRv) {
    357  // Step 1. If this.[[stream]] is undefined, return.
    358  if (!mStream) {
    359    return;
    360  }
    361 
    362  AutoJSAPI jsapi;
    363  if (!jsapi.Init(mGlobal)) {
    364    return aRv.ThrowUnknownError("Internal error");
    365  }
    366  JSContext* cx = jsapi.cx();
    367 
    368  // Step 2. Perform ! ReadableStreamDefaultReaderRelease(this).
    369  RefPtr<ReadableStreamDefaultReader> thisRefPtr = this;
    370  ReadableStreamDefaultReaderRelease(cx, thisRefPtr, aRv);
    371 }
    372 
    373 // https://streams.spec.whatwg.org/#generic-reader-closed
    374 already_AddRefed<Promise> ReadableStreamGenericReader::Closed() const {
    375  // Step 1.
    376  return do_AddRef(mClosedPromise);
    377 }
    378 
    379 // https://streams.spec.whatwg.org/#readable-stream-reader-generic-cancel
    380 MOZ_CAN_RUN_SCRIPT
    381 static already_AddRefed<Promise> ReadableStreamGenericReaderCancel(
    382    JSContext* aCx, ReadableStreamGenericReader* aReader,
    383    JS::Handle<JS::Value> aReason, ErrorResult& aRv) {
    384  // Step 1 (Strong ref for below call).
    385  RefPtr<ReadableStream> stream = aReader->GetStream();
    386 
    387  // Step 2.
    388  MOZ_ASSERT(stream);
    389 
    390  // Step 3.
    391  return ReadableStreamCancel(aCx, stream, aReason, aRv);
    392 }
    393 
    394 already_AddRefed<Promise> ReadableStreamGenericReader::Cancel(
    395    JSContext* aCx, JS::Handle<JS::Value> aReason, ErrorResult& aRv) {
    396  // Step 1. If this.[[stream]] is undefined,
    397  // return a promise rejected with a TypeError exception.
    398  if (!mStream) {
    399    aRv.ThrowTypeError("Canceling is not possible after calling releaseLock.");
    400    return nullptr;
    401  }
    402 
    403  // Step 2. Return ! ReadableStreamReaderGenericCancel(this, reason).
    404  return ReadableStreamGenericReaderCancel(aCx, this, aReason, aRv);
    405 }
    406 
    407 namespace streams_abstract {
    408 // https://streams.spec.whatwg.org/#set-up-readable-stream-default-reader
    409 void SetUpReadableStreamDefaultReader(ReadableStreamDefaultReader* aReader,
    410                                      ReadableStream* aStream,
    411                                      ErrorResult& aRv) {
    412  // Step 1.
    413  if (IsReadableStreamLocked(aStream)) {
    414    return aRv.ThrowTypeError(
    415        "Cannot get a new reader for a readable stream already locked by "
    416        "another reader.");
    417  }
    418 
    419  // Step 2.
    420  if (!ReadableStreamReaderGenericInitialize(aReader, aStream)) {
    421    return;
    422  }
    423 
    424  // Step 3.
    425  aReader->ReadRequests().clear();
    426 }
    427 }  // namespace streams_abstract
    428 
    429 // https://streams.spec.whatwg.org/#readablestreamdefaultreader-read-a-chunk
    430 // To read a chunk from a ReadableStreamDefaultReader reader, given a read
    431 // request readRequest, perform ! ReadableStreamDefaultReaderRead(reader,
    432 // readRequest).
    433 void ReadableStreamDefaultReader::ReadChunk(JSContext* aCx,
    434                                            ReadRequest& aRequest,
    435                                            ErrorResult& aRv) {
    436  ReadableStreamDefaultReaderRead(aCx, this, &aRequest, aRv);
    437 }
    438 
    439 }  // namespace mozilla::dom