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