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