tor-browser

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

WritableStreamDefaultWriter.cpp (20507B)


      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/WritableStreamDefaultWriter.h"
      8 
      9 #include "js/Array.h"
     10 #include "js/TypeDecls.h"
     11 #include "js/Value.h"
     12 #include "mozilla/AlreadyAddRefed.h"
     13 #include "mozilla/Assertions.h"
     14 #include "mozilla/Attributes.h"
     15 #include "mozilla/CycleCollectedJSContext.h"
     16 #include "mozilla/HoldDropJSObjects.h"
     17 #include "mozilla/dom/Promise-inl.h"
     18 #include "mozilla/dom/WritableStream.h"
     19 #include "mozilla/dom/WritableStreamDefaultWriterBinding.h"
     20 #include "nsCOMPtr.h"
     21 #include "nsIGlobalObject.h"
     22 #include "nsISupports.h"
     23 
     24 namespace mozilla::dom {
     25 
     26 using namespace streams_abstract;
     27 
     28 NS_IMPL_CYCLE_COLLECTION_CLASS(WritableStreamDefaultWriter)
     29 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(WritableStreamDefaultWriter)
     30  NS_IMPL_CYCLE_COLLECTION_UNLINK(mGlobal, mStream, mReadyPromise,
     31                                  mClosedPromise)
     32  NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
     33 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
     34 
     35 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(WritableStreamDefaultWriter)
     36  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGlobal, mStream, mReadyPromise,
     37                                    mClosedPromise)
     38 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
     39 
     40 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(WritableStreamDefaultWriter)
     41  NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
     42 NS_IMPL_CYCLE_COLLECTION_TRACE_END
     43 
     44 NS_IMPL_CYCLE_COLLECTING_ADDREF(WritableStreamDefaultWriter)
     45 NS_IMPL_CYCLE_COLLECTING_RELEASE(WritableStreamDefaultWriter)
     46 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(WritableStreamDefaultWriter)
     47  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
     48  NS_INTERFACE_MAP_ENTRY(nsISupports)
     49 NS_INTERFACE_MAP_END
     50 
     51 WritableStreamDefaultWriter::WritableStreamDefaultWriter(
     52    nsIGlobalObject* aGlobal)
     53    : mGlobal(aGlobal) {
     54  mozilla::HoldJSObjects(this);
     55 }
     56 
     57 WritableStreamDefaultWriter::~WritableStreamDefaultWriter() {
     58  mozilla::DropJSObjects(this);
     59 }
     60 
     61 void WritableStreamDefaultWriter::SetReadyPromise(Promise* aPromise) {
     62  MOZ_ASSERT(aPromise);
     63  mReadyPromise = aPromise;
     64 }
     65 
     66 void WritableStreamDefaultWriter::SetClosedPromise(Promise* aPromise) {
     67  MOZ_ASSERT(aPromise);
     68  mClosedPromise = aPromise;
     69 }
     70 
     71 JSObject* WritableStreamDefaultWriter::WrapObject(
     72    JSContext* aCx, JS::Handle<JSObject*> aGivenProto) {
     73  return WritableStreamDefaultWriter_Binding::Wrap(aCx, this, aGivenProto);
     74 }
     75 
     76 /* static */
     77 already_AddRefed<WritableStreamDefaultWriter>
     78 WritableStreamDefaultWriter::Constructor(const GlobalObject& aGlobal,
     79                                         WritableStream& aStream,
     80                                         ErrorResult& aRv) {
     81  nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
     82  RefPtr<WritableStreamDefaultWriter> writer =
     83      new WritableStreamDefaultWriter(global);
     84  SetUpWritableStreamDefaultWriter(writer, &aStream, aRv);
     85  if (aRv.Failed()) {
     86    return nullptr;
     87  }
     88  return writer.forget();
     89 }
     90 
     91 already_AddRefed<Promise> WritableStreamDefaultWriter::Closed() {
     92  RefPtr<Promise> closedPromise = mClosedPromise;
     93  return closedPromise.forget();
     94 }
     95 
     96 already_AddRefed<Promise> WritableStreamDefaultWriter::Ready() {
     97  RefPtr<Promise> readyPromise = mReadyPromise;
     98  return readyPromise.forget();
     99 }
    100 
    101 namespace streams_abstract {
    102 // https://streams.spec.whatwg.org/#writable-stream-default-writer-get-desired-size
    103 Nullable<double> WritableStreamDefaultWriterGetDesiredSize(
    104    WritableStreamDefaultWriter* aWriter) {
    105  // Step 1. Let stream be writer.[[stream]].
    106  RefPtr<WritableStream> stream = aWriter->GetStream();
    107 
    108  // Step 2. Let state be stream.[[state]].
    109  WritableStream::WriterState state = stream->State();
    110 
    111  // Step 3. If state is "errored" or "erroring", return null.
    112  if (state == WritableStream::WriterState::Errored ||
    113      state == WritableStream::WriterState::Erroring) {
    114    return nullptr;
    115  }
    116 
    117  // Step 4. If state is "closed", return 0.
    118  if (state == WritableStream::WriterState::Closed) {
    119    return 0.0;
    120  }
    121 
    122  // Step 5. Return
    123  // ! WritableStreamDefaultControllerGetDesiredSize(stream.[[controller]]).
    124  return stream->Controller()->GetDesiredSize();
    125 }
    126 }  // namespace streams_abstract
    127 
    128 // https://streams.spec.whatwg.org/#default-writer-desired-size
    129 Nullable<double> WritableStreamDefaultWriter::GetDesiredSize(ErrorResult& aRv) {
    130  // Step 1. If this.[[stream]] is undefined, throw a TypeError exception.
    131  if (!mStream) {
    132    aRv.ThrowTypeError("Missing stream");
    133    return nullptr;
    134  }
    135 
    136  // Step 2. Return ! WritableStreamDefaultWriterGetDesiredSize(this).
    137  RefPtr<WritableStreamDefaultWriter> thisRefPtr = this;
    138  return WritableStreamDefaultWriterGetDesiredSize(thisRefPtr);
    139 }
    140 
    141 // https://streams.spec.whatwg.org/#writable-stream-default-writer-abort
    142 MOZ_CAN_RUN_SCRIPT already_AddRefed<Promise> WritableStreamDefaultWriterAbort(
    143    JSContext* aCx, WritableStreamDefaultWriter* aWriter,
    144    JS::Handle<JS::Value> aReason, ErrorResult& aRv) {
    145  // Step 1. Let stream be writer.[[stream]].
    146  RefPtr<WritableStream> stream = aWriter->GetStream();
    147 
    148  // Step 2. Assert: stream is not undefined.
    149  MOZ_ASSERT(stream);
    150 
    151  // Step 3. Return ! WritableStreamAbort(stream, reason).
    152  return WritableStreamAbort(aCx, stream, aReason, aRv);
    153 }
    154 
    155 // https://streams.spec.whatwg.org/#default-writer-abort
    156 already_AddRefed<Promise> WritableStreamDefaultWriter::Abort(
    157    JSContext* aCx, JS::Handle<JS::Value> aReason, ErrorResult& aRv) {
    158  // Step 1. If this.[[stream]] is undefined, return a promise rejected with a
    159  // TypeError exception.
    160  if (!mStream) {
    161    aRv.ThrowTypeError("Missing stream");
    162    return nullptr;
    163  }
    164 
    165  // Step 2. Return ! WritableStreamDefaultWriterAbort(this, reason).
    166  RefPtr<WritableStreamDefaultWriter> thisRefPtr = this;
    167  return WritableStreamDefaultWriterAbort(aCx, thisRefPtr, aReason, aRv);
    168 }
    169 
    170 // https://streams.spec.whatwg.org/#writable-stream-default-writer-close
    171 MOZ_CAN_RUN_SCRIPT static already_AddRefed<Promise>
    172 WritableStreamDefaultWriterClose(JSContext* aCx,
    173                                 WritableStreamDefaultWriter* aWriter,
    174                                 ErrorResult& aRv) {
    175  // Step 1. Let stream be writer.[[stream]].
    176  RefPtr<WritableStream> stream = aWriter->GetStream();
    177 
    178  // Step 2. Assert: stream is not undefined.
    179  MOZ_ASSERT(stream);
    180 
    181  // Step 3. Return ! WritableStreamClose(stream).
    182  return WritableStreamClose(aCx, stream, aRv);
    183 }
    184 
    185 // https://streams.spec.whatwg.org/#default-writer-close
    186 already_AddRefed<Promise> WritableStreamDefaultWriter::Close(JSContext* aCx,
    187                                                             ErrorResult& aRv) {
    188  // Step 1. Let stream be this.[[stream]].
    189  RefPtr<WritableStream> stream = mStream;
    190 
    191  // Step 2. If stream is undefined, return a promise rejected with a TypeError
    192  // exception.
    193  if (!stream) {
    194    aRv.ThrowTypeError("Missing stream");
    195    return nullptr;
    196  }
    197 
    198  // Step 3. If ! WritableStreamCloseQueuedOrInFlight(stream) is true,
    199  // return a promise rejected with a TypeError exception.
    200  if (stream->CloseQueuedOrInFlight()) {
    201    aRv.ThrowTypeError("Stream is closing");
    202    return nullptr;
    203  }
    204 
    205  // Step 3. Return ! WritableStreamDefaultWriterClose(this).
    206  RefPtr<WritableStreamDefaultWriter> thisRefPtr = this;
    207  return WritableStreamDefaultWriterClose(aCx, thisRefPtr, aRv);
    208 }
    209 
    210 namespace streams_abstract {
    211 // https://streams.spec.whatwg.org/#writable-stream-default-writer-release
    212 void WritableStreamDefaultWriterRelease(JSContext* aCx,
    213                                        WritableStreamDefaultWriter* aWriter) {
    214  // Step 1. Let stream be writer.[[stream]].
    215  RefPtr<WritableStream> stream = aWriter->GetStream();
    216 
    217  // Step 2. Assert: stream is not undefined.
    218  MOZ_ASSERT(stream);
    219 
    220  // Step 3. Assert: stream.[[writer]] is writer.
    221  MOZ_ASSERT(stream->GetWriter() == aWriter);
    222 
    223  // Step 4. Let releasedError be a new TypeError.
    224  JS::Rooted<JS::Value> releasedError(RootingCx(), JS::UndefinedValue());
    225  {
    226    ErrorResult rv;
    227    rv.ThrowTypeError("Releasing lock");
    228    bool ok = ToJSValue(aCx, std::move(rv), &releasedError);
    229    MOZ_RELEASE_ASSERT(ok, "must be ok");
    230  }
    231 
    232  // Step 5. Perform !
    233  // WritableStreamDefaultWriterEnsureReadyPromiseRejected(writer,
    234  // releasedError).
    235  WritableStreamDefaultWriterEnsureReadyPromiseRejected(aWriter, releasedError);
    236 
    237  // Step 6. Perform !
    238  // WritableStreamDefaultWriterEnsureClosedPromiseRejected(writer,
    239  // releasedError).
    240  WritableStreamDefaultWriterEnsureClosedPromiseRejected(aWriter,
    241                                                         releasedError);
    242 
    243  // Step 7. Set stream.[[writer]] to undefined.
    244  stream->SetWriter(nullptr);
    245 
    246  // Step 8. Set writer.[[stream]] to undefined.
    247  aWriter->SetStream(nullptr);
    248 }
    249 }  // namespace streams_abstract
    250 
    251 // https://streams.spec.whatwg.org/#default-writer-release-lock
    252 void WritableStreamDefaultWriter::ReleaseLock(JSContext* aCx) {
    253  // Step 1. Let stream be this.[[stream]].
    254  RefPtr<WritableStream> stream = mStream;
    255 
    256  // Step 2. If stream is undefined, return.
    257  if (!stream) {
    258    return;
    259  }
    260 
    261  // Step 3. Assert: stream.[[writer]] is not undefined.
    262  MOZ_ASSERT(stream->GetWriter());
    263 
    264  // Step 4. Perform ! WritableStreamDefaultWriterRelease(this).
    265  RefPtr<WritableStreamDefaultWriter> thisRefPtr = this;
    266  return WritableStreamDefaultWriterRelease(aCx, thisRefPtr);
    267 }
    268 
    269 namespace streams_abstract {
    270 // https://streams.spec.whatwg.org/#writable-stream-default-writer-write
    271 already_AddRefed<Promise> WritableStreamDefaultWriterWrite(
    272    JSContext* aCx, WritableStreamDefaultWriter* aWriter,
    273    JS::Handle<JS::Value> aChunk, ErrorResult& aRv) {
    274  // Step 1. Let stream be writer.[[stream]].
    275  RefPtr<WritableStream> stream = aWriter->GetStream();
    276 
    277  // Step 2. Assert: stream is not undefined.
    278  MOZ_ASSERT(stream);
    279 
    280  // Step 3. Let controller be stream.[[controller]].
    281  RefPtr<WritableStreamDefaultController> controller = stream->Controller();
    282 
    283  // Step 4. Let chunkSize be !
    284  // WritableStreamDefaultControllerGetChunkSize(controller, chunk).
    285  double chunkSize =
    286      WritableStreamDefaultControllerGetChunkSize(aCx, controller, aChunk, aRv);
    287  if (aRv.Failed()) {
    288    return nullptr;
    289  }
    290 
    291  // Step 5. If stream is not equal to writer.[[stream]], return a promise
    292  // rejected with a TypeError exception.
    293  if (stream != aWriter->GetStream()) {
    294    aRv.ThrowTypeError(
    295        "Can not write on WritableStream owned by another writer.");
    296    return nullptr;
    297  }
    298 
    299  // Step 6. Let state be stream.[[state]].
    300  WritableStream::WriterState state = stream->State();
    301 
    302  // Step 7. If state is "errored", return a promise rejected with
    303  // stream.[[storedError]].
    304  if (state == WritableStream::WriterState::Errored) {
    305    JS::Rooted<JS::Value> error(aCx, stream->StoredError());
    306    return Promise::CreateRejected(aWriter->GetParentObject(), error, aRv);
    307  }
    308 
    309  // Step 8. If ! WritableStreamCloseQueuedOrInFlight(stream) is true or state
    310  // is "closed", return a promise rejected with a TypeError exception
    311  // indicating that the stream is closing or closed.
    312  if (stream->CloseQueuedOrInFlight() ||
    313      state == WritableStream::WriterState::Closed) {
    314    return Promise::CreateRejectedWithTypeError(
    315        aWriter->GetParentObject(), "Stream is closed or closing"_ns, aRv);
    316  }
    317 
    318  // Step 9. If state is "erroring", return a promise rejected with
    319  // stream.[[storedError]].
    320  if (state == WritableStream::WriterState::Erroring) {
    321    JS::Rooted<JS::Value> error(aCx, stream->StoredError());
    322    return Promise::CreateRejected(aWriter->GetParentObject(), error, aRv);
    323  }
    324 
    325  // Step 10. Assert: state is "writable".
    326  MOZ_ASSERT(state == WritableStream::WriterState::Writable);
    327 
    328  // Step 11. Let promise be ! WritableStreamAddWriteRequest(stream).
    329  RefPtr<Promise> promise = WritableStreamAddWriteRequest(stream);
    330 
    331  // Step 12. Perform ! WritableStreamDefaultControllerWrite(controller, chunk,
    332  // chunkSize).
    333  WritableStreamDefaultControllerWrite(aCx, controller, aChunk, chunkSize, aRv);
    334  if (aRv.Failed()) {
    335    return nullptr;
    336  }
    337 
    338  // Step 13. Return promise.
    339  return promise.forget();
    340 }
    341 }  // namespace streams_abstract
    342 
    343 // https://streams.spec.whatwg.org/#default-writer-write
    344 already_AddRefed<Promise> WritableStreamDefaultWriter::Write(
    345    JSContext* aCx, JS::Handle<JS::Value> aChunk, ErrorResult& aRv) {
    346  // Step 1. If this.[[stream]] is undefined, return a promise rejected with a
    347  // TypeError exception.
    348  if (!mStream) {
    349    aRv.ThrowTypeError("Missing stream");
    350    return nullptr;
    351  }
    352 
    353  // Step 2. Return ! WritableStreamDefaultWriterWrite(this, chunk).
    354  return WritableStreamDefaultWriterWrite(aCx, this, aChunk, aRv);
    355 }
    356 
    357 namespace streams_abstract {
    358 
    359 // https://streams.spec.whatwg.org/#set-up-writable-stream-default-writer
    360 void SetUpWritableStreamDefaultWriter(WritableStreamDefaultWriter* aWriter,
    361                                      WritableStream* aStream,
    362                                      ErrorResult& aRv) {
    363  // Step 1. If ! IsWritableStreamLocked(stream) is true, throw a TypeError
    364  // exception.
    365  if (IsWritableStreamLocked(aStream)) {
    366    aRv.ThrowTypeError("WritableStream is already locked!");
    367    return;
    368  }
    369 
    370  // Step 2. Set writer.[[stream]] to stream.
    371  aWriter->SetStream(aStream);
    372 
    373  // Step 3. Set stream.[[writer]] to writer.
    374  aStream->SetWriter(aWriter);
    375 
    376  // Step 4. Let state be stream.[[state]].
    377  WritableStream::WriterState state = aStream->State();
    378 
    379  // Step 5. If state is "writable",
    380  if (state == WritableStream::WriterState::Writable) {
    381    RefPtr<Promise> readyPromise =
    382        Promise::CreateInfallible(aWriter->GetParentObject());
    383 
    384    // Step 5.1 If ! WritableStreamCloseQueuedOrInFlight(stream) is false and
    385    // stream.[[backpressure]] is true, set writer.[[readyPromise]] to a new
    386    // promise.
    387    if (!aStream->CloseQueuedOrInFlight() && aStream->Backpressure()) {
    388      aWriter->SetReadyPromise(readyPromise);
    389    } else {
    390      // Step 5.2. Otherwise, set writer.[[readyPromise]] to a promise resolved
    391      // with undefined.
    392      readyPromise->MaybeResolveWithUndefined();
    393      aWriter->SetReadyPromise(readyPromise);
    394    }
    395 
    396    // Step 5.3. Set writer.[[closedPromise]] to a new promise.
    397    RefPtr<Promise> closedPromise =
    398        Promise::CreateInfallible(aWriter->GetParentObject());
    399    aWriter->SetClosedPromise(closedPromise);
    400  } else if (state == WritableStream::WriterState::Erroring) {
    401    // Step 6. Otherwise, if state is "erroring",
    402 
    403    // Step 6.1. Set writer.[[readyPromise]] to a promise rejected with
    404    // stream.[[storedError]].
    405    JS::Rooted<JS::Value> storedError(RootingCx(), aStream->StoredError());
    406    RefPtr<Promise> readyPromise =
    407        Promise::CreateInfallible(aWriter->GetParentObject());
    408    readyPromise->MaybeReject(storedError);
    409    aWriter->SetReadyPromise(readyPromise);
    410 
    411    // Step 6.2. Set writer.[[readyPromise]].[[PromiseIsHandled]] to true.
    412    readyPromise->SetSettledPromiseIsHandled();
    413 
    414    // Step 6.3. Set writer.[[closedPromise]] to a new promise.
    415    RefPtr<Promise> closedPromise =
    416        Promise::CreateInfallible(aWriter->GetParentObject());
    417    aWriter->SetClosedPromise(closedPromise);
    418  } else if (state == WritableStream::WriterState::Closed) {
    419    // Step 7. Otherwise, if state is "closed",
    420    // Step 7.1. Set writer.[[readyPromise]] to a promise resolved with
    421    // undefined.
    422    RefPtr<Promise> readyPromise =
    423        Promise::CreateResolvedWithUndefined(aWriter->GetParentObject(), aRv);
    424    if (aRv.Failed()) {
    425      return;
    426    }
    427    aWriter->SetReadyPromise(readyPromise);
    428 
    429    // Step 7.2. Set writer.[[closedPromise]] to a promise resolved with
    430    // undefined.
    431    RefPtr<Promise> closedPromise =
    432        Promise::CreateResolvedWithUndefined(aWriter->GetParentObject(), aRv);
    433    if (aRv.Failed()) {
    434      return;
    435    }
    436    aWriter->SetClosedPromise(closedPromise);
    437  } else {
    438    // Step 8. Otherwise,
    439    // Step 8.1 Assert: state is "errored".
    440    MOZ_ASSERT(state == WritableStream::WriterState::Errored);
    441 
    442    // Step 8.2. Step Let storedError be stream.[[storedError]].
    443    JS::Rooted<JS::Value> storedError(RootingCx(), aStream->StoredError());
    444 
    445    // Step 8.3. Set writer.[[readyPromise]] to a promise rejected with
    446    // storedError.
    447    RefPtr<Promise> readyPromise =
    448        Promise::CreateInfallible(aWriter->GetParentObject());
    449    readyPromise->MaybeReject(storedError);
    450    aWriter->SetReadyPromise(readyPromise);
    451 
    452    // Step 8.4. Set writer.[[readyPromise]].[[PromiseIsHandled]] to true.
    453    readyPromise->SetSettledPromiseIsHandled();
    454 
    455    // Step 8.5. Set writer.[[closedPromise]] to a promise rejected with
    456    // storedError.
    457    RefPtr<Promise> closedPromise =
    458        Promise::CreateInfallible(aWriter->GetParentObject());
    459    closedPromise->MaybeReject(storedError);
    460    aWriter->SetClosedPromise(closedPromise);
    461 
    462    // Step 8.6 Set writer.[[closedPromise]].[[PromiseIsHandled]] to true.
    463    closedPromise->SetSettledPromiseIsHandled();
    464  }
    465 }
    466 
    467 // https://streams.spec.whatwg.org/#writable-stream-default-writer-ensure-closed-promise-rejected
    468 void WritableStreamDefaultWriterEnsureClosedPromiseRejected(
    469    WritableStreamDefaultWriter* aWriter, JS::Handle<JS::Value> aError) {
    470  RefPtr<Promise> closedPromise = aWriter->ClosedPromise();
    471  // Step 1. If writer.[[closedPromise]].[[PromiseState]] is "pending", reject
    472  // writer.[[closedPromise]] with error.
    473  if (closedPromise->State() == Promise::PromiseState::Pending) {
    474    closedPromise->MaybeReject(aError);
    475  } else {
    476    // Step 2. Otherwise, set writer.[[closedPromise]] to a promise rejected
    477    // with error.
    478    closedPromise = Promise::CreateInfallible(aWriter->GetParentObject());
    479    closedPromise->MaybeReject(aError);
    480    aWriter->SetClosedPromise(closedPromise);
    481  }
    482 
    483  // Step 3. Set writer.[[closedPromise]].[[PromiseIsHandled]] to true.
    484  closedPromise->SetSettledPromiseIsHandled();
    485 }
    486 
    487 // https://streams.spec.whatwg.org/#writable-stream-default-writer-ensure-ready-promise-rejected
    488 void WritableStreamDefaultWriterEnsureReadyPromiseRejected(
    489    WritableStreamDefaultWriter* aWriter, JS::Handle<JS::Value> aError) {
    490  RefPtr<Promise> readyPromise = aWriter->ReadyPromise();
    491  // Step 1. If writer.[[readyPromise]].[[PromiseState]] is "pending", reject
    492  // writer.[[readyPromise]] with error.
    493  if (readyPromise->State() == Promise::PromiseState::Pending) {
    494    readyPromise->MaybeReject(aError);
    495  } else {
    496    // Step 2. Otherwise, set writer.[[readyPromise]] to a promise rejected with
    497    // error.
    498    readyPromise = Promise::CreateInfallible(aWriter->GetParentObject());
    499    readyPromise->MaybeReject(aError);
    500    aWriter->SetReadyPromise(readyPromise);
    501  }
    502 
    503  // Step 3. Set writer.[[readyPromise]].[[PromiseIsHandled]] to true.
    504  readyPromise->SetSettledPromiseIsHandled();
    505 }
    506 
    507 // https://streams.spec.whatwg.org/#writable-stream-default-writer-close-with-error-propagation
    508 already_AddRefed<Promise> WritableStreamDefaultWriterCloseWithErrorPropagation(
    509    JSContext* aCx, WritableStreamDefaultWriter* aWriter, ErrorResult& aRv) {
    510  // Step 1. Let stream be writer.[[stream]].
    511  RefPtr<WritableStream> stream = aWriter->GetStream();
    512 
    513  // Step 2. Assert: stream is not undefined.
    514  MOZ_ASSERT(stream);
    515 
    516  // Step 3. Let state be stream.[[state]].
    517  WritableStream::WriterState state = stream->State();
    518 
    519  // Step 4. If ! WritableStreamCloseQueuedOrInFlight(stream) is true
    520  // or state is "closed", return a promise resolved with undefined.
    521  if (stream->CloseQueuedOrInFlight() ||
    522      state == WritableStream::WriterState::Closed) {
    523    return Promise::CreateResolvedWithUndefined(aWriter->GetParentObject(),
    524                                                aRv);
    525  }
    526 
    527  // Step 5. If state is "errored",
    528  // return a promise rejected with stream.[[storedError]].
    529  if (state == WritableStream::WriterState::Errored) {
    530    JS::Rooted<JS::Value> error(aCx, stream->StoredError());
    531    return Promise::CreateRejected(aWriter->GetParentObject(), error, aRv);
    532  }
    533 
    534  // Step 6. Assert: state is "writable" or "erroring".
    535  MOZ_ASSERT(state == WritableStream::WriterState::Writable ||
    536             state == WritableStream::WriterState::Erroring);
    537 
    538  // Step 7. Return ! WritableStreamDefaultWriterClose(writer).
    539  return WritableStreamDefaultWriterClose(aCx, aWriter, aRv);
    540 }
    541 
    542 }  // namespace streams_abstract
    543 
    544 }  // namespace mozilla::dom