ReadableStreamDefaultController.cpp (21246B)
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/ReadableStreamDefaultController.h" 8 9 #include "js/Exception.h" 10 #include "js/TypeDecls.h" 11 #include "js/Value.h" 12 #include "mozilla/AlreadyAddRefed.h" 13 #include "mozilla/Attributes.h" 14 #include "mozilla/HoldDropJSObjects.h" 15 #include "mozilla/dom/Promise-inl.h" 16 #include "mozilla/dom/Promise.h" 17 #include "mozilla/dom/ReadableStream.h" 18 #include "mozilla/dom/ReadableStreamControllerBase.h" 19 #include "mozilla/dom/ReadableStreamDefaultControllerBinding.h" 20 #include "mozilla/dom/ReadableStreamDefaultReaderBinding.h" 21 #include "mozilla/dom/UnderlyingSourceBinding.h" 22 #include "mozilla/dom/UnderlyingSourceCallbackHelpers.h" 23 #include "nsCycleCollectionParticipant.h" 24 #include "nsISupports.h" 25 26 namespace mozilla::dom { 27 28 using namespace streams_abstract; 29 30 NS_IMPL_CYCLE_COLLECTION(ReadableStreamControllerBase, mGlobal, mAlgorithms, 31 mStream) 32 NS_IMPL_CYCLE_COLLECTING_ADDREF(ReadableStreamControllerBase) 33 NS_IMPL_CYCLE_COLLECTING_RELEASE(ReadableStreamControllerBase) 34 35 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ReadableStreamControllerBase) 36 NS_INTERFACE_MAP_ENTRY(nsISupports) 37 NS_INTERFACE_MAP_END 38 39 ReadableStreamControllerBase::ReadableStreamControllerBase( 40 nsIGlobalObject* aGlobal) 41 : mGlobal(aGlobal) {} 42 43 void ReadableStreamControllerBase::SetStream(ReadableStream* aStream) { 44 mStream = aStream; 45 } 46 47 // Note: Using the individual macros vs NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE 48 // because I need to specify a manual implementation of 49 // NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN. 50 NS_IMPL_CYCLE_COLLECTION_CLASS(ReadableStreamDefaultController) 51 52 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(ReadableStreamDefaultController, 53 ReadableStreamControllerBase) 54 NS_IMPL_CYCLE_COLLECTION_UNLINK(mStrategySizeAlgorithm) 55 tmp->mQueue.clear(); 56 NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER 57 NS_IMPL_CYCLE_COLLECTION_UNLINK_END 58 59 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED( 60 ReadableStreamDefaultController, ReadableStreamControllerBase) 61 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStrategySizeAlgorithm) 62 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END 63 64 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(ReadableStreamDefaultController, 65 ReadableStreamControllerBase) 66 NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER 67 // Trace the associated queue. 68 for (const auto& queueEntry : tmp->mQueue) { 69 aCallbacks.Trace(&queueEntry->mValue, "mQueue.mValue", aClosure); 70 } 71 NS_IMPL_CYCLE_COLLECTION_TRACE_END 72 73 NS_IMPL_ADDREF_INHERITED(ReadableStreamDefaultController, 74 ReadableStreamControllerBase) 75 NS_IMPL_RELEASE_INHERITED(ReadableStreamDefaultController, 76 ReadableStreamControllerBase) 77 78 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ReadableStreamDefaultController) 79 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY 80 NS_INTERFACE_MAP_END_INHERITING(ReadableStreamControllerBase) 81 82 ReadableStreamDefaultController::ReadableStreamDefaultController( 83 nsIGlobalObject* aGlobal) 84 : ReadableStreamControllerBase(aGlobal) { 85 mozilla::HoldJSObjects(this); 86 } 87 88 ReadableStreamDefaultController::~ReadableStreamDefaultController() { 89 // MG:XXX: LinkedLists are required to be empty at destruction, but it seems 90 // it is possible to have a controller be destructed while still 91 // having entries in its queue. 92 // 93 // This needs to be verified as not indicating some other issue. 94 mozilla::DropJSObjects(this); 95 mQueue.clear(); 96 } 97 98 JSObject* ReadableStreamDefaultController::WrapObject( 99 JSContext* aCx, JS::Handle<JSObject*> aGivenProto) { 100 return ReadableStreamDefaultController_Binding::Wrap(aCx, this, aGivenProto); 101 } 102 103 namespace streams_abstract { 104 105 // https://streams.spec.whatwg.org/#readable-stream-default-controller-can-close-or-enqueue 106 static bool ReadableStreamDefaultControllerCanCloseOrEnqueue( 107 ReadableStreamDefaultController* aController) { 108 // Step 1. Let state be controller.[[stream]].[[state]]. 109 ReadableStream::ReaderState state = aController->Stream()->State(); 110 111 // Step 2. If controller.[[closeRequested]] is false and state is "readable", 112 // return true. 113 // Step 3. Return false. 114 return !aController->CloseRequested() && 115 state == ReadableStream::ReaderState::Readable; 116 } 117 118 // https://streams.spec.whatwg.org/#readable-stream-default-controller-can-close-or-enqueue 119 // This is a variant of ReadableStreamDefaultControllerCanCloseOrEnqueue 120 // that also throws when the function would return false to improve error 121 // messages. 122 bool ReadableStreamDefaultControllerCanCloseOrEnqueueAndThrow( 123 ReadableStreamDefaultController* aController, 124 CloseOrEnqueue aCloseOrEnqueue, ErrorResult& aRv) { 125 // Step 1. Let state be controller.[[stream]].[[state]]. 126 ReadableStream::ReaderState state = aController->Stream()->State(); 127 128 nsCString prefix; 129 if (aCloseOrEnqueue == CloseOrEnqueue::Close) { 130 prefix = "Cannot close a stream that "_ns; 131 } else { 132 prefix = "Cannot enqueue into a stream that "_ns; 133 } 134 135 switch (state) { 136 case ReadableStream::ReaderState::Readable: 137 // Step 2. If controller.[[closeRequested]] is false and 138 // state is "readable", return true. 139 // Note: We don't error/check for [[closeRequest]] first, because 140 // [[closedRequest]] is still true even after the state is "closed". 141 // This doesn't cause any spec observable difference. 142 if (!aController->CloseRequested()) { 143 return true; 144 } 145 146 // Step 3. Return false. 147 aRv.ThrowTypeError(prefix + "has already been requested to close."_ns); 148 return false; 149 150 case ReadableStream::ReaderState::Closed: 151 aRv.ThrowTypeError(prefix + "is already closed."_ns); 152 return false; 153 154 case ReadableStream::ReaderState::Errored: 155 aRv.ThrowTypeError(prefix + "has errored."_ns); 156 return false; 157 158 default: 159 MOZ_ASSERT_UNREACHABLE("Unknown ReaderState"); 160 return false; 161 } 162 } 163 164 Nullable<double> ReadableStreamDefaultControllerGetDesiredSize( 165 ReadableStreamDefaultController* aController) { 166 ReadableStream::ReaderState state = aController->Stream()->State(); 167 if (state == ReadableStream::ReaderState::Errored) { 168 return nullptr; 169 } 170 171 if (state == ReadableStream::ReaderState::Closed) { 172 return 0.0; 173 } 174 175 return aController->StrategyHWM() - aController->QueueTotalSize(); 176 } 177 178 } // namespace streams_abstract 179 180 // https://streams.spec.whatwg.org/#rs-default-controller-desired-size 181 Nullable<double> ReadableStreamDefaultController::GetDesiredSize() { 182 // Step 1. 183 return ReadableStreamDefaultControllerGetDesiredSize(this); 184 } 185 186 namespace streams_abstract { 187 188 // https://streams.spec.whatwg.org/#readable-stream-default-controller-clear-algorithms 189 // 190 // Note: nullptr is used to indicate we run the default algorithm at the 191 // moment, 192 // so the below doesn't quite match the spec, but serves the correct 193 // purpose for disconnecting the algorithms from the object graph to allow 194 // collection. 195 // 196 // As far as I know, this isn't currently visible, but we need to keep 197 // this in mind. This is a weakness of this current implementation, and 198 // I'd prefer to have a better answer here eventually. 199 void ReadableStreamDefaultControllerClearAlgorithms( 200 ReadableStreamDefaultController* aController) { 201 // Step 1. 202 // Step 2. 203 aController->ClearAlgorithms(); 204 205 // Step 3. 206 aController->setStrategySizeAlgorithm(nullptr); 207 } 208 209 // https://streams.spec.whatwg.org/#readable-stream-default-controller-close 210 void ReadableStreamDefaultControllerClose( 211 JSContext* aCx, ReadableStreamDefaultController* aController, 212 ErrorResult& aRv) { 213 // Step 1. 214 if (!ReadableStreamDefaultControllerCanCloseOrEnqueue(aController)) { 215 return; 216 } 217 218 // Step 2. 219 RefPtr<ReadableStream> stream = aController->Stream(); 220 221 // Step 3. 222 aController->SetCloseRequested(true); 223 224 // Step 4. 225 if (aController->Queue().isEmpty()) { 226 // Step 4.1 227 ReadableStreamDefaultControllerClearAlgorithms(aController); 228 229 // Step 4.2 230 ReadableStreamClose(aCx, stream, aRv); 231 } 232 } 233 234 } // namespace streams_abstract 235 236 // https://streams.spec.whatwg.org/#rs-default-controller-close 237 void ReadableStreamDefaultController::Close(JSContext* aCx, ErrorResult& aRv) { 238 // Step 1. 239 if (!ReadableStreamDefaultControllerCanCloseOrEnqueueAndThrow( 240 this, CloseOrEnqueue::Close, aRv)) { 241 return; 242 } 243 244 // Step 2. 245 ReadableStreamDefaultControllerClose(aCx, this, aRv); 246 } 247 248 namespace streams_abstract { 249 250 MOZ_CAN_RUN_SCRIPT static void ReadableStreamDefaultControllerCallPullIfNeeded( 251 JSContext* aCx, ReadableStreamDefaultController* aController, 252 ErrorResult& aRv); 253 254 // https://streams.spec.whatwg.org/#readable-stream-default-controller-enqueue 255 void ReadableStreamDefaultControllerEnqueue( 256 JSContext* aCx, ReadableStreamDefaultController* aController, 257 JS::Handle<JS::Value> aChunk, ErrorResult& aRv) { 258 // Step 1. 259 if (!ReadableStreamDefaultControllerCanCloseOrEnqueue(aController)) { 260 return; 261 } 262 263 // Step 2. 264 RefPtr<ReadableStream> stream = aController->Stream(); 265 266 // Step 3. 267 if (IsReadableStreamLocked(stream) && 268 ReadableStreamGetNumReadRequests(stream) > 0) { 269 ReadableStreamFulfillReadRequest(aCx, stream, aChunk, false, aRv); 270 } else { 271 // Step 4.1 272 Optional<JS::Handle<JS::Value>> optionalChunk(aCx, aChunk); 273 274 // Step 4.3 (Re-ordered); 275 RefPtr<QueuingStrategySize> sizeAlgorithm( 276 aController->StrategySizeAlgorithm()); 277 278 // If !sizeAlgorithm, we return 1, which is inlined from 279 // https://streams.spec.whatwg.org/#make-size-algorithm-from-size-function 280 double chunkSize = 281 sizeAlgorithm 282 ? sizeAlgorithm->Call( 283 optionalChunk, aRv, 284 "ReadableStreamDefaultController.[[strategySizeAlgorithm]]", 285 CallbackObject::eRethrowExceptions) 286 : 1.0; 287 288 // If this is an uncatchable exception we can't continue. 289 if (aRv.IsUncatchableException()) { 290 return; 291 } 292 293 // Step 4.2: 294 if (aRv.MaybeSetPendingException( 295 aCx, "ReadableStreamDefaultController.enqueue")) { 296 JS::Rooted<JS::Value> errorValue(aCx); 297 298 JS_GetPendingException(aCx, &errorValue); 299 300 // Step 4.2.1 301 302 ReadableStreamDefaultControllerError(aCx, aController, errorValue, aRv); 303 if (aRv.Failed()) { 304 return; 305 } 306 307 // Step 4.2.2 Caller must treat aRv as if it were a completion 308 // value 309 aRv.MightThrowJSException(); 310 aRv.ThrowJSException(aCx, errorValue); 311 return; 312 } 313 314 // Step 4.4 315 EnqueueValueWithSize(aController, aChunk, chunkSize, aRv); 316 317 // Step 4.5 318 // Note we convert the pending exception to a JS value here, and then 319 // re-throw it because we save this exception and re-expose it elsewhere 320 // and there are tests to ensure the identity of these errors are the same. 321 if (aRv.MaybeSetPendingException( 322 aCx, "ReadableStreamDefaultController.enqueue")) { 323 JS::Rooted<JS::Value> errorValue(aCx); 324 325 if (!JS_GetPendingException(aCx, &errorValue)) { 326 // Uncatchable exception; we should mark aRv and return. 327 aRv.StealExceptionFromJSContext(aCx); 328 return; 329 } 330 JS_ClearPendingException(aCx); 331 332 // Step 4.5.1 333 ReadableStreamDefaultControllerError(aCx, aController, errorValue, aRv); 334 if (aRv.Failed()) { 335 return; 336 } 337 338 // Step 4.5.2 Caller must treat aRv as if it were a completion 339 // value 340 aRv.MightThrowJSException(); 341 aRv.ThrowJSException(aCx, errorValue); 342 return; 343 } 344 } 345 346 // Step 5. 347 ReadableStreamDefaultControllerCallPullIfNeeded(aCx, aController, aRv); 348 } 349 350 } // namespace streams_abstract 351 352 // https://streams.spec.whatwg.org/#rs-default-controller-close 353 void ReadableStreamDefaultController::Enqueue(JSContext* aCx, 354 JS::Handle<JS::Value> aChunk, 355 ErrorResult& aRv) { 356 // Step 1. 357 if (!ReadableStreamDefaultControllerCanCloseOrEnqueueAndThrow( 358 this, CloseOrEnqueue::Enqueue, aRv)) { 359 return; 360 } 361 362 // Step 2. 363 ReadableStreamDefaultControllerEnqueue(aCx, this, aChunk, aRv); 364 } 365 366 void ReadableStreamDefaultController::Error(JSContext* aCx, 367 JS::Handle<JS::Value> aError, 368 ErrorResult& aRv) { 369 ReadableStreamDefaultControllerError(aCx, this, aError, aRv); 370 } 371 372 namespace streams_abstract { 373 374 // https://streams.spec.whatwg.org/#readable-stream-default-controller-should-call-pull 375 bool ReadableStreamDefaultControllerShouldCallPull( 376 ReadableStreamDefaultController* aController) { 377 // Step 1. 378 ReadableStream* stream = aController->Stream(); 379 380 // Step 2. 381 if (!ReadableStreamDefaultControllerCanCloseOrEnqueue(aController)) { 382 return false; 383 } 384 385 // Step 3. 386 if (!aController->Started()) { 387 return false; 388 } 389 390 // Step 4. 391 if (IsReadableStreamLocked(stream) && 392 ReadableStreamGetNumReadRequests(stream) > 0) { 393 return true; 394 } 395 396 // Step 5. 397 Nullable<double> desiredSize = 398 ReadableStreamDefaultControllerGetDesiredSize(aController); 399 400 // Step 6. 401 MOZ_ASSERT(!desiredSize.IsNull()); 402 403 // Step 7 + 8 404 return desiredSize.Value() > 0; 405 } 406 407 // https://streams.spec.whatwg.org/#readable-stream-default-controller-error 408 void ReadableStreamDefaultControllerError( 409 JSContext* aCx, ReadableStreamDefaultController* aController, 410 JS::Handle<JS::Value> aValue, ErrorResult& aRv) { 411 // Step 1. 412 ReadableStream* stream = aController->Stream(); 413 414 // Step 2. 415 if (stream->State() != ReadableStream::ReaderState::Readable) { 416 return; 417 } 418 419 // Step 3. 420 ResetQueue(aController); 421 422 // Step 4. 423 ReadableStreamDefaultControllerClearAlgorithms(aController); 424 425 // Step 5. 426 ReadableStreamError(aCx, stream, aValue, aRv); 427 } 428 429 // https://streams.spec.whatwg.org/#readable-stream-default-controller-call-pull-if-needed 430 static void ReadableStreamDefaultControllerCallPullIfNeeded( 431 JSContext* aCx, ReadableStreamDefaultController* aController, 432 ErrorResult& aRv) { 433 // Step 1. 434 bool shouldPull = ReadableStreamDefaultControllerShouldCallPull(aController); 435 436 // Step 2. 437 if (!shouldPull) { 438 return; 439 } 440 441 // Step 3. 442 if (aController->Pulling()) { 443 // Step 3.1 444 aController->SetPullAgain(true); 445 // Step 3.2 446 return; 447 } 448 449 // Step 4. 450 MOZ_ASSERT(!aController->PullAgain()); 451 452 // Step 5. 453 aController->SetPulling(true); 454 455 // Step 6. 456 RefPtr<UnderlyingSourceAlgorithmsBase> algorithms = 457 aController->GetAlgorithms(); 458 RefPtr<Promise> pullPromise = 459 algorithms->PullCallback(aCx, *aController, aRv); 460 if (aRv.Failed()) { 461 return; 462 } 463 464 // Step 7 + 8: 465 pullPromise->AddCallbacksWithCycleCollectedArgs( 466 [](JSContext* aCx, JS::Handle<JS::Value> aValue, ErrorResult& aRv, 467 ReadableStreamDefaultController* mController) 468 MOZ_CAN_RUN_SCRIPT_BOUNDARY { 469 // Step 7.1 470 mController->SetPulling(false); 471 // Step 7.2 472 if (mController->PullAgain()) { 473 // Step 7.2.1 474 mController->SetPullAgain(false); 475 476 // Step 7.2.2 477 ErrorResult rv; 478 ReadableStreamDefaultControllerCallPullIfNeeded( 479 aCx, MOZ_KnownLive(mController), aRv); 480 } 481 }, 482 [](JSContext* aCx, JS::Handle<JS::Value> aValue, ErrorResult& aRv, 483 ReadableStreamDefaultController* mController) { 484 // Step 8.1 485 ReadableStreamDefaultControllerError(aCx, mController, aValue, aRv); 486 }, 487 RefPtr(aController)); 488 } 489 490 // https://streams.spec.whatwg.org/#set-up-readable-stream-default-controller 491 void SetUpReadableStreamDefaultController( 492 JSContext* aCx, ReadableStream* aStream, 493 ReadableStreamDefaultController* aController, 494 UnderlyingSourceAlgorithmsBase* aAlgorithms, double aHighWaterMark, 495 QueuingStrategySize* aSizeAlgorithm, ErrorResult& aRv) { 496 // Step 1. 497 MOZ_ASSERT(!aStream->Controller()); 498 499 // Step 2. 500 aController->SetStream(aStream); 501 502 // Step 3. 503 ResetQueue(aController); 504 505 // Step 4. 506 aController->SetStarted(false); 507 aController->SetCloseRequested(false); 508 aController->SetPullAgain(false); 509 aController->SetPulling(false); 510 511 // Step 5. 512 aController->setStrategySizeAlgorithm(aSizeAlgorithm); 513 aController->SetStrategyHWM(aHighWaterMark); 514 515 // Step 6. 516 // Step 7. 517 aController->SetAlgorithms(*aAlgorithms); 518 519 // Step 8. 520 aStream->SetController(*aController); 521 522 // Step 9. Default algorithm returns undefined. See Step 2 of 523 // https://streams.spec.whatwg.org/#set-up-readable-stream-default-controller 524 JS::Rooted<JS::Value> startResult(aCx, JS::UndefinedValue()); 525 RefPtr<ReadableStreamDefaultController> controller = aController; 526 aAlgorithms->StartCallback(aCx, *controller, &startResult, aRv); 527 if (aRv.Failed()) { 528 return; 529 } 530 531 // Step 10. 532 RefPtr<Promise> startPromise = 533 Promise::CreateInfallible(aStream->GetParentObject()); 534 startPromise->MaybeResolve(startResult); 535 536 // Step 11 & 12: 537 startPromise->AddCallbacksWithCycleCollectedArgs( 538 [](JSContext* aCx, JS::Handle<JS::Value> aValue, ErrorResult& aRv, 539 ReadableStreamDefaultController* aController) 540 MOZ_CAN_RUN_SCRIPT_BOUNDARY { 541 MOZ_ASSERT(aController); 542 543 // Step 11.1 544 aController->SetStarted(true); 545 546 // Step 11.2 547 aController->SetPulling(false); 548 549 // Step 11.3 550 aController->SetPullAgain(false); 551 552 // Step 11.4: 553 ReadableStreamDefaultControllerCallPullIfNeeded( 554 aCx, MOZ_KnownLive(aController), aRv); 555 }, 556 557 [](JSContext* aCx, JS::Handle<JS::Value> aValue, ErrorResult& aRv, 558 ReadableStreamDefaultController* aController) { 559 // Step 12.1 560 ReadableStreamDefaultControllerError(aCx, aController, aValue, aRv); 561 }, 562 RefPtr(aController)); 563 } 564 565 // https://streams.spec.whatwg.org/#set-up-readable-stream-default-controller-from-underlying-source 566 void SetupReadableStreamDefaultControllerFromUnderlyingSource( 567 JSContext* aCx, ReadableStream* aStream, 568 JS::Handle<JSObject*> aUnderlyingSource, 569 UnderlyingSource& aUnderlyingSourceDict, double aHighWaterMark, 570 QueuingStrategySize* aSizeAlgorithm, ErrorResult& aRv) { 571 // Step 1. 572 RefPtr<ReadableStreamDefaultController> controller = 573 new ReadableStreamDefaultController(aStream->GetParentObject()); 574 575 // Step 2 - 7 576 RefPtr<UnderlyingSourceAlgorithms> algorithms = 577 new UnderlyingSourceAlgorithms(aStream->GetParentObject(), 578 aUnderlyingSource, aUnderlyingSourceDict); 579 580 // Step 8: 581 SetUpReadableStreamDefaultController(aCx, aStream, controller, algorithms, 582 aHighWaterMark, aSizeAlgorithm, aRv); 583 } 584 585 } // namespace streams_abstract 586 587 // https://streams.spec.whatwg.org/#rs-default-controller-private-cancel 588 already_AddRefed<Promise> ReadableStreamDefaultController::CancelSteps( 589 JSContext* aCx, JS::Handle<JS::Value> aReason, ErrorResult& aRv) { 590 // Step 1. 591 ResetQueue(this); 592 593 // Step 2. 594 Optional<JS::Handle<JS::Value>> errorOption(aCx, aReason); 595 RefPtr<UnderlyingSourceAlgorithmsBase> algorithms = mAlgorithms; 596 RefPtr<Promise> result = algorithms->CancelCallback(aCx, errorOption, aRv); 597 if (aRv.Failed()) { 598 return nullptr; 599 } 600 601 // Step 3. 602 ReadableStreamDefaultControllerClearAlgorithms(this); 603 604 // Step 4. 605 return result.forget(); 606 } 607 608 // https://streams.spec.whatwg.org/#rs-default-controller-private-pull 609 void ReadableStreamDefaultController::PullSteps(JSContext* aCx, 610 ReadRequest* aReadRequest, 611 ErrorResult& aRv) { 612 // Step 1. 613 RefPtr<ReadableStream> stream = mStream; 614 615 // Step 2. 616 if (!mQueue.isEmpty()) { 617 // Step 2.1 618 JS::Rooted<JS::Value> chunk(aCx); 619 DequeueValue(this, &chunk); 620 621 // Step 2.2 622 if (CloseRequested() && mQueue.isEmpty()) { 623 // Step 2.2.1 624 ReadableStreamDefaultControllerClearAlgorithms(this); 625 // Step 2.2.2 626 ReadableStreamClose(aCx, stream, aRv); 627 if (aRv.Failed()) { 628 return; 629 } 630 } else { 631 // Step 2.3 632 ReadableStreamDefaultControllerCallPullIfNeeded(aCx, this, aRv); 633 if (aRv.Failed()) { 634 return; 635 } 636 } 637 638 // Step 2.4 639 aReadRequest->ChunkSteps(aCx, chunk, aRv); 640 } else { 641 // Step 3. 642 // Step 3.1 643 ReadableStreamAddReadRequest(stream, aReadRequest); 644 // Step 3.2 645 ReadableStreamDefaultControllerCallPullIfNeeded(aCx, this, aRv); 646 } 647 } 648 649 // https://streams.spec.whatwg.org/#abstract-opdef-readablestreamdefaultcontroller-releasesteps 650 void ReadableStreamDefaultController::ReleaseSteps() { 651 // Step 1. Return. 652 } 653 654 } // namespace mozilla::dom