ReadableByteStreamController.cpp (81573B)
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/ReadableByteStreamController.h" 8 9 #include <algorithm> // std::min 10 11 #include "ReadIntoRequest.h" 12 #include "js/ArrayBuffer.h" 13 #include "js/ErrorReport.h" 14 #include "js/Exception.h" 15 #include "js/TypeDecls.h" 16 #include "js/Value.h" 17 #include "js/ValueArray.h" 18 #include "js/experimental/TypedData.h" 19 #include "js/friend/ErrorMessages.h" 20 #include "mozilla/AlreadyAddRefed.h" 21 #include "mozilla/Attributes.h" 22 #include "mozilla/ErrorResult.h" 23 #include "mozilla/HoldDropJSObjects.h" 24 #include "mozilla/dom/ByteStreamHelpers.h" 25 #include "mozilla/dom/Promise-inl.h" 26 #include "mozilla/dom/Promise.h" 27 #include "mozilla/dom/ReadableByteStreamControllerBinding.h" 28 #include "mozilla/dom/ReadableStream.h" 29 #include "mozilla/dom/ReadableStreamBYOBReader.h" 30 #include "mozilla/dom/ReadableStreamBYOBRequest.h" 31 #include "mozilla/dom/ReadableStreamControllerBase.h" 32 #include "mozilla/dom/ReadableStreamDefaultController.h" 33 #include "mozilla/dom/ReadableStreamDefaultReader.h" 34 #include "mozilla/dom/ReadableStreamGenericReader.h" 35 #include "mozilla/dom/ScriptSettings.h" 36 #include "mozilla/dom/ToJSValue.h" 37 #include "mozilla/dom/UnderlyingSourceCallbackHelpers.h" 38 #include "nsCycleCollectionParticipant.h" 39 #include "nsIGlobalObject.h" 40 #include "nsISupports.h" 41 42 namespace mozilla::dom { 43 44 using namespace streams_abstract; 45 46 // https://streams.spec.whatwg.org/#readable-byte-stream-queue-entry 47 struct ReadableByteStreamQueueEntry 48 : LinkedListElement<RefPtr<ReadableByteStreamQueueEntry>> { 49 NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING( 50 ReadableByteStreamQueueEntry) 51 NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS( 52 ReadableByteStreamQueueEntry) 53 54 ReadableByteStreamQueueEntry(JS::Handle<JSObject*> aBuffer, 55 size_t aByteOffset, size_t aByteLength) 56 : mBuffer(aBuffer), mByteOffset(aByteOffset), mByteLength(aByteLength) { 57 mozilla::HoldJSObjects(this); 58 } 59 60 JSObject* Buffer() const { return mBuffer; } 61 void SetBuffer(JS::Handle<JSObject*> aBuffer) { mBuffer = aBuffer; } 62 63 size_t ByteOffset() const { return mByteOffset; } 64 void SetByteOffset(size_t aByteOffset) { mByteOffset = aByteOffset; } 65 66 size_t ByteLength() const { return mByteLength; } 67 void SetByteLength(size_t aByteLength) { mByteLength = aByteLength; } 68 69 private: 70 // An ArrayBuffer, which will be a transferred version of the one originally 71 // supplied by the underlying byte source. 72 JS::Heap<JSObject*> mBuffer; 73 74 // A nonnegative integer number giving the byte offset derived from the view 75 // originally supplied by the underlying byte source 76 size_t mByteOffset = 0; 77 78 // A nonnegative integer number giving the byte length derived from the view 79 // originally supplied by the underlying byte source 80 size_t mByteLength = 0; 81 82 ~ReadableByteStreamQueueEntry() { mozilla::DropJSObjects(this); } 83 }; 84 85 NS_IMPL_CYCLE_COLLECTION_WITH_JS_MEMBERS(ReadableByteStreamQueueEntry, (), 86 (mBuffer)); 87 88 struct PullIntoDescriptor final 89 : LinkedListElement<RefPtr<PullIntoDescriptor>> { 90 NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(PullIntoDescriptor) 91 NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(PullIntoDescriptor) 92 93 enum Constructor { 94 DataView, 95 #define DEFINE_TYPED_CONSTRUCTOR_ENUM_NAMES(ExternalT, NativeT, Name) Name, 96 JS_FOR_EACH_TYPED_ARRAY(DEFINE_TYPED_CONSTRUCTOR_ENUM_NAMES) 97 #undef DEFINE_TYPED_CONSTRUCTOR_ENUM_NAMES 98 }; 99 100 static Constructor constructorFromScalar(JS::Scalar::Type type) { 101 switch (type) { 102 #define REMAP_PULL_INTO_DESCRIPTOR_TYPE(ExternalT, NativeT, Name) \ 103 case JS::Scalar::Name: \ 104 return Constructor::Name; 105 JS_FOR_EACH_TYPED_ARRAY(REMAP_PULL_INTO_DESCRIPTOR_TYPE) 106 #undef REMAP 107 108 case JS::Scalar::Int64: 109 case JS::Scalar::Simd128: 110 case JS::Scalar::MaxTypedArrayViewType: 111 break; 112 } 113 MOZ_CRASH("Unexpected Scalar::Type"); 114 } 115 116 PullIntoDescriptor(JS::Handle<JSObject*> aBuffer, uint64_t aBufferByteLength, 117 uint64_t aByteOffset, uint64_t aByteLength, 118 uint64_t aBytesFilled, uint64_t aMinimumFill, 119 uint64_t aElementSize, Constructor aViewConstructor, 120 ReaderType aReaderType) 121 : mBuffer(aBuffer), 122 mBufferByteLength(aBufferByteLength), 123 mByteOffset(aByteOffset), 124 mByteLength(aByteLength), 125 mBytesFilled(aBytesFilled), 126 mMinimumFill(aMinimumFill), 127 mElementSize(aElementSize), 128 mViewConstructor(aViewConstructor), 129 mReaderType(aReaderType) { 130 mozilla::HoldJSObjects(this); 131 } 132 133 JSObject* Buffer() const { return mBuffer; } 134 void SetBuffer(JS::Handle<JSObject*> aBuffer) { mBuffer = aBuffer; } 135 136 uint64_t BufferByteLength() const { return mBufferByteLength; } 137 void SetBufferByteLength(const uint64_t aBufferByteLength) { 138 mBufferByteLength = aBufferByteLength; 139 } 140 141 uint64_t ByteOffset() const { return mByteOffset; } 142 void SetByteOffset(const uint64_t aByteOffset) { mByteOffset = aByteOffset; } 143 144 uint64_t ByteLength() const { return mByteLength; } 145 void SetByteLength(const uint64_t aByteLength) { mByteLength = aByteLength; } 146 147 uint64_t BytesFilled() const { return mBytesFilled; } 148 void SetBytesFilled(const uint64_t aBytesFilled) { 149 mBytesFilled = aBytesFilled; 150 } 151 152 uint64_t MinimumFill() const { return mMinimumFill; } 153 154 uint64_t ElementSize() const { return mElementSize; } 155 void SetElementSize(const uint64_t aElementSize) { 156 mElementSize = aElementSize; 157 } 158 159 Constructor ViewConstructor() const { return mViewConstructor; } 160 161 // Note: Named GetReaderType to avoid name conflict with type. 162 ReaderType GetReaderType() const { return mReaderType; } 163 void SetReaderType(const ReaderType aReaderType) { 164 mReaderType = aReaderType; 165 } 166 167 private: 168 JS::Heap<JSObject*> mBuffer; 169 uint64_t mBufferByteLength = 0; 170 uint64_t mByteOffset = 0; 171 uint64_t mByteLength = 0; 172 uint64_t mBytesFilled = 0; 173 uint64_t mMinimumFill = 0; 174 uint64_t mElementSize = 0; 175 Constructor mViewConstructor; 176 ReaderType mReaderType; 177 178 ~PullIntoDescriptor() { mozilla::DropJSObjects(this); } 179 }; 180 181 NS_IMPL_CYCLE_COLLECTION_WITH_JS_MEMBERS(PullIntoDescriptor, (), (mBuffer)); 182 183 NS_IMPL_CYCLE_COLLECTION_CLASS(ReadableByteStreamController) 184 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(ReadableByteStreamController, 185 ReadableStreamControllerBase) 186 NS_IMPL_CYCLE_COLLECTION_UNLINK(mByobRequest, mQueue, mPendingPullIntos) 187 NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER 188 NS_IMPL_CYCLE_COLLECTION_UNLINK_END 189 190 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(ReadableByteStreamController, 191 ReadableStreamControllerBase) 192 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mByobRequest, mQueue, mPendingPullIntos) 193 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END 194 195 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(ReadableByteStreamController, 196 ReadableStreamControllerBase) 197 NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER 198 NS_IMPL_CYCLE_COLLECTION_TRACE_END 199 200 NS_IMPL_ADDREF_INHERITED(ReadableByteStreamController, 201 ReadableStreamControllerBase) 202 NS_IMPL_RELEASE_INHERITED(ReadableByteStreamController, 203 ReadableStreamControllerBase) 204 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ReadableByteStreamController) 205 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY 206 NS_INTERFACE_MAP_END_INHERITING(ReadableStreamControllerBase) 207 208 ReadableByteStreamController::ReadableByteStreamController( 209 nsIGlobalObject* aGlobal) 210 : ReadableStreamControllerBase(aGlobal) {} 211 212 ReadableByteStreamController::~ReadableByteStreamController() = default; 213 214 void ReadableByteStreamController::ClearQueue() { mQueue.clear(); } 215 216 void ReadableByteStreamController::ClearPendingPullIntos() { 217 mPendingPullIntos.clear(); 218 } 219 220 namespace streams_abstract { 221 // https://streams.spec.whatwg.org/#abstract-opdef-readablebytestreamcontrollergetbyobrequest 222 already_AddRefed<ReadableStreamBYOBRequest> 223 ReadableByteStreamControllerGetBYOBRequest( 224 JSContext* aCx, ReadableByteStreamController* aController, 225 ErrorResult& aRv) { 226 // Step 1. 227 if (!aController->GetByobRequest() && 228 !aController->PendingPullIntos().isEmpty()) { 229 // Step 1.1: 230 PullIntoDescriptor* firstDescriptor = 231 aController->PendingPullIntos().getFirst(); 232 233 // Step 1.2: 234 aRv.MightThrowJSException(); 235 JS::Rooted<JSObject*> buffer(aCx, firstDescriptor->Buffer()); 236 JS::Rooted<JSObject*> view( 237 aCx, JS_NewUint8ArrayWithBuffer( 238 aCx, buffer, 239 firstDescriptor->ByteOffset() + firstDescriptor->BytesFilled(), 240 int64_t(firstDescriptor->ByteLength() - 241 firstDescriptor->BytesFilled()))); 242 if (!view) { 243 aRv.StealExceptionFromJSContext(aCx); 244 return nullptr; 245 } 246 247 // Step 1.3: 248 RefPtr<ReadableStreamBYOBRequest> byobRequest = 249 new ReadableStreamBYOBRequest(aController->GetParentObject()); 250 251 // Step 1.4: 252 byobRequest->SetController(aController); 253 254 // Step 1.5: 255 byobRequest->SetView(view); 256 257 // Step 1.6: 258 aController->SetByobRequest(byobRequest); 259 } 260 261 // Step 2. 262 RefPtr<ReadableStreamBYOBRequest> request(aController->GetByobRequest()); 263 return request.forget(); 264 } 265 } // namespace streams_abstract 266 267 already_AddRefed<ReadableStreamBYOBRequest> 268 ReadableByteStreamController::GetByobRequest(JSContext* aCx, ErrorResult& aRv) { 269 return ReadableByteStreamControllerGetBYOBRequest(aCx, this, aRv); 270 } 271 272 // https://streams.spec.whatwg.org/#readable-byte-stream-controller-get-desired-size 273 Nullable<double> ReadableByteStreamControllerGetDesiredSize( 274 const ReadableByteStreamController* aController) { 275 // Step 1. 276 ReadableStream::ReaderState state = aController->Stream()->State(); 277 278 // Step 2. 279 if (state == ReadableStream::ReaderState::Errored) { 280 return nullptr; 281 } 282 283 // Step 3. 284 if (state == ReadableStream::ReaderState::Closed) { 285 return 0.0; 286 } 287 288 // Step 4. 289 return aController->StrategyHWM() - aController->QueueTotalSize(); 290 } 291 292 Nullable<double> ReadableByteStreamController::GetDesiredSize() const { 293 // Step 1. 294 return ReadableByteStreamControllerGetDesiredSize(this); 295 } 296 297 JSObject* ReadableByteStreamController::WrapObject( 298 JSContext* aCx, JS::Handle<JSObject*> aGivenProto) { 299 return ReadableByteStreamController_Binding::Wrap(aCx, this, aGivenProto); 300 } 301 302 namespace streams_abstract { 303 304 // https://streams.spec.whatwg.org/#readable-byte-stream-controller-invalidate-byob-request 305 static void ReadableByteStreamControllerInvalidateBYOBRequest( 306 ReadableByteStreamController* aController) { 307 // Step 1. 308 if (!aController->GetByobRequest()) { 309 return; 310 } 311 312 // Step 2. 313 aController->GetByobRequest()->SetController(nullptr); 314 315 // Step 3. 316 aController->GetByobRequest()->SetView(nullptr); 317 318 // Step 4. 319 aController->SetByobRequest(nullptr); 320 } 321 322 // https://streams.spec.whatwg.org/#readable-byte-stream-controller-clear-pending-pull-intos 323 void ReadableByteStreamControllerClearPendingPullIntos( 324 ReadableByteStreamController* aController) { 325 // Step 1. 326 ReadableByteStreamControllerInvalidateBYOBRequest(aController); 327 328 // Step 2. 329 aController->ClearPendingPullIntos(); 330 } 331 332 // https://streams.spec.whatwg.org/#reset-queue 333 void ResetQueue(ReadableByteStreamController* aContainer) { 334 // Step 1. Implied by type. 335 // Step 2. 336 aContainer->ClearQueue(); 337 338 // Step 3. 339 aContainer->SetQueueTotalSize(0); 340 } 341 342 // https://streams.spec.whatwg.org/#readable-byte-stream-controller-clear-algorithms 343 void ReadableByteStreamControllerClearAlgorithms( 344 ReadableByteStreamController* aController) { 345 // Step 1. Set controller.[[pullAlgorithm]] to undefined. 346 // Step 2. Set controller.[[cancelAlgorithm]] to undefined. 347 aController->ClearAlgorithms(); 348 } 349 350 // https://streams.spec.whatwg.org/#readable-byte-stream-controller-error 351 void ReadableByteStreamControllerError( 352 ReadableByteStreamController* aController, JS::Handle<JS::Value> aValue, 353 ErrorResult& aRv) { 354 // Step 1. Let stream be controller.[[stream]]. 355 ReadableStream* stream = aController->Stream(); 356 357 // Step 2. If stream.[[state]] is not "readable", return. 358 if (stream->State() != ReadableStream::ReaderState::Readable) { 359 return; 360 } 361 362 // Step 3. Perform 363 // !ReadableByteStreamControllerClearPendingPullIntos(controller). 364 ReadableByteStreamControllerClearPendingPullIntos(aController); 365 366 // Step 4. Perform !ResetQueue(controller). 367 ResetQueue(aController); 368 369 // Step 5. Perform !ReadableByteStreamControllerClearAlgorithms(controller). 370 ReadableByteStreamControllerClearAlgorithms(aController); 371 372 // Step 6. Perform !ReadableStreamError(stream, e). 373 AutoJSAPI jsapi; 374 if (!jsapi.Init(aController->GetParentObject())) { 375 return; 376 } 377 ReadableStreamError(jsapi.cx(), stream, aValue, aRv); 378 } 379 380 // https://streams.spec.whatwg.org/#readable-byte-stream-controller-close 381 void ReadableByteStreamControllerClose( 382 JSContext* aCx, ReadableByteStreamController* aController, 383 ErrorResult& aRv) { 384 // Step 1. 385 RefPtr<ReadableStream> stream = aController->Stream(); 386 387 // Step 2. 388 if (aController->CloseRequested() || 389 stream->State() != ReadableStream::ReaderState::Readable) { 390 return; 391 } 392 393 // Step 3. 394 if (aController->QueueTotalSize() > 0) { 395 // Step 3.1 396 aController->SetCloseRequested(true); 397 // Step 3.2 398 return; 399 } 400 401 // Step 4. 402 if (!aController->PendingPullIntos().isEmpty()) { 403 // Step 4.1. Let firstPendingPullInto be controller.[[pendingPullIntos]][0]. 404 PullIntoDescriptor* firstPendingPullInto = 405 aController->PendingPullIntos().getFirst(); 406 407 // Step 4.2. If the remainder after dividing firstPendingPullInto’s bytes 408 // filled by firstPendingPullInto’s element size is not 0, 409 if ((firstPendingPullInto->BytesFilled() % 410 firstPendingPullInto->ElementSize()) != 0) { 411 // Step 4.2.1 412 ErrorResult rv; 413 rv.ThrowTypeError("Leftover Bytes"); 414 415 JS::Rooted<JS::Value> exception(aCx); 416 MOZ_ALWAYS_TRUE(ToJSValue(aCx, std::move(rv), &exception)); 417 418 // Step 4.2.2 419 ReadableByteStreamControllerError(aController, exception, aRv); 420 if (aRv.Failed()) { 421 return; 422 } 423 424 aRv.MightThrowJSException(); 425 aRv.ThrowJSException(aCx, exception); 426 return; 427 } 428 } 429 430 // Step 5. 431 ReadableByteStreamControllerClearAlgorithms(aController); 432 433 // Step 6. 434 ReadableStreamClose(aCx, stream, aRv); 435 } 436 437 } // namespace streams_abstract 438 439 // https://streams.spec.whatwg.org/#rbs-controller-close 440 void ReadableByteStreamController::Close(JSContext* aCx, ErrorResult& aRv) { 441 // Step 1. 442 if (mCloseRequested) { 443 aRv.ThrowTypeError("Close already requested"); 444 return; 445 } 446 447 // Step 2. 448 if (Stream()->State() != ReadableStream::ReaderState::Readable) { 449 aRv.ThrowTypeError("Closing un-readable stream controller"); 450 return; 451 } 452 453 // Step 3. 454 ReadableByteStreamControllerClose(aCx, this, aRv); 455 } 456 457 namespace streams_abstract { 458 459 // https://streams.spec.whatwg.org/#readable-byte-stream-controller-enqueue-chunk-to-queue 460 void ReadableByteStreamControllerEnqueueChunkToQueue( 461 ReadableByteStreamController* aController, 462 JS::Handle<JSObject*> aTransferredBuffer, size_t aByteOffset, 463 size_t aByteLength) { 464 // Step 1. 465 RefPtr<ReadableByteStreamQueueEntry> queueEntry = 466 new ReadableByteStreamQueueEntry(aTransferredBuffer, aByteOffset, 467 aByteLength); 468 aController->Queue().insertBack(queueEntry); 469 470 // Step 2. 471 aController->AddToQueueTotalSize(double(aByteLength)); 472 } 473 474 // https://streams.spec.whatwg.org/#abstract-opdef-readablebytestreamcontrollerenqueueclonedchunktoqueue 475 void ReadableByteStreamControllerEnqueueClonedChunkToQueue( 476 JSContext* aCx, ReadableByteStreamController* aController, 477 JS::Handle<JSObject*> aBuffer, size_t aByteOffset, size_t aByteLength, 478 ErrorResult& aRv) { 479 // Step 1. Let cloneResult be CloneArrayBuffer(buffer, byteOffset, byteLength, 480 // %ArrayBuffer%). 481 aRv.MightThrowJSException(); 482 JS::Rooted<JSObject*> cloneResult( 483 aCx, JS::ArrayBufferClone(aCx, aBuffer, aByteOffset, aByteLength)); 484 485 // Step 2. If cloneResult is an abrupt completion, 486 if (!cloneResult) { 487 JS::Rooted<JS::Value> exception(aCx); 488 if (!JS_GetPendingException(aCx, &exception)) { 489 // Uncatchable exception; we should mark aRv and return. 490 aRv.StealExceptionFromJSContext(aCx); 491 return; 492 } 493 JS_ClearPendingException(aCx); 494 495 // Step 2.1. Perform ! ReadableByteStreamControllerError(controller, 496 // cloneResult.[[Value]]). 497 ReadableByteStreamControllerError(aController, exception, aRv); 498 if (aRv.Failed()) { 499 return; 500 } 501 502 // Step 2.2. Return cloneResult. 503 aRv.ThrowJSException(aCx, exception); 504 return; 505 } 506 507 // Step 3. Perform ! 508 // ReadableByteStreamControllerEnqueueChunkToQueue(controller, 509 // cloneResult.[[Value]], 0, byteLength). 510 ReadableByteStreamControllerEnqueueChunkToQueue(aController, cloneResult, 0, 511 aByteLength); 512 } 513 514 already_AddRefed<PullIntoDescriptor> 515 ReadableByteStreamControllerShiftPendingPullInto( 516 ReadableByteStreamController* aController); 517 518 // https://streams.spec.whatwg.org/#abstract-opdef-readablebytestreamcontrollerenqueuedetachedpullintotoqueue 519 void ReadableByteStreamControllerEnqueueDetachedPullIntoToQueue( 520 JSContext* aCx, ReadableByteStreamController* aController, 521 PullIntoDescriptor* aPullIntoDescriptor, ErrorResult& aRv) { 522 // Step 1. Assert: pullIntoDescriptor’s reader type is "none". 523 MOZ_ASSERT(aPullIntoDescriptor->GetReaderType() == ReaderType::None); 524 525 // Step 2. If pullIntoDescriptor’s bytes filled > 0, 526 // perform ? ReadableByteStreamControllerEnqueueClonedChunkToQueue(controller, 527 // pullIntoDescriptor’s buffer, pullIntoDescriptor’s byte offset, 528 // pullIntoDescriptor’s bytes filled). 529 if (aPullIntoDescriptor->BytesFilled() > 0) { 530 JS::Rooted<JSObject*> buffer(aCx, aPullIntoDescriptor->Buffer()); 531 ReadableByteStreamControllerEnqueueClonedChunkToQueue( 532 aCx, aController, buffer, aPullIntoDescriptor->ByteOffset(), 533 aPullIntoDescriptor->BytesFilled(), aRv); 534 if (aRv.Failed()) { 535 return; 536 } 537 } 538 539 // Step 3. Perform ! 540 // ReadableByteStreamControllerShiftPendingPullInto(controller). 541 RefPtr<PullIntoDescriptor> discarded = 542 ReadableByteStreamControllerShiftPendingPullInto(aController); 543 (void)discarded; 544 } 545 546 // https://streams.spec.whatwg.org/#readable-stream-get-num-read-into-requests 547 static size_t ReadableStreamGetNumReadIntoRequests(ReadableStream* aStream) { 548 // Step 1. 549 MOZ_ASSERT(ReadableStreamHasBYOBReader(aStream)); 550 551 // Step 2. 552 return aStream->GetReader()->AsBYOB()->ReadIntoRequests().length(); 553 } 554 555 // https://streams.spec.whatwg.org/#readable-byte-stream-controller-should-call-pull 556 bool ReadableByteStreamControllerShouldCallPull( 557 ReadableByteStreamController* aController) { 558 // Step 1. Let stream be controller.[[stream]]. 559 ReadableStream* stream = aController->Stream(); 560 561 // Step 2. If stream.[[state]] is not "readable", return false. 562 if (stream->State() != ReadableStream::ReaderState::Readable) { 563 return false; 564 } 565 566 // Step 3. If controller.[[closeRequested]] is true, return false. 567 if (aController->CloseRequested()) { 568 return false; 569 } 570 571 // Step 4. If controller.[[started]] is false, return false. 572 if (!aController->Started()) { 573 return false; 574 } 575 576 // Step 5. If ! ReadableStreamHasDefaultReader(stream) is true 577 // and ! ReadableStreamGetNumReadRequests(stream) > 0, return true. 578 if (ReadableStreamHasDefaultReader(stream) && 579 ReadableStreamGetNumReadRequests(stream) > 0) { 580 return true; 581 } 582 583 // Step 6. If ! ReadableStreamHasBYOBReader(stream) is true 584 // and ! ReadableStreamGetNumReadIntoRequests(stream) > 0, return true. 585 if (ReadableStreamHasBYOBReader(stream) && 586 ReadableStreamGetNumReadIntoRequests(stream) > 0) { 587 return true; 588 } 589 590 // Step 7. Let desiredSize be 591 // ! ReadableByteStreamControllerGetDesiredSize(controller). 592 Nullable<double> desiredSize = 593 ReadableByteStreamControllerGetDesiredSize(aController); 594 595 // Step 8. Assert: desiredSize is not null. 596 MOZ_ASSERT(!desiredSize.IsNull()); 597 598 // Step 9. If desiredSize > 0, return true. 599 // Step 10. Return false. 600 return desiredSize.Value() > 0; 601 } 602 603 // https://streams.spec.whatwg.org/#readable-byte-stream-controller-call-pull-if-needed 604 void ReadableByteStreamControllerCallPullIfNeeded( 605 JSContext* aCx, ReadableByteStreamController* aController, 606 ErrorResult& aRv) { 607 // Step 1. 608 bool shouldPull = ReadableByteStreamControllerShouldCallPull(aController); 609 610 // Step 2. 611 if (!shouldPull) { 612 return; 613 } 614 615 // Step 3. 616 if (aController->Pulling()) { 617 aController->SetPullAgain(true); 618 return; 619 } 620 621 // Step 4. 622 MOZ_ASSERT(!aController->PullAgain()); 623 624 // Step 5. 625 aController->SetPulling(true); 626 627 // Step 6. 628 RefPtr<ReadableStreamControllerBase> controller(aController); 629 RefPtr<UnderlyingSourceAlgorithmsBase> algorithms = 630 aController->GetAlgorithms(); 631 RefPtr<Promise> pullPromise = algorithms->PullCallback(aCx, *controller, aRv); 632 if (aRv.Failed()) { 633 return; 634 } 635 636 // Steps 7+8 637 pullPromise->AddCallbacksWithCycleCollectedArgs( 638 [](JSContext* aCx, JS::Handle<JS::Value> aValue, ErrorResult& aRv, 639 ReadableByteStreamController* aController) 640 MOZ_CAN_RUN_SCRIPT_BOUNDARY { 641 // Step 7.1 642 aController->SetPulling(false); 643 // Step 7.2 644 if (aController->PullAgain()) { 645 // Step 7.2.1 646 aController->SetPullAgain(false); 647 648 // Step 7.2.2 649 ReadableByteStreamControllerCallPullIfNeeded( 650 aCx, MOZ_KnownLive(aController), aRv); 651 } 652 }, 653 [](JSContext* aCx, JS::Handle<JS::Value> aValue, ErrorResult& aRv, 654 ReadableByteStreamController* aController) { 655 // Step 8.1 656 ReadableByteStreamControllerError(aController, aValue, aRv); 657 }, 658 RefPtr(aController)); 659 } 660 661 bool ReadableByteStreamControllerFillPullIntoDescriptorFromQueue( 662 JSContext* aCx, ReadableByteStreamController* aController, 663 PullIntoDescriptor* aPullIntoDescriptor, ErrorResult& aRv); 664 665 JSObject* ReadableByteStreamControllerConvertPullIntoDescriptor( 666 JSContext* aCx, PullIntoDescriptor* pullIntoDescriptor, ErrorResult& aRv); 667 668 // https://streams.spec.whatwg.org/#readable-stream-fulfill-read-into-request 669 MOZ_CAN_RUN_SCRIPT 670 void ReadableStreamFulfillReadIntoRequest(JSContext* aCx, 671 ReadableStream* aStream, 672 JS::Handle<JS::Value> aChunk, 673 bool done, ErrorResult& aRv) { 674 // Step 1. Assert: !ReadableStreamHasBYOBReader(stream) is true. 675 MOZ_ASSERT(ReadableStreamHasBYOBReader(aStream)); 676 677 // Step 2. Let reader be stream.[[reader]]. 678 ReadableStreamBYOBReader* reader = aStream->GetReader()->AsBYOB(); 679 680 // Step 3. Assert: reader.[[readIntoRequests]] is not empty. 681 MOZ_ASSERT(!reader->ReadIntoRequests().isEmpty()); 682 683 // Step 4. Let readIntoRequest be reader.[[readIntoRequests]][0]. 684 // Step 5. Remove readIntoRequest from reader.[[readIntoRequests]]. 685 RefPtr<ReadIntoRequest> readIntoRequest = 686 reader->ReadIntoRequests().popFirst(); 687 688 // Step 6. If done is true, perform readIntoRequest’s close steps, given 689 // chunk. 690 if (done) { 691 readIntoRequest->CloseSteps(aCx, aChunk, aRv); 692 return; 693 } 694 695 // Step 7. Otherwise, perform readIntoRequest’s chunk steps, given chunk. 696 readIntoRequest->ChunkSteps(aCx, aChunk, aRv); 697 } 698 699 // https://streams.spec.whatwg.org/#readable-byte-stream-controller-commit-pull-into-descriptor 700 MOZ_CAN_RUN_SCRIPT 701 void ReadableByteStreamControllerCommitPullIntoDescriptor( 702 JSContext* aCx, ReadableStream* aStream, 703 PullIntoDescriptor* pullIntoDescriptor, ErrorResult& aRv) { 704 // Step 1. Assert: stream.[[state]] is not "errored". 705 MOZ_ASSERT(aStream->State() != ReadableStream::ReaderState::Errored); 706 707 // Step 2. Assert: pullIntoDescriptor.reader type is not "none". 708 MOZ_ASSERT(pullIntoDescriptor->GetReaderType() != ReaderType::None); 709 710 // Step 3. Let done be false. 711 bool done = false; 712 713 // Step 4. If stream.[[state]] is "closed", 714 if (aStream->State() == ReadableStream::ReaderState::Closed) { 715 // Step 4.1. Assert: the remainder after dividing pullIntoDescriptor’s bytes 716 // filled by pullIntoDescriptor’s element size is 0. 717 MOZ_ASSERT((pullIntoDescriptor->BytesFilled() % 718 pullIntoDescriptor->ElementSize()) == 0); 719 720 // Step 4.2. Set done to true. 721 done = true; 722 } 723 724 // Step 5. Let filledView be ! 725 // ReadableByteStreamControllerConvertPullIntoDescriptor(pullIntoDescriptor). 726 JS::Rooted<JSObject*> filledView( 727 aCx, ReadableByteStreamControllerConvertPullIntoDescriptor( 728 aCx, pullIntoDescriptor, aRv)); 729 if (aRv.Failed()) { 730 return; 731 } 732 JS::Rooted<JS::Value> filledViewValue(aCx, JS::ObjectValue(*filledView)); 733 734 // Step 6. If pullIntoDescriptor’s reader type is "default", 735 if (pullIntoDescriptor->GetReaderType() == ReaderType::Default) { 736 // Step 6.1. Perform !ReadableStreamFulfillReadRequest(stream, filledView, 737 // done). 738 ReadableStreamFulfillReadRequest(aCx, aStream, filledViewValue, done, aRv); 739 return; 740 } 741 742 // Step 7.1. Assert: pullIntoDescriptor’s reader type is "byob". 743 MOZ_ASSERT(pullIntoDescriptor->GetReaderType() == ReaderType::BYOB); 744 745 // Step 7.2 Perform !ReadableStreamFulfillReadIntoRequest(stream, filledView, 746 // done). 747 ReadableStreamFulfillReadIntoRequest(aCx, aStream, filledViewValue, done, 748 aRv); 749 } 750 751 // https://streams.spec.whatwg.org/#readable-byte-stream-controller-process-pull-into-descriptors-using-queue 752 MOZ_CAN_RUN_SCRIPT 753 void ReadableByteStreamControllerProcessPullIntoDescriptorsUsingQueue( 754 JSContext* aCx, ReadableByteStreamController* aController, 755 nsTArray<RefPtr<PullIntoDescriptor>>& aFilledPullIntos, ErrorResult& aRv) { 756 // Step 1. Assert: controller.[[closeRequested]] is false. 757 MOZ_ASSERT(!aController->CloseRequested()); 758 759 // Step 2. Let filledPullIntos be a new empty list. 760 MOZ_ASSERT(aFilledPullIntos.IsEmpty()); 761 762 // Step 3. While controller.[[pendingPullIntos]] is not empty, 763 while (!aController->PendingPullIntos().isEmpty()) { 764 // Step 3.1. If controller.[[queueTotalSize]] is 0, then break. 765 if (aController->QueueTotalSize() == 0) { 766 break; 767 } 768 769 // Step 3.2. Let pullIntoDescriptor be controller.[[pendingPullIntos]][0]. 770 RefPtr<PullIntoDescriptor> pullIntoDescriptor = 771 aController->PendingPullIntos().getFirst(); 772 773 // Step 3.3. If 774 // !ReadableByteStreamControllerFillPullIntoDescriptorFromQueue(controller, 775 // pullIntoDescriptor) is true, 776 bool ready = ReadableByteStreamControllerFillPullIntoDescriptorFromQueue( 777 aCx, aController, pullIntoDescriptor, aRv); 778 if (aRv.Failed()) { 779 return; 780 } 781 782 if (ready) { 783 // Step 3.3.1. Perform 784 // !ReadableByteStreamControllerShiftPendingPullInto(controller). 785 RefPtr<PullIntoDescriptor> discardedPullIntoDescriptor = 786 ReadableByteStreamControllerShiftPendingPullInto(aController); 787 788 // Step 3.3.2. Append pullIntoDescriptor to filledPullIntos. 789 aFilledPullIntos.AppendElement(pullIntoDescriptor); 790 } 791 } 792 793 // Step 4: Return filledPullIntos. (Implicit) 794 } 795 796 MOZ_CAN_RUN_SCRIPT 797 void ReadableByteStreamControllerHandleQueueDrain( 798 JSContext* aCx, ReadableByteStreamController* aController, 799 ErrorResult& aRv); 800 801 // https://streams.spec.whatwg.org/#abstract-opdef-readablebytestreamcontrollerfillreadrequestfromqueue 802 MOZ_CAN_RUN_SCRIPT void ReadableByteStreamControllerFillReadRequestFromQueue( 803 JSContext* aCx, ReadableByteStreamController* aController, 804 ReadRequest* aReadRequest, ErrorResult& aRv) { 805 // Step 1. Assert: controller.[[queueTotalSize]] > 0. 806 MOZ_ASSERT(aController->QueueTotalSize() > 0); 807 // Also assert that the queue has a non-zero length; 808 MOZ_ASSERT(aController->Queue().length() > 0); 809 810 // Step 2. Let entry be controller.[[queue]][0]. 811 // Step 3. Remove entry from controller.[[queue]]. 812 RefPtr<ReadableByteStreamQueueEntry> entry = aController->Queue().popFirst(); 813 814 // Assert that we actually got an entry. 815 MOZ_ASSERT(entry); 816 817 // Step 4. Set controller.[[queueTotalSize]] to controller.[[queueTotalSize]] 818 // − entry’s byte length. 819 aController->SetQueueTotalSize(aController->QueueTotalSize() - 820 double(entry->ByteLength())); 821 822 // Step 5. Perform ! ReadableByteStreamControllerHandleQueueDrain(controller). 823 ReadableByteStreamControllerHandleQueueDrain(aCx, aController, aRv); 824 if (aRv.Failed()) { 825 return; 826 } 827 828 // Step 6. Let view be ! Construct(%Uint8Array%, « entry’s buffer, entry’s 829 // byte offset, entry’s byte length »). 830 aRv.MightThrowJSException(); 831 JS::Rooted<JSObject*> buffer(aCx, entry->Buffer()); 832 JS::Rooted<JSObject*> view( 833 aCx, JS_NewUint8ArrayWithBuffer(aCx, buffer, entry->ByteOffset(), 834 int64_t(entry->ByteLength()))); 835 if (!view) { 836 aRv.StealExceptionFromJSContext(aCx); 837 return; 838 } 839 840 // Step 7. Perform readRequest’s chunk steps, given view. 841 JS::Rooted<JS::Value> viewValue(aCx, JS::ObjectValue(*view)); 842 aReadRequest->ChunkSteps(aCx, viewValue, aRv); 843 } 844 845 MOZ_CAN_RUN_SCRIPT void 846 ReadableByteStreamControllerProcessReadRequestsUsingQueue( 847 JSContext* aCx, ReadableByteStreamController* aController, 848 ErrorResult& aRv) { 849 // Step 1. Let reader be controller.[[stream]].[[reader]]. 850 // Step 2. Assert: reader implements ReadableStreamDefaultReader. 851 RefPtr<ReadableStreamDefaultReader> reader = 852 aController->Stream()->GetDefaultReader(); 853 854 // Step 3. While reader.[[readRequests]] is not empty, 855 while (!reader->ReadRequests().isEmpty()) { 856 // Step 3.1. If controller.[[queueTotalSize]] is 0, return. 857 if (aController->QueueTotalSize() == 0) { 858 return; 859 } 860 861 // Step 3.2. Let readRequest be reader.[[readRequests]][0]. 862 // Step 3.3. Remove readRequest from reader.[[readRequests]]. 863 RefPtr<ReadRequest> readRequest = reader->ReadRequests().popFirst(); 864 865 // Step 3.4. Perform ! 866 // ReadableByteStreamControllerFillReadRequestFromQueue(controller, 867 // readRequest). 868 ReadableByteStreamControllerFillReadRequestFromQueue(aCx, aController, 869 readRequest, aRv); 870 if (aRv.Failed()) { 871 return; 872 } 873 } 874 } 875 876 // https://streams.spec.whatwg.org/#readable-byte-stream-controller-enqueue 877 void ReadableByteStreamControllerEnqueue( 878 JSContext* aCx, ReadableByteStreamController* aController, 879 JS::Handle<JSObject*> aChunk, ErrorResult& aRv) { 880 aRv.MightThrowJSException(); 881 882 // Step 1. 883 RefPtr<ReadableStream> stream = aController->Stream(); 884 885 // Step 2. 886 if (aController->CloseRequested() || 887 stream->State() != ReadableStream::ReaderState::Readable) { 888 return; 889 } 890 891 // Step 3. 892 bool isShared; 893 JS::Rooted<JSObject*> buffer( 894 aCx, JS_GetArrayBufferViewBuffer(aCx, aChunk, &isShared)); 895 if (!buffer) { 896 aRv.StealExceptionFromJSContext(aCx); 897 return; 898 } 899 900 // Step 4. 901 size_t byteOffset = JS_GetArrayBufferViewByteOffset(aChunk); 902 903 // Step 5. 904 size_t byteLength = JS_GetArrayBufferViewByteLength(aChunk); 905 906 // Step 6. 907 if (JS::IsDetachedArrayBufferObject(buffer)) { 908 aRv.ThrowTypeError("Detached Array Buffer"); 909 return; 910 } 911 912 // Step 7. 913 JS::Rooted<JSObject*> transferredBuffer(aCx, 914 TransferArrayBuffer(aCx, buffer)); 915 if (!transferredBuffer) { 916 aRv.StealExceptionFromJSContext(aCx); 917 return; 918 } 919 920 // Step 8. 921 if (!aController->PendingPullIntos().isEmpty()) { 922 // Step 8.1 923 RefPtr<PullIntoDescriptor> firstPendingPullInto = 924 aController->PendingPullIntos().getFirst(); 925 926 // Step 8.2 927 JS::Rooted<JSObject*> pendingBuffer(aCx, firstPendingPullInto->Buffer()); 928 if (JS::IsDetachedArrayBufferObject(pendingBuffer)) { 929 aRv.ThrowTypeError("Pending PullInto has detached buffer"); 930 return; 931 } 932 933 // Step 8.3. Perform ! 934 // ReadableByteStreamControllerInvalidateBYOBRequest(controller). 935 ReadableByteStreamControllerInvalidateBYOBRequest(aController); 936 937 // Step 8.4. Set firstPendingPullInto’s buffer to ! 938 // TransferArrayBuffer(firstPendingPullInto’s buffer). 939 pendingBuffer = TransferArrayBuffer(aCx, pendingBuffer); 940 if (!pendingBuffer) { 941 aRv.StealExceptionFromJSContext(aCx); 942 return; 943 } 944 firstPendingPullInto->SetBuffer(pendingBuffer); 945 946 // Step 8.5. If firstPendingPullInto’s reader type is "none", perform ? 947 // ReadableByteStreamControllerEnqueueDetachedPullIntoToQueue(controller, 948 // firstPendingPullInto). 949 if (firstPendingPullInto->GetReaderType() == ReaderType::None) { 950 ReadableByteStreamControllerEnqueueDetachedPullIntoToQueue( 951 aCx, aController, firstPendingPullInto, aRv); 952 if (aRv.Failed()) { 953 return; 954 } 955 } 956 } 957 958 // Step 9. If ! ReadableStreamHasDefaultReader(stream) is true, 959 if (ReadableStreamHasDefaultReader(stream)) { 960 // Step 9.1. Perform ! 961 // ReadableByteStreamControllerProcessReadRequestsUsingQueue(controller). 962 ReadableByteStreamControllerProcessReadRequestsUsingQueue(aCx, aController, 963 aRv); 964 if (aRv.Failed()) { 965 return; 966 } 967 968 // Step 9.2. If ! ReadableStreamGetNumReadRequests(stream) is 0, 969 if (ReadableStreamGetNumReadRequests(stream) == 0) { 970 // Step 9.2.1 Assert: controller.[[pendingPullIntos]] is empty. 971 MOZ_ASSERT(aController->PendingPullIntos().isEmpty()); 972 973 // Step 9.2.2. Perform ! 974 // ReadableByteStreamControllerEnqueueChunkToQueue(controller, 975 // transferredBuffer, byteOffset, byteLength). 976 ReadableByteStreamControllerEnqueueChunkToQueue( 977 aController, transferredBuffer, byteOffset, byteLength); 978 979 // Step 9.3. Otherwise, 980 } else { 981 // Step 9.3.1 Assert: controller.[[queue]] is empty. 982 MOZ_ASSERT(aController->Queue().isEmpty()); 983 984 // Step 9.3.2. If controller.[[pendingPullIntos]] is not empty, 985 if (!aController->PendingPullIntos().isEmpty()) { 986 // Step 9.3.2.1. Assert: controller.[[pendingPullIntos]][0]'s reader 987 // type is "default". 988 MOZ_ASSERT( 989 aController->PendingPullIntos().getFirst()->GetReaderType() == 990 ReaderType::Default); 991 992 // Step 9.3.2.2. Perform ! 993 // ReadableByteStreamControllerShiftPendingPullInto(controller). 994 RefPtr<PullIntoDescriptor> pullIntoDescriptor = 995 ReadableByteStreamControllerShiftPendingPullInto(aController); 996 (void)pullIntoDescriptor; 997 } 998 999 // Step 9.3.3. Let transferredView be ! Construct(%Uint8Array%, « 1000 // transferredBuffer, byteOffset, byteLength »). 1001 JS::Rooted<JSObject*> transferredView( 1002 aCx, JS_NewUint8ArrayWithBuffer(aCx, transferredBuffer, byteOffset, 1003 int64_t(byteLength))); 1004 if (!transferredView) { 1005 aRv.StealExceptionFromJSContext(aCx); 1006 return; 1007 } 1008 1009 // Step 9.3.4. Perform ! ReadableStreamFulfillReadRequest(stream, 1010 // transferredView, false). 1011 JS::Rooted<JS::Value> transferredViewValue( 1012 aCx, JS::ObjectValue(*transferredView)); 1013 ReadableStreamFulfillReadRequest(aCx, stream, transferredViewValue, false, 1014 aRv); 1015 if (aRv.Failed()) { 1016 return; 1017 } 1018 } 1019 1020 // Step 10. Otherwise, if ! ReadableStreamHasBYOBReader(stream) is true, 1021 } else if (ReadableStreamHasBYOBReader(stream)) { 1022 // Step 10.1. Perform ! 1023 // ReadableByteStreamControllerEnqueueChunkToQueue(controller, 1024 // transferredBuffer, byteOffset, byteLength). 1025 ReadableByteStreamControllerEnqueueChunkToQueue( 1026 aController, transferredBuffer, byteOffset, byteLength); 1027 1028 // Step 10.2. Let filledPullIntos be the result of performing ! 1029 // ReadableByteStreamControllerProcessPullIntoDescriptorsUsingQueue(controller). 1030 nsTArray<RefPtr<PullIntoDescriptor>> filledPullIntos; 1031 ReadableByteStreamControllerProcessPullIntoDescriptorsUsingQueue( 1032 aCx, aController, filledPullIntos, aRv); 1033 if (aRv.Failed()) { 1034 return; 1035 } 1036 1037 // Step 10.3. For each filledPullInto of filledPullIntos, 1038 for (auto& filledPullInto : filledPullIntos) { 1039 // Step 10.3.1. Perform ! 1040 // ReadableByteStreamControllerCommitPullIntoDescriptor(stream, 1041 // filledPullInto). 1042 ReadableByteStreamControllerCommitPullIntoDescriptor( 1043 aCx, stream, MOZ_KnownLive(filledPullInto), aRv); 1044 if (aRv.Failed()) { 1045 return; 1046 } 1047 } 1048 1049 // Step 11. Otherwise, 1050 } else { 1051 // Step 11.1. Assert: ! IsReadableStreamLocked(stream) is false. 1052 MOZ_ASSERT(!IsReadableStreamLocked(stream)); 1053 1054 // Step 11.2. Perform ! 1055 // ReadableByteStreamControllerEnqueueChunkToQueue(controller, 1056 // transferredBuffer, byteOffset, byteLength). 1057 ReadableByteStreamControllerEnqueueChunkToQueue( 1058 aController, transferredBuffer, byteOffset, byteLength); 1059 } 1060 1061 // Step 12. Perform ! 1062 // ReadableByteStreamControllerCallPullIfNeeded(controller). 1063 ReadableByteStreamControllerCallPullIfNeeded(aCx, aController, aRv); 1064 } 1065 1066 } // namespace streams_abstract 1067 1068 // https://streams.spec.whatwg.org/#rbs-controller-enqueue 1069 void ReadableByteStreamController::Enqueue(JSContext* aCx, 1070 const ArrayBufferView& aChunk, 1071 ErrorResult& aRv) { 1072 // Step 1. 1073 JS::Rooted<JSObject*> chunk(aCx, aChunk.Obj()); 1074 if (JS_GetArrayBufferViewByteLength(chunk) == 0) { 1075 aRv.ThrowTypeError("Zero Length View"); 1076 return; 1077 } 1078 1079 // Step 2. 1080 bool isShared; 1081 JS::Rooted<JSObject*> viewedArrayBuffer( 1082 aCx, JS_GetArrayBufferViewBuffer(aCx, chunk, &isShared)); 1083 if (!viewedArrayBuffer) { 1084 aRv.StealExceptionFromJSContext(aCx); 1085 return; 1086 } 1087 1088 if (JS::GetArrayBufferByteLength(viewedArrayBuffer) == 0) { 1089 aRv.ThrowTypeError("Zero Length Buffer"); 1090 return; 1091 } 1092 1093 // Step 3. 1094 if (CloseRequested()) { 1095 aRv.ThrowTypeError("close requested"); 1096 return; 1097 } 1098 1099 // Step 4. 1100 if (Stream()->State() != ReadableStream::ReaderState::Readable) { 1101 aRv.ThrowTypeError("Not Readable"); 1102 return; 1103 } 1104 1105 // Step 5. 1106 ReadableByteStreamControllerEnqueue(aCx, this, chunk, aRv); 1107 } 1108 1109 // https://streams.spec.whatwg.org/#rbs-controller-error 1110 void ReadableByteStreamController::Error(JSContext* aCx, 1111 JS::Handle<JS::Value> aErrorValue, 1112 ErrorResult& aRv) { 1113 // Step 1. 1114 ReadableByteStreamControllerError(this, aErrorValue, aRv); 1115 } 1116 1117 // https://streams.spec.whatwg.org/#rbs-controller-private-cancel 1118 already_AddRefed<Promise> ReadableByteStreamController::CancelSteps( 1119 JSContext* aCx, JS::Handle<JS::Value> aReason, ErrorResult& aRv) { 1120 // Step 1. 1121 ReadableByteStreamControllerClearPendingPullIntos(this); 1122 1123 // Step 2. 1124 ResetQueue(this); 1125 1126 // Step 3. 1127 Optional<JS::Handle<JS::Value>> reason(aCx, aReason); 1128 RefPtr<UnderlyingSourceAlgorithmsBase> algorithms = mAlgorithms; 1129 RefPtr<Promise> result = algorithms->CancelCallback(aCx, reason, aRv); 1130 if (NS_WARN_IF(aRv.Failed())) { 1131 return nullptr; 1132 } 1133 // Step 4. 1134 ReadableByteStreamControllerClearAlgorithms(this); 1135 1136 // Step 5. 1137 return result.forget(); 1138 } 1139 1140 namespace streams_abstract { 1141 // https://streams.spec.whatwg.org/#readable-byte-stream-controller-handle-queue-drain 1142 void ReadableByteStreamControllerHandleQueueDrain( 1143 JSContext* aCx, ReadableByteStreamController* aController, 1144 ErrorResult& aRv) { 1145 // Step 1. 1146 MOZ_ASSERT(aController->Stream()->State() == 1147 ReadableStream::ReaderState::Readable); 1148 1149 // Step 2. 1150 if (aController->QueueTotalSize() == 0 && aController->CloseRequested()) { 1151 // Step 2.1 1152 ReadableByteStreamControllerClearAlgorithms(aController); 1153 1154 // Step 2.2 1155 RefPtr<ReadableStream> stream = aController->Stream(); 1156 ReadableStreamClose(aCx, stream, aRv); 1157 return; 1158 } 1159 1160 // Step 3.1 1161 ReadableByteStreamControllerCallPullIfNeeded(aCx, aController, aRv); 1162 } 1163 } // namespace streams_abstract 1164 1165 // https://streams.spec.whatwg.org/#rbs-controller-private-pull 1166 void ReadableByteStreamController::PullSteps(JSContext* aCx, 1167 ReadRequest* aReadRequest, 1168 ErrorResult& aRv) { 1169 // Step 1. Let stream be this.[[stream]]. 1170 ReadableStream* stream = Stream(); 1171 1172 // Step 2. Assert: ! ReadableStreamHasDefaultReader(stream) is true. 1173 MOZ_ASSERT(ReadableStreamHasDefaultReader(stream)); 1174 1175 // Step 3. If this.[[queueTotalSize]] > 0, 1176 if (QueueTotalSize() > 0) { 1177 // Step 3.1. Assert: ! ReadableStreamGetNumReadRequests ( stream ) is 0. 1178 MOZ_ASSERT(ReadableStreamGetNumReadRequests(stream) == 0); 1179 1180 // Step 3.2. Perform ! 1181 // ReadableByteStreamControllerFillReadRequestFromQueue(this, readRequest). 1182 ReadableByteStreamControllerFillReadRequestFromQueue(aCx, this, 1183 aReadRequest, aRv); 1184 1185 // Step 3.3. Return. 1186 return; 1187 } 1188 1189 // Step 4. Let autoAllocateChunkSize be this.[[autoAllocateChunkSize]]. 1190 Maybe<uint64_t> autoAllocateChunkSize = AutoAllocateChunkSize(); 1191 1192 // Step 5. If autoAllocateChunkSize is not undefined, 1193 if (autoAllocateChunkSize) { 1194 // Step 5.1. Let buffer be Construct(%ArrayBuffer%, « autoAllocateChunkSize 1195 // »). 1196 aRv.MightThrowJSException(); 1197 JS::Rooted<JSObject*> buffer( 1198 aCx, JS::NewArrayBuffer(aCx, *autoAllocateChunkSize)); 1199 1200 // Step 5.2. If buffer is an abrupt completion, 1201 if (!buffer) { 1202 // Step 5.2.1. Perform readRequest’s error steps, given buffer.[[Value]]. 1203 JS::Rooted<JS::Value> bufferError(aCx); 1204 if (!JS_GetPendingException(aCx, &bufferError)) { 1205 // Uncatchable exception; we should mark aRv and return. 1206 aRv.StealExceptionFromJSContext(aCx); 1207 return; 1208 } 1209 1210 // It's not explicitly stated, but I assume the intention here is that 1211 // we perform a normal completion here. 1212 JS_ClearPendingException(aCx); 1213 1214 aReadRequest->ErrorSteps(aCx, bufferError, aRv); 1215 1216 // Step 5.2.2. Return. 1217 return; 1218 } 1219 1220 // Step 5.3 Let pullIntoDescriptor be a new pull-into descriptor with 1221 // buffer buffer.[[Value]] 1222 // buffer byte length autoAllocateChunkSize 1223 // byte offset 0 1224 // byte length autoAllocateChunkSize 1225 // bytes filled 0 1226 // minimum fill 1 1227 // element size 1 1228 // view constructor %Uint8Array% 1229 // reader type "default" 1230 RefPtr<PullIntoDescriptor> pullIntoDescriptor = new PullIntoDescriptor( 1231 buffer, /* aBufferByteLength */ *autoAllocateChunkSize, 1232 /*aByteOffset */ 0, /* aByteLength */ *autoAllocateChunkSize, 1233 /* aBytesFilled */ 0, /* aMinimumFill */ 1, /* aElementSize */ 1, 1234 PullIntoDescriptor::Constructor::Uint8, ReaderType::Default); 1235 1236 // Step 5.4. Append pullIntoDescriptor to this.[[pendingPullIntos]]. 1237 PendingPullIntos().insertBack(pullIntoDescriptor); 1238 } 1239 1240 // Step 6. Perform ! ReadableStreamAddReadRequest(stream, readRequest). 1241 ReadableStreamAddReadRequest(stream, aReadRequest); 1242 1243 // Step 7. Perform ! ReadableByteStreamControllerCallPullIfNeeded(this). 1244 ReadableByteStreamControllerCallPullIfNeeded(aCx, this, aRv); 1245 } 1246 1247 // https://streams.spec.whatwg.org/#abstract-opdef-readablebytestreamcontroller-releasesteps 1248 void ReadableByteStreamController::ReleaseSteps() { 1249 // Step 1. If this.[[pendingPullIntos]] is not empty, 1250 if (!PendingPullIntos().isEmpty()) { 1251 // Step 1.1. Let firstPendingPullInto be this.[[pendingPullIntos]][0]. 1252 RefPtr<PullIntoDescriptor> firstPendingPullInto = 1253 PendingPullIntos().popFirst(); 1254 1255 // Step 1.2. Set firstPendingPullInto’s reader type to "none". 1256 firstPendingPullInto->SetReaderType(ReaderType::None); 1257 1258 // Step 1.3. Set this.[[pendingPullIntos]] to the list « 1259 // firstPendingPullInto ». 1260 PendingPullIntos().clear(); 1261 PendingPullIntos().insertBack(firstPendingPullInto); 1262 } 1263 } 1264 1265 namespace streams_abstract { 1266 1267 // https://streams.spec.whatwg.org/#readable-byte-stream-controller-shift-pending-pull-into 1268 already_AddRefed<PullIntoDescriptor> 1269 ReadableByteStreamControllerShiftPendingPullInto( 1270 ReadableByteStreamController* aController) { 1271 // Step 1. 1272 MOZ_ASSERT(!aController->GetByobRequest()); 1273 1274 // Step 2 + 3 1275 RefPtr<PullIntoDescriptor> descriptor = 1276 aController->PendingPullIntos().popFirst(); 1277 1278 // Step 4. 1279 return descriptor.forget(); 1280 } 1281 1282 JSObject* ConstructFromPullIntoConstructor( 1283 JSContext* aCx, PullIntoDescriptor::Constructor constructor, 1284 JS::Handle<JSObject*> buffer, size_t byteOffset, size_t length) { 1285 switch (constructor) { 1286 case PullIntoDescriptor::Constructor::DataView: 1287 return JS_NewDataView(aCx, buffer, byteOffset, length); 1288 break; 1289 1290 #define CONSTRUCT_TYPED_ARRAY_TYPE(ExternalT, NativeT, Name) \ 1291 case PullIntoDescriptor::Constructor::Name: \ 1292 return JS_New##Name##ArrayWithBuffer(aCx, buffer, byteOffset, \ 1293 int64_t(length)); \ 1294 break; 1295 1296 JS_FOR_EACH_TYPED_ARRAY(CONSTRUCT_TYPED_ARRAY_TYPE) 1297 1298 #undef CONSTRUCT_TYPED_ARRAY_TYPE 1299 1300 default: 1301 MOZ_ASSERT_UNREACHABLE("Unknown PullIntoDescriptor::Constructor"); 1302 return nullptr; 1303 } 1304 } 1305 1306 // https://streams.spec.whatwg.org/#readable-byte-stream-controller-convert-pull-into-descriptor 1307 JSObject* ReadableByteStreamControllerConvertPullIntoDescriptor( 1308 JSContext* aCx, PullIntoDescriptor* pullIntoDescriptor, ErrorResult& aRv) { 1309 // Step 1. Let bytesFilled be pullIntoDescriptor’s bytes filled. 1310 uint64_t bytesFilled = pullIntoDescriptor->BytesFilled(); 1311 1312 // Step 2. Let elementSize be pullIntoDescriptor’s element size. 1313 uint64_t elementSize = pullIntoDescriptor->ElementSize(); 1314 1315 // Step 3. Assert: bytesFilled ≤ pullIntoDescriptor’s byte length. 1316 MOZ_ASSERT(bytesFilled <= pullIntoDescriptor->ByteLength()); 1317 1318 // Step 4. Assert: the remainder after dividing bytesFilled by elementSize is 1319 // 0. 1320 MOZ_ASSERT(bytesFilled % elementSize == 0); 1321 1322 // Step 5. Let buffer be ! TransferArrayBuffer(pullIntoDescriptor’s buffer). 1323 aRv.MightThrowJSException(); 1324 JS::Rooted<JSObject*> srcBuffer(aCx, pullIntoDescriptor->Buffer()); 1325 JS::Rooted<JSObject*> buffer(aCx, TransferArrayBuffer(aCx, srcBuffer)); 1326 if (!buffer) { 1327 aRv.StealExceptionFromJSContext(aCx); 1328 return nullptr; 1329 } 1330 1331 // Step 6. Return ! Construct(pullIntoDescriptor’s view constructor, 1332 // « buffer, pullIntoDescriptor’s byte offset, bytesFilled ÷ elementSize »). 1333 JS::Rooted<JSObject*> res( 1334 aCx, ConstructFromPullIntoConstructor( 1335 aCx, pullIntoDescriptor->ViewConstructor(), buffer, 1336 pullIntoDescriptor->ByteOffset(), bytesFilled / elementSize)); 1337 if (!res) { 1338 aRv.StealExceptionFromJSContext(aCx); 1339 return nullptr; 1340 } 1341 return res; 1342 } 1343 1344 // https://streams.spec.whatwg.org/#readable-byte-stream-controller-respond-in-closed-state 1345 MOZ_CAN_RUN_SCRIPT 1346 static void ReadableByteStreamControllerRespondInClosedState( 1347 JSContext* aCx, ReadableByteStreamController* aController, 1348 RefPtr<PullIntoDescriptor>& aFirstDescriptor, ErrorResult& aRv) { 1349 // Step 1. Assert: the remainder after dividing firstDescriptor’s bytes filled 1350 // by firstDescriptor’s element size is 0. 1351 MOZ_ASSERT( 1352 (aFirstDescriptor->BytesFilled() % aFirstDescriptor->ElementSize()) == 0); 1353 1354 // Step 2. If firstDescriptor’s reader type is "none", 1355 // perform ! ReadableByteStreamControllerShiftPendingPullInto(controller). 1356 if (aFirstDescriptor->GetReaderType() == ReaderType::None) { 1357 RefPtr<PullIntoDescriptor> discarded = 1358 ReadableByteStreamControllerShiftPendingPullInto(aController); 1359 (void)discarded; 1360 } 1361 1362 // Step 3. Let stream be controller.[[stream]]. 1363 RefPtr<ReadableStream> stream = aController->Stream(); 1364 1365 // Step 4. If ! ReadableStreamHasBYOBReader(stream) is true, 1366 if (ReadableStreamHasBYOBReader(stream)) { 1367 // Step 4.1. Let filledPullIntos be a new empty list. 1368 nsTArray<RefPtr<PullIntoDescriptor>> filledPullIntos; 1369 1370 // Step 4.2. While |filledPullInto|'s [=list/size=] < ! 1371 // ReadableStreamGetNumReadIntoRequests(stream), 1372 while (filledPullIntos.Length() < 1373 ReadableStreamGetNumReadIntoRequests(stream)) { 1374 // Step 4.2.1. Let pullIntoDescriptor be ! 1375 // ReadableByteStreamControllerShiftPendingPullInto(controller). 1376 RefPtr<PullIntoDescriptor> pullIntoDescriptor = 1377 ReadableByteStreamControllerShiftPendingPullInto(aController); 1378 1379 // Step 4.2.2. Append pullIntoDescriptor to filledPullIntos. 1380 filledPullIntos.AppendElement(pullIntoDescriptor); 1381 } 1382 1383 // Step 4.3. For each filledPullInto of filledPullIntos, 1384 for (auto& filledPullInto : filledPullIntos) { 1385 // Step 4.3.1. Perform ! 1386 // ReadableByteStreamControllerCommitPullIntoDescriptor(stream, 1387 // filledPullInto). 1388 ReadableByteStreamControllerCommitPullIntoDescriptor( 1389 aCx, stream, MOZ_KnownLive(filledPullInto), aRv); 1390 if (aRv.Failed()) { 1391 return; 1392 } 1393 } 1394 } 1395 } 1396 1397 // https://streams.spec.whatwg.org/#readable-byte-stream-controller-fill-head-pull-into-descriptor 1398 void ReadableByteStreamControllerFillHeadPullIntoDescriptor( 1399 ReadableByteStreamController* aController, size_t aSize, 1400 PullIntoDescriptor* aPullIntoDescriptor) { 1401 // Step 1. Assert: either controller.[[pendingPullIntos]] is empty, or 1402 // controller.[[pendingPullIntos]][0] is pullIntoDescriptor. 1403 MOZ_ASSERT(aController->PendingPullIntos().isEmpty() || 1404 aController->PendingPullIntos().getFirst() == aPullIntoDescriptor); 1405 1406 // Step 2. Assert: controller.[[byobRequest]] is null. 1407 MOZ_ASSERT(!aController->GetByobRequest()); 1408 1409 // Step 3. Set pullIntoDescriptor’s bytes filled to bytes filled + size. 1410 aPullIntoDescriptor->SetBytesFilled(aPullIntoDescriptor->BytesFilled() + 1411 aSize); 1412 } 1413 1414 // https://streams.spec.whatwg.org/#readable-byte-stream-controller-respond-in-readable-state 1415 MOZ_CAN_RUN_SCRIPT 1416 static void ReadableByteStreamControllerRespondInReadableState( 1417 JSContext* aCx, ReadableByteStreamController* aController, 1418 uint64_t aBytesWritten, PullIntoDescriptor* aPullIntoDescriptor, 1419 ErrorResult& aRv) { 1420 // Step 1. Assert: pullIntoDescriptor’s bytes filled + bytesWritten ≤ 1421 // pullIntoDescriptor’s byte length. 1422 MOZ_ASSERT(aPullIntoDescriptor->BytesFilled() + aBytesWritten <= 1423 aPullIntoDescriptor->ByteLength()); 1424 1425 // Step 2. Perform 1426 // !ReadableByteStreamControllerFillHeadPullIntoDescriptor(controller, 1427 // bytesWritten, pullIntoDescriptor). 1428 ReadableByteStreamControllerFillHeadPullIntoDescriptor( 1429 aController, aBytesWritten, aPullIntoDescriptor); 1430 1431 // Step 3. If pullIntoDescriptor’s reader type is "none", 1432 if (aPullIntoDescriptor->GetReaderType() == ReaderType::None) { 1433 // Step 3.1. Perform ? 1434 // ReadableByteStreamControllerEnqueueDetachedPullIntoToQueue(controller, 1435 // pullIntoDescriptor). 1436 ReadableByteStreamControllerEnqueueDetachedPullIntoToQueue( 1437 aCx, aController, aPullIntoDescriptor, aRv); 1438 if (aRv.Failed()) { 1439 return; 1440 } 1441 1442 // Step 3.2. Let filledPullIntos be the result of performing ! 1443 // ReadableByteStreamControllerProcessPullIntoDescriptorsUsingQueue(controller). 1444 nsTArray<RefPtr<PullIntoDescriptor>> filledPullIntos; 1445 ReadableByteStreamControllerProcessPullIntoDescriptorsUsingQueue( 1446 aCx, aController, filledPullIntos, aRv); 1447 if (aRv.Failed()) { 1448 return; 1449 } 1450 1451 // Step 3.3. For each filledPullInto of filledPullIntos, 1452 for (auto& filledPullInto : filledPullIntos) { 1453 // Step 3.3.1. Perform ! 1454 // ReadableByteStreamControllerCommitPullIntoDescriptor(controller.[[stream]], 1455 // filledPullInto). 1456 ReadableByteStreamControllerCommitPullIntoDescriptor( 1457 aCx, MOZ_KnownLive(aController->Stream()), 1458 MOZ_KnownLive(filledPullInto), aRv); 1459 if (aRv.Failed()) { 1460 return; 1461 } 1462 } 1463 1464 // Step 3.4. Return. 1465 return; 1466 } 1467 1468 // Step 4. If pullIntoDescriptor’s bytes filled < pullIntoDescriptor’s minimum 1469 // fill, return. 1470 if (aPullIntoDescriptor->BytesFilled() < aPullIntoDescriptor->MinimumFill()) { 1471 return; 1472 } 1473 1474 // Step 5. Perform 1475 // !ReadableByteStreamControllerShiftPendingPullInto(controller). 1476 RefPtr<PullIntoDescriptor> pullIntoDescriptor = 1477 ReadableByteStreamControllerShiftPendingPullInto(aController); 1478 (void)pullIntoDescriptor; 1479 1480 // Step 6. Let remainderSize be the remainder after dividing 1481 // pullIntoDescriptor’s bytes filled by pullIntoDescriptor’s element size. 1482 size_t remainderSize = 1483 aPullIntoDescriptor->BytesFilled() % aPullIntoDescriptor->ElementSize(); 1484 1485 // Step 7. If remainderSize > 0, 1486 if (remainderSize > 0) { 1487 // Step 7.1. Let end be pullIntoDescriptor’s byte offset + 1488 // pullIntoDescriptor’s bytes filled. 1489 size_t end = 1490 aPullIntoDescriptor->ByteOffset() + aPullIntoDescriptor->BytesFilled(); 1491 1492 // Step 7.2. Perform ? 1493 // ReadableByteStreamControllerEnqueueClonedChunkToQueue(controller, 1494 // pullIntoDescriptor’s buffer, end − remainderSize, remainderSize). 1495 JS::Rooted<JSObject*> pullIntoBuffer(aCx, aPullIntoDescriptor->Buffer()); 1496 ReadableByteStreamControllerEnqueueClonedChunkToQueue( 1497 aCx, aController, pullIntoBuffer, end - remainderSize, remainderSize, 1498 aRv); 1499 if (aRv.Failed()) { 1500 return; 1501 } 1502 } 1503 1504 // Step 8. Set pullIntoDescriptor’s bytes filled to pullIntoDescriptor’s bytes 1505 // filled − remainderSize. 1506 aPullIntoDescriptor->SetBytesFilled(aPullIntoDescriptor->BytesFilled() - 1507 remainderSize); 1508 1509 // Step 9. Let filledPullIntos be the result of performing ! 1510 // ReadableByteStreamControllerProcessPullIntoDescriptorsUsingQueue(controller). 1511 nsTArray<RefPtr<PullIntoDescriptor>> filledPullIntos; 1512 ReadableByteStreamControllerProcessPullIntoDescriptorsUsingQueue( 1513 aCx, aController, filledPullIntos, aRv); 1514 if (aRv.Failed()) { 1515 return; 1516 } 1517 1518 // Step 10. Perform 1519 // !ReadableByteStreamControllerCommitPullIntoDescriptor(controller.[[stream]], 1520 // pullIntoDescriptor). 1521 RefPtr<ReadableStream> stream(aController->Stream()); 1522 ReadableByteStreamControllerCommitPullIntoDescriptor( 1523 aCx, stream, aPullIntoDescriptor, aRv); 1524 if (aRv.Failed()) { 1525 return; 1526 } 1527 1528 // Step 11. For each filledPullInto of filledPullIntos, 1529 for (auto& filledPullInto : filledPullIntos) { 1530 // Step 11.1. Perform ! 1531 // ReadableByteStreamControllerCommitPullIntoDescriptor(controller.[[stream]], 1532 // filledPullInto). 1533 ReadableByteStreamControllerCommitPullIntoDescriptor( 1534 aCx, stream, MOZ_KnownLive(filledPullInto), aRv); 1535 if (aRv.Failed()) { 1536 return; 1537 } 1538 } 1539 } 1540 1541 // https://streams.spec.whatwg.org/#readable-byte-stream-controller-respond-internal 1542 void ReadableByteStreamControllerRespondInternal( 1543 JSContext* aCx, ReadableByteStreamController* aController, 1544 uint64_t aBytesWritten, ErrorResult& aRv) { 1545 // Step 1. 1546 RefPtr<PullIntoDescriptor> firstDescriptor = 1547 aController->PendingPullIntos().getFirst(); 1548 1549 // Step 2. 1550 JS::Rooted<JSObject*> buffer(aCx, firstDescriptor->Buffer()); 1551 #ifdef DEBUG 1552 bool canTransferBuffer = CanTransferArrayBuffer(aCx, buffer, aRv); 1553 MOZ_ASSERT(!aRv.Failed()); 1554 MOZ_ASSERT(canTransferBuffer); 1555 #endif 1556 1557 // Step 3. 1558 ReadableByteStreamControllerInvalidateBYOBRequest(aController); 1559 1560 // Step 4. 1561 auto state = aController->Stream()->State(); 1562 1563 // Step 5. 1564 if (state == ReadableStream::ReaderState::Closed) { 1565 // Step 5.1 1566 MOZ_ASSERT(aBytesWritten == 0); 1567 1568 // Step 5.2 1569 ReadableByteStreamControllerRespondInClosedState(aCx, aController, 1570 firstDescriptor, aRv); 1571 if (aRv.Failed()) { 1572 return; 1573 } 1574 } else { 1575 // Step 6.1 1576 MOZ_ASSERT(state == ReadableStream::ReaderState::Readable); 1577 1578 // Step 6.2. 1579 MOZ_ASSERT(aBytesWritten > 0); 1580 1581 // Step 6.3 1582 ReadableByteStreamControllerRespondInReadableState( 1583 aCx, aController, aBytesWritten, firstDescriptor, aRv); 1584 if (aRv.Failed()) { 1585 return; 1586 } 1587 } 1588 // Step 7. 1589 ReadableByteStreamControllerCallPullIfNeeded(aCx, aController, aRv); 1590 } 1591 1592 // https://streams.spec.whatwg.org/#readable-byte-stream-controller-respond 1593 void ReadableByteStreamControllerRespond( 1594 JSContext* aCx, ReadableByteStreamController* aController, 1595 uint64_t aBytesWritten, ErrorResult& aRv) { 1596 // Step 1. 1597 MOZ_ASSERT(!aController->PendingPullIntos().isEmpty()); 1598 1599 // Step 2. 1600 PullIntoDescriptor* firstDescriptor = 1601 aController->PendingPullIntos().getFirst(); 1602 1603 // Step 3. 1604 auto state = aController->Stream()->State(); 1605 1606 // Step 4. 1607 if (state == ReadableStream::ReaderState::Closed) { 1608 // Step 4.1 1609 if (aBytesWritten != 0) { 1610 aRv.ThrowTypeError("bytesWritten not zero on closed stream"); 1611 return; 1612 } 1613 } else { 1614 // Step 5.1 1615 MOZ_ASSERT(state == ReadableStream::ReaderState::Readable); 1616 1617 // Step 5.2 1618 if (aBytesWritten == 0) { 1619 aRv.ThrowTypeError("bytesWritten 0"); 1620 return; 1621 } 1622 1623 // Step 5.3 1624 if (firstDescriptor->BytesFilled() + aBytesWritten > 1625 firstDescriptor->ByteLength()) { 1626 aRv.ThrowRangeError("bytesFilled + bytesWritten > byteLength"); 1627 return; 1628 } 1629 } 1630 1631 // Step 6. 1632 aRv.MightThrowJSException(); 1633 JS::Rooted<JSObject*> buffer(aCx, firstDescriptor->Buffer()); 1634 JS::Rooted<JSObject*> transferredBuffer(aCx, 1635 TransferArrayBuffer(aCx, buffer)); 1636 if (!transferredBuffer) { 1637 aRv.StealExceptionFromJSContext(aCx); 1638 return; 1639 } 1640 firstDescriptor->SetBuffer(transferredBuffer); 1641 1642 // Step 7. 1643 ReadableByteStreamControllerRespondInternal(aCx, aController, aBytesWritten, 1644 aRv); 1645 } 1646 1647 // https://streams.spec.whatwg.org/#readable-byte-stream-controller-respond-with-new-view 1648 void ReadableByteStreamControllerRespondWithNewView( 1649 JSContext* aCx, ReadableByteStreamController* aController, 1650 JS::Handle<JSObject*> aView, ErrorResult& aRv) { 1651 aRv.MightThrowJSException(); 1652 1653 // Step 1. 1654 MOZ_ASSERT(!aController->PendingPullIntos().isEmpty()); 1655 1656 // Step 2. 1657 bool isSharedMemory; 1658 JS::Rooted<JSObject*> viewedArrayBuffer( 1659 aCx, JS_GetArrayBufferViewBuffer(aCx, aView, &isSharedMemory)); 1660 if (!viewedArrayBuffer) { 1661 aRv.StealExceptionFromJSContext(aCx); 1662 return; 1663 } 1664 MOZ_ASSERT(!JS::IsDetachedArrayBufferObject(viewedArrayBuffer)); 1665 1666 // Step 3. 1667 RefPtr<PullIntoDescriptor> firstDescriptor = 1668 aController->PendingPullIntos().getFirst(); 1669 1670 // Step 4. 1671 ReadableStream::ReaderState state = aController->Stream()->State(); 1672 1673 // Step 5. 1674 if (state == ReadableStream::ReaderState::Closed) { 1675 // Step 5.1 1676 if (JS_GetArrayBufferViewByteLength(aView) != 0) { 1677 aRv.ThrowTypeError("View has non-zero length in closed stream"); 1678 return; 1679 } 1680 } else { 1681 // Step 6.1 1682 MOZ_ASSERT(state == ReadableStream::ReaderState::Readable); 1683 1684 // Step 6.2 1685 if (JS_GetArrayBufferViewByteLength(aView) == 0) { 1686 aRv.ThrowTypeError("View has zero length in readable stream"); 1687 return; 1688 } 1689 } 1690 1691 // Step 7. 1692 if (firstDescriptor->ByteOffset() + firstDescriptor->BytesFilled() != 1693 JS_GetArrayBufferViewByteOffset(aView)) { 1694 aRv.ThrowRangeError("Invalid Offset"); 1695 return; 1696 } 1697 1698 // Step 8. 1699 if (firstDescriptor->BufferByteLength() != 1700 JS::GetArrayBufferByteLength(viewedArrayBuffer)) { 1701 aRv.ThrowRangeError("Mismatched buffer byte lengths"); 1702 return; 1703 } 1704 1705 // Step 9. 1706 if (firstDescriptor->BytesFilled() + JS_GetArrayBufferViewByteLength(aView) > 1707 firstDescriptor->ByteLength()) { 1708 aRv.ThrowRangeError("Too many bytes"); 1709 return; 1710 } 1711 1712 // Step 10. Let viewByteLength be view.[[ByteLength]]. 1713 size_t viewByteLength = JS_GetArrayBufferViewByteLength(aView); 1714 1715 // Step 11. Set firstDescriptor’s buffer to ? 1716 // TransferArrayBuffer(view.[[ViewedArrayBuffer]]). 1717 JS::Rooted<JSObject*> transferedBuffer( 1718 aCx, TransferArrayBuffer(aCx, viewedArrayBuffer)); 1719 if (!transferedBuffer) { 1720 aRv.StealExceptionFromJSContext(aCx); 1721 return; 1722 } 1723 firstDescriptor->SetBuffer(transferedBuffer); 1724 1725 // Step 12. Perform ? ReadableByteStreamControllerRespondInternal(controller, 1726 // viewByteLength). 1727 ReadableByteStreamControllerRespondInternal(aCx, aController, viewByteLength, 1728 aRv); 1729 } 1730 1731 #ifdef DEBUG 1732 // https://streams.spec.whatwg.org/#abstract-opdef-cancopydatablockbytes 1733 bool CanCopyDataBlockBytes(JS::Handle<JSObject*> aToBuffer, size_t aToIndex, 1734 JS::Handle<JSObject*> aFromBuffer, size_t aFromIndex, 1735 size_t aCount) { 1736 // Step 1. Assert: toBuffer is an Object. 1737 // Step 2. Assert: toBuffer has an [[ArrayBufferData]] internal slot. 1738 MOZ_ASSERT(JS::IsArrayBufferObject(aToBuffer)); 1739 1740 // Step 3. Assert: fromBuffer is an Object. 1741 // Step 4. Assert: fromBuffer has an [[ArrayBufferData]] internal slot. 1742 MOZ_ASSERT(JS::IsArrayBufferObject(aFromBuffer)); 1743 1744 // Step 5. If toBuffer is fromBuffer, return false. 1745 // Note: JS API makes it safe to just compare the pointers. 1746 if (aToBuffer == aFromBuffer) { 1747 return false; 1748 } 1749 1750 // Step 6. If ! IsDetachedBuffer(toBuffer) is true, return false. 1751 if (JS::IsDetachedArrayBufferObject(aToBuffer)) { 1752 return false; 1753 } 1754 1755 // Step 7. If ! IsDetachedBuffer(fromBuffer) is true, return false. 1756 if (JS::IsDetachedArrayBufferObject(aFromBuffer)) { 1757 return false; 1758 } 1759 1760 // Step 8. If toIndex + count > toBuffer.[[ArrayBufferByteLength]], return 1761 // false. 1762 if (aToIndex + aCount > JS::GetArrayBufferByteLength(aToBuffer)) { 1763 return false; 1764 } 1765 // (Not in the spec) also check overflow. 1766 if (aToIndex + aCount < aToIndex) { 1767 return false; 1768 } 1769 1770 // Step 9. If fromIndex + count > fromBuffer.[[ArrayBufferByteLength]], return 1771 // false. 1772 if (aFromIndex + aCount > JS::GetArrayBufferByteLength(aFromBuffer)) { 1773 return false; 1774 } 1775 // (Not in the spec) also check overflow. 1776 if (aFromIndex + aCount < aFromIndex) { 1777 return false; 1778 } 1779 1780 // Step 10. Return true. 1781 return true; 1782 } 1783 #endif 1784 1785 // https://streams.spec.whatwg.org/#readable-byte-stream-controller-fill-pull-into-descriptor-from-queue 1786 bool ReadableByteStreamControllerFillPullIntoDescriptorFromQueue( 1787 JSContext* aCx, ReadableByteStreamController* aController, 1788 PullIntoDescriptor* aPullIntoDescriptor, ErrorResult& aRv) { 1789 // Step 1. Let maxBytesToCopy be min(controller.[[queueTotalSize]], 1790 // pullIntoDescriptor’s byte length − pullIntoDescriptor’s bytes filled). 1791 size_t maxBytesToCopy = 1792 std::min(static_cast<size_t>(aController->QueueTotalSize()), 1793 static_cast<size_t>((aPullIntoDescriptor->ByteLength() - 1794 aPullIntoDescriptor->BytesFilled()))); 1795 1796 // Step 2. Let maxBytesFilled be pullIntoDescriptor’s bytes filled + 1797 // maxBytesToCopy. 1798 size_t maxBytesFilled = aPullIntoDescriptor->BytesFilled() + maxBytesToCopy; 1799 1800 // Step 3. Let totalBytesToCopyRemaining be maxBytesToCopy. 1801 size_t totalBytesToCopyRemaining = maxBytesToCopy; 1802 1803 // Step 4. Let ready be false. 1804 bool ready = false; 1805 1806 // Step 5. Assert: ! IsDetachedBuffer(pullIntoDescriptor ’s buffer) is false. 1807 MOZ_ASSERT(!JS::IsDetachedArrayBufferObject(aPullIntoDescriptor->Buffer())); 1808 1809 // Step 6. Assert: pullIntoDescriptor’s bytes filled < pullIntoDescriptor’s 1810 // minimum fill. 1811 MOZ_ASSERT(aPullIntoDescriptor->BytesFilled() < 1812 aPullIntoDescriptor->MinimumFill()); 1813 1814 // Step 7. Let remainderBytes be the remainder after dividing maxBytesFilled 1815 // by pullIntoDescriptor’s element size. 1816 size_t remainderBytes = maxBytesFilled % aPullIntoDescriptor->ElementSize(); 1817 1818 // Step 8. Let maxAlignedBytes be maxBytesFilled − remainderBytes. 1819 size_t maxAlignedBytes = maxBytesFilled - remainderBytes; 1820 1821 // Step 9. If maxAlignedBytes ≥ pullIntoDescriptor’s minimum fill, 1822 if (maxAlignedBytes >= aPullIntoDescriptor->MinimumFill()) { 1823 // Step 9.1. Set totalBytesToCopyRemaining to maxAlignedBytes − 1824 // pullIntoDescriptor’s bytes filled. 1825 totalBytesToCopyRemaining = 1826 maxAlignedBytes - aPullIntoDescriptor->BytesFilled(); 1827 // Step 9.2. Set ready to true. 1828 ready = true; 1829 } 1830 1831 // Step 10. Let queue be controller.[[queue]]. 1832 LinkedList<RefPtr<ReadableByteStreamQueueEntry>>& queue = 1833 aController->Queue(); 1834 1835 // Step 11. While totalBytesToCopyRemaining > 0, 1836 while (totalBytesToCopyRemaining > 0) { 1837 // Step 11.1 Let headOfQueue be queue[0]. 1838 ReadableByteStreamQueueEntry* headOfQueue = queue.getFirst(); 1839 1840 // Step 11.2. Let bytesToCopy be min(totalBytesToCopyRemaining, 1841 // headOfQueue’s byte length). 1842 size_t bytesToCopy = 1843 std::min(totalBytesToCopyRemaining, headOfQueue->ByteLength()); 1844 1845 // Step 11.3. Let destStart be pullIntoDescriptor’s byte offset + 1846 // pullIntoDescriptor’s bytes filled. 1847 size_t destStart = 1848 aPullIntoDescriptor->ByteOffset() + aPullIntoDescriptor->BytesFilled(); 1849 1850 // Step 11.4. Let descriptorBuffer be pullIntoDescriptor’s buffer. 1851 JS::Rooted<JSObject*> descriptorBuffer(aCx, aPullIntoDescriptor->Buffer()); 1852 1853 // Step 11.5. Let queueBuffer be headOfQueue’s buffer. 1854 JS::Rooted<JSObject*> queueBuffer(aCx, headOfQueue->Buffer()); 1855 1856 // Step 11.6. Let queueByteOffset be headOfQueue’s byte offset. 1857 size_t queueByteOffset = headOfQueue->ByteOffset(); 1858 1859 // Step 11.7. Assert: ! CanCopyDataBlockBytes(descriptorBuffer, destStart, 1860 // queueBuffer, queueByteOffset, bytesToCopy) is true. 1861 MOZ_ASSERT(CanCopyDataBlockBytes(descriptorBuffer, destStart, queueBuffer, 1862 queueByteOffset, bytesToCopy)); 1863 1864 // Step 11.8. Perform ! 1865 // CopyDataBlockBytes(descriptorBuffer.[[ArrayBufferData]], destStart, 1866 // queueBuffer.[[ArrayBufferData]], queueByteOffset, bytesToCopy). 1867 if (!JS::ArrayBufferCopyData(aCx, descriptorBuffer, destStart, queueBuffer, 1868 queueByteOffset, bytesToCopy)) { 1869 aRv.StealExceptionFromJSContext(aCx); 1870 return false; 1871 } 1872 1873 // Step 11.9. If headOfQueue’s byte length is bytesToCopy, 1874 if (headOfQueue->ByteLength() == bytesToCopy) { 1875 // Step 11.9.1. Remove queue[0]. 1876 queue.popFirst(); 1877 } else { 1878 // Step 11.10. Otherwise, 1879 1880 // Step 11.10.1 Set headOfQueue’s byte offset to 1881 // headOfQueue’s byte offset + bytesToCopy. 1882 headOfQueue->SetByteOffset(headOfQueue->ByteOffset() + bytesToCopy); 1883 // Step 11.10.2 Set headOfQueue’s byte length to 1884 // headOfQueue’s byte length − bytesToCopy. 1885 headOfQueue->SetByteLength(headOfQueue->ByteLength() - bytesToCopy); 1886 } 1887 1888 // Step 11.11. Set controller.[[queueTotalSize]] to 1889 // controller.[[queueTotalSize]] − bytesToCopy. 1890 aController->SetQueueTotalSize(aController->QueueTotalSize() - 1891 (double)bytesToCopy); 1892 1893 // Step 11.12, Perform 1894 // !ReadableByteStreamControllerFillHeadPullIntoDescriptor(controller, 1895 // bytesToCopy, pullIntoDescriptor). 1896 ReadableByteStreamControllerFillHeadPullIntoDescriptor( 1897 aController, bytesToCopy, aPullIntoDescriptor); 1898 1899 // Step 11.13. Set totalBytesToCopyRemaining to totalBytesToCopyRemaining − 1900 // bytesToCopy. 1901 totalBytesToCopyRemaining = totalBytesToCopyRemaining - bytesToCopy; 1902 } 1903 1904 // Step 12. If ready is false, 1905 if (!ready) { 1906 // Step 12.1. Assert: controller.[[queueTotalSize]] is 0. 1907 MOZ_ASSERT(aController->QueueTotalSize() == 0); 1908 1909 // Step 12.2. Assert: pullIntoDescriptor’s bytes filled > 0. 1910 MOZ_ASSERT(aPullIntoDescriptor->BytesFilled() > 0); 1911 1912 // Step 12.3. Assert: pullIntoDescriptor’s bytes filled < 1913 // pullIntoDescriptor’s minimum fill. 1914 MOZ_ASSERT(aPullIntoDescriptor->BytesFilled() < 1915 aPullIntoDescriptor->MinimumFill()); 1916 } 1917 1918 // Step 13. Return ready. 1919 return ready; 1920 } 1921 1922 // https://streams.spec.whatwg.org/#readable-byte-stream-controller-pull-into 1923 void ReadableByteStreamControllerPullInto( 1924 JSContext* aCx, ReadableByteStreamController* aController, 1925 JS::Handle<JSObject*> aView, uint64_t aMin, 1926 ReadIntoRequest* aReadIntoRequest, ErrorResult& aRv) { 1927 aRv.MightThrowJSException(); 1928 1929 // Step 1. Let stream be controller.[[stream]]. 1930 ReadableStream* stream = aController->Stream(); 1931 1932 // Step 2. Let elementSize be 1. 1933 size_t elementSize = 1; 1934 1935 // Step 3. Let ctor be %DataView%. 1936 PullIntoDescriptor::Constructor ctor = 1937 PullIntoDescriptor::Constructor::DataView; 1938 1939 // Step 4. If view has a [[TypedArrayName]] internal slot (i.e., it is not a 1940 // DataView), 1941 if (JS_IsTypedArrayObject(aView)) { 1942 // Step 4.1. Set elementSize to the element size specified in the typed 1943 // array constructors table for view.[[TypedArrayName]]. 1944 JS::Scalar::Type type = JS_GetArrayBufferViewType(aView); 1945 elementSize = JS::Scalar::byteSize(type); 1946 1947 // Step 4.2 Set ctor to the constructor specified in the typed array 1948 // constructors table for view.[[TypedArrayName]]. 1949 ctor = PullIntoDescriptor::constructorFromScalar(type); 1950 } 1951 1952 // Step 5. Let minimumFill be min × elementSize. 1953 uint64_t minimumFill = aMin * elementSize; 1954 1955 // Step 6. Assert: minimumFill ≥ 0 and minimumFill ≤ view.[[ByteLength]]. 1956 MOZ_ASSERT(minimumFill <= JS_GetArrayBufferViewByteLength(aView)); 1957 1958 // Step 7. Assert: the remainder after dividing minimumFill by elementSize is 1959 // 0. 1960 MOZ_ASSERT((minimumFill % elementSize) == 0); 1961 1962 // Step 8. Let byteOffset be view.[[ByteOffset]]. 1963 size_t byteOffset = JS_GetArrayBufferViewByteOffset(aView); 1964 1965 // Step 9. Let byteLength be view.[[ByteLength]]. 1966 size_t byteLength = JS_GetArrayBufferViewByteLength(aView); 1967 1968 // Step 10. Let bufferResult be 1969 // TransferArrayBuffer(view.[[ViewedArrayBuffer]]). 1970 bool isShared; 1971 JS::Rooted<JSObject*> viewedArrayBuffer( 1972 aCx, JS_GetArrayBufferViewBuffer(aCx, aView, &isShared)); 1973 if (!viewedArrayBuffer) { 1974 aRv.StealExceptionFromJSContext(aCx); 1975 return; 1976 } 1977 JS::Rooted<JSObject*> bufferResult( 1978 aCx, TransferArrayBuffer(aCx, viewedArrayBuffer)); 1979 1980 // Step 11. If bufferResult is an abrupt completion, 1981 if (!bufferResult) { 1982 JS::Rooted<JS::Value> pendingException(aCx); 1983 if (!JS_GetPendingException(aCx, &pendingException)) { 1984 // This means an un-catchable exception. Use StealExceptionFromJSContext 1985 // to setup aRv properly. 1986 aRv.StealExceptionFromJSContext(aCx); 1987 return; 1988 } 1989 1990 // It's not expliclitly stated, but I assume the intention here is that 1991 // we perform a normal completion here; we also need to clear the 1992 // exception state anyhow to succesfully run ErrorSteps. 1993 JS_ClearPendingException(aCx); 1994 1995 // Step 11.1. Perform readIntoRequest’s error steps, given 1996 // bufferResult.[[Value]]. 1997 aReadIntoRequest->ErrorSteps(aCx, pendingException, aRv); 1998 1999 // Step 11.2. Return. 2000 return; 2001 } 2002 2003 // Step 12. Let buffer be bufferResult.[[Value]]. 2004 JS::Rooted<JSObject*> buffer(aCx, bufferResult); 2005 2006 // Step 13. Let pullIntoDescriptor be a new pull-into descriptor with 2007 // buffer: buffer 2008 // buffer byte length: buffer.[[ArrayBufferByteLength]] 2009 // byte offset: byteOffset 2010 // byte length: byteLength 2011 // bytes filled: 0 2012 // minimum fill: minimumFill 2013 // element size: elementSize 2014 // view constructor: ctor 2015 // reader type: "byob" 2016 RefPtr<PullIntoDescriptor> pullIntoDescriptor = new PullIntoDescriptor( 2017 buffer, JS::GetArrayBufferByteLength(buffer), byteOffset, byteLength, 0, 2018 minimumFill, elementSize, ctor, ReaderType::BYOB); 2019 2020 // Step 14. If controller.[[pendingPullIntos]] is not empty, 2021 if (!aController->PendingPullIntos().isEmpty()) { 2022 // Step 14.1. Append pullIntoDescriptor to controller.[[pendingPullIntos]]. 2023 aController->PendingPullIntos().insertBack(pullIntoDescriptor); 2024 2025 // Step 14.2. Perform !ReadableStreamAddReadIntoRequest(stream, 2026 // readIntoRequest). 2027 ReadableStreamAddReadIntoRequest(stream, aReadIntoRequest); 2028 2029 // Step 14.3. Return. 2030 return; 2031 } 2032 2033 // Step 15. If stream.[[state]] is "closed", 2034 if (stream->State() == ReadableStream::ReaderState::Closed) { 2035 // Step 15.1. Let emptyView be !Construct(ctor, « pullIntoDescriptor’s 2036 // buffer, pullIntoDescriptor’s byte offset, 0 »). 2037 JS::Rooted<JSObject*> pullIntoBuffer(aCx, pullIntoDescriptor->Buffer()); 2038 JS::Rooted<JSObject*> emptyView( 2039 aCx, 2040 ConstructFromPullIntoConstructor(aCx, ctor, pullIntoBuffer, 2041 pullIntoDescriptor->ByteOffset(), 0)); 2042 if (!emptyView) { 2043 aRv.StealExceptionFromJSContext(aCx); 2044 return; 2045 } 2046 2047 // Step 15.2. Perform readIntoRequest’s close steps, given emptyView. 2048 JS::Rooted<JS::Value> emptyViewValue(aCx, JS::ObjectValue(*emptyView)); 2049 aReadIntoRequest->CloseSteps(aCx, emptyViewValue, aRv); 2050 2051 // Step 15.3. Return. 2052 return; 2053 } 2054 2055 // Step 16. If controller.[[queueTotalSize]] > 0, 2056 if (aController->QueueTotalSize() > 0) { 2057 // Step 16.1 If 2058 // !ReadableByteStreamControllerFillPullIntoDescriptorFromQueue(controller, 2059 // pullIntoDescriptor) is true, 2060 bool ready = ReadableByteStreamControllerFillPullIntoDescriptorFromQueue( 2061 aCx, aController, pullIntoDescriptor, aRv); 2062 if (aRv.Failed()) { 2063 return; 2064 } 2065 if (ready) { 2066 // Step 16.1.1 Let filledView be 2067 // !ReadableByteStreamControllerConvertPullIntoDescriptor(pullIntoDescriptor). 2068 JS::Rooted<JSObject*> filledView( 2069 aCx, ReadableByteStreamControllerConvertPullIntoDescriptor( 2070 aCx, pullIntoDescriptor, aRv)); 2071 if (aRv.Failed()) { 2072 return; 2073 } 2074 // Step 16.1.2. Perform 2075 // !ReadableByteStreamControllerHandleQueueDrain(controller). 2076 ReadableByteStreamControllerHandleQueueDrain(aCx, aController, aRv); 2077 if (aRv.Failed()) { 2078 return; 2079 } 2080 // Step 16.1.3. Perform readIntoRequest’s chunk steps, given filledView. 2081 JS::Rooted<JS::Value> filledViewValue(aCx, JS::ObjectValue(*filledView)); 2082 aReadIntoRequest->ChunkSteps(aCx, filledViewValue, aRv); 2083 // Step 16.1.4. Return. 2084 return; 2085 } 2086 2087 // Step 16.2 If controller.[[closeRequested]] is true, 2088 if (aController->CloseRequested()) { 2089 // Step 16.2.1. Let e be a TypeError exception. 2090 ErrorResult typeError; 2091 typeError.ThrowTypeError("Close Requested True during Pull Into"); 2092 2093 JS::Rooted<JS::Value> e(aCx); 2094 MOZ_RELEASE_ASSERT(ToJSValue(aCx, std::move(typeError), &e)); 2095 2096 // Step 16.2.2. Perform !ReadableByteStreamControllerError(controller, e). 2097 ReadableByteStreamControllerError(aController, e, aRv); 2098 if (aRv.Failed()) { 2099 return; 2100 } 2101 2102 // Step 16.2.3. Perform readIntoRequest’s error steps, given e. 2103 aReadIntoRequest->ErrorSteps(aCx, e, aRv); 2104 2105 // Step 16.2.4. Return. 2106 return; 2107 } 2108 } 2109 2110 // Step 17. Append pullIntoDescriptor to controller.[[pendingPullIntos]]. 2111 aController->PendingPullIntos().insertBack(pullIntoDescriptor); 2112 2113 // Step 18. Perform !ReadableStreamAddReadIntoRequest(stream, 2114 // readIntoRequest). 2115 ReadableStreamAddReadIntoRequest(stream, aReadIntoRequest); 2116 2117 // Step 19. Perform !ReadableByteStreamControllerCallPullIfNeeded(controller). 2118 ReadableByteStreamControllerCallPullIfNeeded(aCx, aController, aRv); 2119 } 2120 2121 // https://streams.spec.whatwg.org/#set-up-readable-byte-stream-controller 2122 void SetUpReadableByteStreamController( 2123 JSContext* aCx, ReadableStream* aStream, 2124 ReadableByteStreamController* aController, 2125 UnderlyingSourceAlgorithmsBase* aAlgorithms, double aHighWaterMark, 2126 Maybe<uint64_t> aAutoAllocateChunkSize, ErrorResult& aRv) { 2127 // Step 1. Assert: stream.[[controller]] is undefined. 2128 MOZ_ASSERT(!aStream->Controller()); 2129 2130 // Step 2. If autoAllocateChunkSize is not undefined, 2131 // Step 2.1. Assert: ! IsInteger(autoAllocateChunkSize) is true. Implicit 2132 // Step 2.2. Assert: autoAllocateChunkSize is positive. (Implicit by 2133 // type.) 2134 2135 // Step 3. Set controller.[[stream]] to stream. 2136 aController->SetStream(aStream); 2137 2138 // Step 4. Set controller.[[pullAgain]] and controller.[[pulling]] to false. 2139 aController->SetPullAgain(false); 2140 aController->SetPulling(false); 2141 2142 // Step 5. Set controller.[[byobRequest]] to null. 2143 aController->SetByobRequest(nullptr); 2144 2145 // Step 6. Perform !ResetQueue(controller). 2146 ResetQueue(aController); 2147 2148 // Step 7. Set controller.[[closeRequested]] and controller.[[started]] to 2149 // false. 2150 aController->SetCloseRequested(false); 2151 aController->SetStarted(false); 2152 2153 // Step 8. Set controller.[[strategyHWM]] to highWaterMark. 2154 aController->SetStrategyHWM(aHighWaterMark); 2155 2156 // Step 9. Set controller.[[pullAlgorithm]] to pullAlgorithm. 2157 // Step 10. Set controller.[[cancelAlgorithm]] to cancelAlgorithm. 2158 aController->SetAlgorithms(*aAlgorithms); 2159 2160 // Step 11. Set controller.[[autoAllocateChunkSize]] to autoAllocateChunkSize. 2161 aController->SetAutoAllocateChunkSize(aAutoAllocateChunkSize); 2162 2163 // Step 12. Set controller.[[pendingPullIntos]] to a new empty list. 2164 aController->PendingPullIntos().clear(); 2165 2166 // Step 13. Set stream.[[controller]] to controller. 2167 aStream->SetController(*aController); 2168 2169 // Step 14. Let startResult be the result of performing startAlgorithm. 2170 JS::Rooted<JS::Value> startResult(aCx, JS::UndefinedValue()); 2171 RefPtr<ReadableStreamControllerBase> controller = aController; 2172 aAlgorithms->StartCallback(aCx, *controller, &startResult, aRv); 2173 if (aRv.Failed()) { 2174 return; 2175 } 2176 2177 // Let startPromise be a promise resolved with startResult. 2178 RefPtr<Promise> startPromise = 2179 Promise::CreateInfallible(aStream->GetParentObject()); 2180 startPromise->MaybeResolve(startResult); 2181 2182 // Step 16+17 2183 startPromise->AddCallbacksWithCycleCollectedArgs( 2184 [](JSContext* aCx, JS::Handle<JS::Value> aValue, ErrorResult& aRv, 2185 ReadableByteStreamController* aController) 2186 MOZ_CAN_RUN_SCRIPT_BOUNDARY { 2187 MOZ_ASSERT(aController); 2188 2189 // Step 16.1 2190 aController->SetStarted(true); 2191 2192 // Step 16.2 2193 aController->SetPulling(false); 2194 2195 // Step 16.3 2196 aController->SetPullAgain(false); 2197 2198 // Step 16.4: 2199 ReadableByteStreamControllerCallPullIfNeeded( 2200 aCx, MOZ_KnownLive(aController), aRv); 2201 }, 2202 [](JSContext* aCx, JS::Handle<JS::Value> aValue, ErrorResult& aRv, 2203 ReadableByteStreamController* aController) { 2204 // Step 17.1 2205 ReadableByteStreamControllerError(aController, aValue, aRv); 2206 }, 2207 RefPtr(aController)); 2208 } 2209 2210 // https://streams.spec.whatwg.org/#set-up-readable-byte-stream-controller-from-underlying-source 2211 void SetUpReadableByteStreamControllerFromUnderlyingSource( 2212 JSContext* aCx, ReadableStream* aStream, 2213 JS::Handle<JSObject*> aUnderlyingSource, 2214 UnderlyingSource& aUnderlyingSourceDict, double aHighWaterMark, 2215 ErrorResult& aRv) { 2216 // Step 1. Let controller be a new ReadableByteStreamController. 2217 auto controller = 2218 MakeRefPtr<ReadableByteStreamController>(aStream->GetParentObject()); 2219 2220 // Step 2 - 7 2221 auto algorithms = MakeRefPtr<UnderlyingSourceAlgorithms>( 2222 aStream->GetParentObject(), aUnderlyingSource, aUnderlyingSourceDict); 2223 2224 // Step 8. Let autoAllocateChunkSize be 2225 // underlyingSourceDict["autoAllocateChunkSize"], if it exists, or undefined 2226 // otherwise. 2227 Maybe<uint64_t> autoAllocateChunkSize = mozilla::Nothing(); 2228 if (aUnderlyingSourceDict.mAutoAllocateChunkSize.WasPassed()) { 2229 uint64_t value = aUnderlyingSourceDict.mAutoAllocateChunkSize.Value(); 2230 // Step 9. If autoAllocateChunkSize is 0, then throw a TypeError 2231 // exception. 2232 if (value == 0) { 2233 aRv.ThrowTypeError("autoAllocateChunkSize can not be zero."); 2234 return; 2235 } 2236 2237 if constexpr (sizeof(size_t) == sizeof(uint32_t)) { 2238 if (value > uint64_t(UINT32_MAX)) { 2239 aRv.ThrowRangeError("autoAllocateChunkSize too large"); 2240 return; 2241 } 2242 } 2243 2244 autoAllocateChunkSize = mozilla::Some(value); 2245 } 2246 2247 // Step 10. Perform ? SetUpReadableByteStreamController(stream, controller, 2248 // startAlgorithm, pullAlgorithm, cancelAlgorithm, highWaterMark, 2249 // autoAllocateChunkSize). 2250 SetUpReadableByteStreamController(aCx, aStream, controller, algorithms, 2251 aHighWaterMark, autoAllocateChunkSize, aRv); 2252 } 2253 2254 } // namespace streams_abstract 2255 2256 } // namespace mozilla::dom